Skip to content

feat(examples): degit-able starter templates — chat, mcp-client, proxy-failover - #1185

Merged
murdore merged 1 commit into
releasefrom
feat/cookbook-starters
Jul 17, 2026
Merged

murdore merged 1 commit into
releasefrom
feat/cookbook-starters

Conversation

@murdore

@murdore murdore commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

What

Three self-contained starter templates under examples/starters/ + an index README. Each is copy-out-and-run:

npx degit juspay/neurolink/examples/starters/<name> my-app
cd my-app && npm install && npm start
Starter Shows
chat Streaming terminal chat via neurolink.stream(), automatic provider selection, one-line provider pinning
mcp-client .mcp-config.json auto-load registering the filesystem MCP server; a generate() call where the model reads a shipped sample.txt; the neurolink mcp add CLI equivalent
proxy-failover neurolink proxy setup + account-pooling walkthrough, plus a status health CLI against the local /status endpoint with a clean not-running message

Verification (all three)

  • Real npm install against the registry succeeded
  • tsc --noEmit clean under strict — no any anywhere (only guarded narrowing)
  • prettier-clean per repo config
  • README steps checked against the shipped files; degit paths match the repo layout
  • Every SDK/CLI API verified against source before use (e.g., stream chunk shape src/lib/types/stream.ts:664-672, .mcp-config.json auto-load src/lib/mcp/externalServerManager.ts:355, proxy status port src/cli/commands/proxy.ts:2135)
  • .env.example files contain placeholder names only; no lockfiles or node_modules shipped

Why

Growth playbook play #7 (marketing repo docs/growth-exec/growth-playbook.md): the template/starter gallery is the single biggest owned discovery+retention asset for Vercel AI SDK and Mastra in this exact category — this is NeuroLink's first step there, timed for the July 22 launch traffic.

Summary by CodeRabbit

  • New Features

    • Added three ready-to-use starter templates: terminal chat, MCP client, and proxy failover.
    • Added provider configuration examples and setup instructions for each starter.
    • Added an MCP example that reads a local file through a filesystem tool.
    • Added a proxy status example showing health, uptime, request metrics, and account failover details.
  • Documentation

    • Added a central guide explaining how to copy, configure, install, and run the starter templates.

…proxy-failover

Three self-contained starters under examples/starters/, each with its own
package.json (@juspay/neurolink ^9.88.12), strict tsconfig, README with a
degit quickstart, and .env.example (placeholder names only):

- chat: streaming terminal chat via neurolink.stream() with auto provider
  selection (chunk shape verified against src/lib/types/stream.ts)
- mcp-client: .mcp-config.json auto-load (externalServerManager.ts:355)
  registering the filesystem MCP server; one generate() call where the
  model reads a shipped sample.txt; documents the neurolink mcp add
  equivalent
- proxy-failover: ops walkthrough for neurolink proxy setup + account
  pooling, plus a status health CLI against the local /status endpoint
  (default port verified at src/cli/commands/proxy.ts:2135) with a clean
  proxy-not-running message

All three verified: real npm install against the registry, tsc --noEmit
clean under strict, prettier-clean, README steps match shipped files.
@vercel

vercel Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
neurolink Ready Ready Preview, Comment Jul 17, 2026 12:55am

Copilot AI review requested due to automatic review settings July 17, 2026 00:55
@github-actions

Copy link
Copy Markdown
Contributor

✅ Single Commit Policy - COMPLIANT

Status: Policy requirements met • 1 commit • Valid format • Ready for merge

📊 View validation details

📝 Commit Details

  • Hash: 34b813118180b780526f939bf38a2439cbe5e401
  • Message: feat(examples): add degit-able starter templates — chat, mcp-client, proxy-failover
  • Author: Sachin Sharma

✅ Validation Results

  • Single commit requirement met
  • No merge commits in branch
  • Semantic commit message format verified
  • Ready for squash merge to release branch

🤖 Automated validation by NeuroLink Single Commit Enforcement

@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds three TypeScript starter applications: a streaming terminal chat, an MCP filesystem client, and a Claude proxy status checker. Each includes project configuration, environment templates, executable code, and README documentation.

Changes

Starter examples

Layer / File(s) Summary
Chat starter flow
examples/starters/README.md, examples/starters/chat/*
Adds the starter catalog and a terminal chat app that streams NeuroLink responses, supports /exit, configures provider selection, and includes start/typecheck scripts.
MCP client integration
examples/starters/mcp-client/*
Adds a filesystem MCP configuration, sample fixture, provider setup, and a generation flow that verifies filesystem tool usage.
Proxy status checker
examples/starters/proxy-failover/*
Adds a proxy /status checker with response validation, uptime and account formatting, timeout/error handling, configuration defaults, and setup documentation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant readline
  participant main
  participant NeuroLink
  participant Provider
  User->>readline: enter prompt
  readline->>main: return input
  main->>NeuroLink: stream prompt
  NeuroLink->>Provider: request streamed reply
  Provider-->>NeuroLink: text chunks
  NeuroLink-->>main: stream events
  main-->>User: write reply chunks
Loading

Possibly related PRs

  • juspay/neurolink#1163: Changes the Claude proxy /status behavior consumed by the new proxy-failover starter.
  • juspay/neurolink#1173: Changes the proxy /status schema and statistics fields expected by the starter.

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding degit-able starter templates for chat, mcp-client, and proxy-failover.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cookbook-starters

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 AI Review & Build Compliance ✅

Status: AI analysis complete • Build rules validated • Ready for review

📊 View detailed analysis results

🛡️ Analysis Complete

  • ✅ Security scan (vulnerabilities, API keys)
  • ✅ TypeScript safety & code quality
  • ✅ Error handling & best practices
  • ✅ Build rule enforcement validated
  • ✅ Commit format & compliance checks

📋 Ready for Merge When

  • All CI checks passing
  • Manual review approved
  • Any AI-flagged issues resolved

🤖 AI analysis complete - check individual code comments for specific feedback

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a small “starter templates” gallery under examples/starters/ intended to be degit-able, standalone projects (each with its own package.json, tsconfig, and README) to help users quickly try key NeuroLink features.

Changes:

  • Added examples/starters/README.md index documenting available starters and the degit flow.
  • Added chat starter: a minimal terminal chat loop using neurolink.stream() for streaming output.
  • Added mcp-client and proxy-failover starters: MCP filesystem-server auto-load demo and a local Claude proxy /status health/status CLI.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
examples/starters/README.md Index page for the starter gallery and copy-out instructions.
examples/starters/chat/.env.example Provider key placeholders for the chat starter.
examples/starters/chat/README.md Usage docs for the streaming terminal chat starter.
examples/starters/chat/package.json Standalone dependencies/scripts for the chat starter.
examples/starters/chat/src/index.ts Streaming chat loop using NeuroLink.stream() and readline/promises.
examples/starters/chat/tsconfig.json TypeScript configuration for the chat starter.
examples/starters/mcp-client/.env.example Provider key placeholders for the MCP starter.
examples/starters/mcp-client/.mcp-config.json Local MCP filesystem server config intended to be auto-loaded from cwd.
examples/starters/mcp-client/README.md Documentation for MCP auto-load + filesystem tool usage example.
examples/starters/mcp-client/package.json Standalone dependencies/scripts for the MCP starter.
examples/starters/mcp-client/sample.txt Fixture file intended to be read via MCP filesystem tools.
examples/starters/mcp-client/src/index.ts MCP status/servers validation + a generate() prompting file tool usage.
examples/starters/mcp-client/tsconfig.json TypeScript configuration for the MCP starter.
examples/starters/proxy-failover/.env.example Proxy host/port configuration for the status checker.
examples/starters/proxy-failover/README.md Walkthrough for setting up the proxy + what the status checker prints.
examples/starters/proxy-failover/package.json Standalone dependencies/scripts for the proxy status starter.
examples/starters/proxy-failover/src/index.ts CLI that fetches /status and prints proxy/account summary.
examples/starters/proxy-failover/tsconfig.json TypeScript configuration for the proxy status starter.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +40 to +51
function isProxyStatusResponse(value: unknown): value is ProxyStatusResponse {
if (typeof value !== "object" || value === null) {
return false;
}
const candidate = value as Record<string, unknown>;
return (
typeof candidate.status === "string" &&
typeof candidate.pid === "number" &&
typeof candidate.stats === "object" &&
candidate.stats !== null
);
}
Comment on lines +115 to +125
const body: unknown = await response.json();
if (!isProxyStatusResponse(body)) {
console.error(
`Unexpected response shape from ${url}. Is this a NeuroLink proxy?`,
);
process.exitCode = 1;
return;
}

printStatus(body);
}
Comment on lines +127 to +130
const host = process.env.PROXY_HOST ?? "127.0.0.1";
const port = Number.parseInt(process.env.PROXY_PORT ?? "55669", 10);

await checkProxyStatus(host, port);
Comment on lines +9 to +11
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"outDir": "dist"
@@ -0,0 +1,22 @@
{
"name": "proxy-failover",

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
examples/starters/proxy-failover/src/index.ts (1)

127-128: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Use || instead of ?? for environment variable fallbacks.

If PROXY_PORT is set to an empty string in the shell environment, ?? will preserve the empty string rather than falling back to the default, causing Number.parseInt to return NaN and the subsequent fetch request to fail cryptically. Using || ensures the default is applied for empty strings as well.

♻️ Proposed refactor
-const host = process.env.PROXY_HOST ?? "127.0.0.1";
-const port = Number.parseInt(process.env.PROXY_PORT ?? "55669", 10);
+const host = process.env.PROXY_HOST || "127.0.0.1";
+const port = Number.parseInt(process.env.PROXY_PORT || "55669", 10);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/starters/proxy-failover/src/index.ts` around lines 127 - 128, Update
the environment-variable fallbacks in the host and port initialization to use ||
instead of ??, so empty PROXY_HOST or PROXY_PORT values select their defaults.
Preserve the existing default values and parsing behavior in the proxy startup
configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/starters/chat/src/index.ts`:
- Around line 40-64: Wrap the interactive loop in main with a try...finally
block so rl.close() always executes when rl.question or another loop operation
fails. In the finally cleanup, also invoke neurolink.shutdown() to release SDK
resources such as HTTP keep-alive agents, preserving the existing normal exit
and error handling behavior.

In `@examples/starters/proxy-failover/src/index.ts`:
- Around line 115-122: Wrap the response.json() call in the request flow with
try/catch so malformed response bodies do not produce an unhandled exception. In
the catch path, report the invalid response using the existing console error and
set process.exitCode to 1 before returning; keep the existing
isProxyStatusResponse validation for successfully parsed JSON.
- Around line 45-51: Update the type guard surrounding the candidate status
validation to also verify that candidate.stats.accounts is an array before
asserting ProxyStatusResponse. Preserve the existing status, pid, and stats
checks so printStatus can safely read accounts.length and iterate over the
validated collection.

---

Nitpick comments:
In `@examples/starters/proxy-failover/src/index.ts`:
- Around line 127-128: Update the environment-variable fallbacks in the host and
port initialization to use || instead of ??, so empty PROXY_HOST or PROXY_PORT
values select their defaults. Preserve the existing default values and parsing
behavior in the proxy startup configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bf64fcf2-3a50-4f5e-be2f-23673df9de51

📥 Commits

Reviewing files that changed from the base of the PR and between c5515be and 34b8131.

📒 Files selected for processing (18)
  • examples/starters/README.md
  • examples/starters/chat/.env.example
  • examples/starters/chat/README.md
  • examples/starters/chat/package.json
  • examples/starters/chat/src/index.ts
  • examples/starters/chat/tsconfig.json
  • examples/starters/mcp-client/.env.example
  • examples/starters/mcp-client/.mcp-config.json
  • examples/starters/mcp-client/README.md
  • examples/starters/mcp-client/package.json
  • examples/starters/mcp-client/sample.txt
  • examples/starters/mcp-client/src/index.ts
  • examples/starters/mcp-client/tsconfig.json
  • examples/starters/proxy-failover/.env.example
  • examples/starters/proxy-failover/README.md
  • examples/starters/proxy-failover/package.json
  • examples/starters/proxy-failover/src/index.ts
  • examples/starters/proxy-failover/tsconfig.json

Comment on lines +40 to +64
const main = async (): Promise<void> => {
printWelcome();

for (;;) {
const line = await rl.question("you> ");
const text = line.trim();

if (text.length === 0) {
continue;
}
if (text === "/exit") {
break;
}

stdout.write("ai> ");
try {
await streamReply(text);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`\n[error] ${message}\n`);
}
}

rl.close();
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Ensure resources are cleaned up safely on early exit.

If rl.question throws (e.g., EOF received), or if another operation within the loop fails unexpectedly, main() will reject and completely bypass the rl.close() call. This leaves the readline interface active and prevents the Node.js process from exiting gracefully, even after the global .catch() intercepts the error.

Additionally, like the mcp-client starter, it is a good practice to invoke neurolink.shutdown() to ensure underlying HTTP keep-alive agents in the SDK are swiftly torn down. Wrap the interactive loop in a try...finally block to guarantee these cleanups run regardless of how the function exits.

🐛 Proposed fix to guarantee resource cleanup
 const main = async (): Promise<void> => {
   printWelcome();
 
-  for (;;) {
-    const line = await rl.question("you> ");
-    const text = line.trim();
-
-    if (text.length === 0) {
-      continue;
-    }
-    if (text === "/exit") {
-      break;
-    }
-
-    stdout.write("ai>  ");
-    try {
-      await streamReply(text);
-    } catch (error) {
-      const message = error instanceof Error ? error.message : String(error);
-      console.error(`\n[error] ${message}\n`);
-    }
-  }
-
-  rl.close();
+  try {
+    for (;;) {
+      const line = await rl.question("you> ");
+      const text = line.trim();
+
+      if (text.length === 0) {
+        continue;
+      }
+      if (text === "/exit") {
+        break;
+      }
+
+      stdout.write("ai>  ");
+      try {
+        await streamReply(text);
+      } catch (error) {
+        const message = error instanceof Error ? error.message : String(error);
+        console.error(`\n[error] ${message}\n`);
+      }
+    }
+  } finally {
+    rl.close();
+    await neurolink.shutdown();
+  }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const main = async (): Promise<void> => {
printWelcome();
for (;;) {
const line = await rl.question("you> ");
const text = line.trim();
if (text.length === 0) {
continue;
}
if (text === "/exit") {
break;
}
stdout.write("ai> ");
try {
await streamReply(text);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`\n[error] ${message}\n`);
}
}
rl.close();
};
const main = async (): Promise<void> => {
printWelcome();
try {
for (;;) {
const line = await rl.question("you> ");
const text = line.trim();
if (text.length === 0) {
continue;
}
if (text === "/exit") {
break;
}
stdout.write("ai> ");
try {
await streamReply(text);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
console.error(`\n[error] ${message}\n`);
}
}
} finally {
rl.close();
await neurolink.shutdown();
}
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/starters/chat/src/index.ts` around lines 40 - 64, Wrap the
interactive loop in main with a try...finally block so rl.close() always
executes when rl.question or another loop operation fails. In the finally
cleanup, also invoke neurolink.shutdown() to release SDK resources such as HTTP
keep-alive agents, preserving the existing normal exit and error handling
behavior.

Comment on lines +45 to +51
return (
typeof candidate.status === "string" &&
typeof candidate.pid === "number" &&
typeof candidate.stats === "object" &&
candidate.stats !== null
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate the accounts array to prevent runtime crashes.

The type guard asserts that value is a ProxyStatusResponse, but it does not verify that stats.accounts is an array. If accounts is missing or is not an array, printStatus will crash with a TypeError when trying to read its .length or iterate over it.

🐛 Proposed fix to add array validation
-  return (
-    typeof candidate.status === "string" &&
-    typeof candidate.pid === "number" &&
-    typeof candidate.stats === "object" &&
-    candidate.stats !== null
-  );
+  return (
+    typeof candidate.status === "string" &&
+    typeof candidate.pid === "number" &&
+    typeof candidate.stats === "object" &&
+    candidate.stats !== null &&
+    Array.isArray((candidate.stats as Record<string, unknown>).accounts)
+  );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
typeof candidate.status === "string" &&
typeof candidate.pid === "number" &&
typeof candidate.stats === "object" &&
candidate.stats !== null
);
}
return (
typeof candidate.status === "string" &&
typeof candidate.pid === "number" &&
typeof candidate.stats === "object" &&
candidate.stats !== null &&
Array.isArray((candidate.stats as Record<string, unknown>).accounts)
);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/starters/proxy-failover/src/index.ts` around lines 45 - 51, Update
the type guard surrounding the candidate status validation to also verify that
candidate.stats.accounts is an array before asserting ProxyStatusResponse.
Preserve the existing status, pid, and stats checks so printStatus can safely
read accounts.length and iterate over the validated collection.

Comment on lines +115 to +122
const body: unknown = await response.json();
if (!isProxyStatusResponse(body)) {
console.error(
`Unexpected response shape from ${url}. Is this a NeuroLink proxy?`,
);
process.exitCode = 1;
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle potential JSON parsing exceptions.

If the server responds with a 200 OK but the body is not valid JSON (e.g., returning an HTML page from a captive portal or a misconfigured reverse proxy), response.json() will throw an unhandled SyntaxError, causing the script to crash. Defensively wrap the JSON parsing in a try...catch block.

🛡️ Proposed fix to handle parsing errors gracefully
-  const body: unknown = await response.json();
-  if (!isProxyStatusResponse(body)) {
-    console.error(
-      `Unexpected response shape from ${url}. Is this a NeuroLink proxy?`,
-    );
-    process.exitCode = 1;
-    return;
-  }
+  let body: unknown;
+  try {
+    body = await response.json();
+  } catch {
+    console.error(`Invalid JSON response from ${url}. Is this a NeuroLink proxy?`);
+    process.exitCode = 1;
+    return;
+  }
+
+  if (!isProxyStatusResponse(body)) {
+    console.error(
+      `Unexpected response shape from ${url}. Is this a NeuroLink proxy?`,
+    );
+    process.exitCode = 1;
+    return;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const body: unknown = await response.json();
if (!isProxyStatusResponse(body)) {
console.error(
`Unexpected response shape from ${url}. Is this a NeuroLink proxy?`,
);
process.exitCode = 1;
return;
}
let body: unknown;
try {
body = await response.json();
} catch {
console.error(`Invalid JSON response from ${url}. Is this a NeuroLink proxy?`);
process.exitCode = 1;
return;
}
if (!isProxyStatusResponse(body)) {
console.error(
`Unexpected response shape from ${url}. Is this a NeuroLink proxy?`,
);
process.exitCode = 1;
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/starters/proxy-failover/src/index.ts` around lines 115 - 122, Wrap
the response.json() call in the request flow with try/catch so malformed
response bodies do not produce an unhandled exception. In the catch path, report
the invalid response using the existing console error and set process.exitCode
to 1 before returning; keep the existing isProxyStatusResponse validation for
successfully parsed JSON.

@Tara-ag Tara-ag left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Reviewed all 18 added files in examples/starters/. Existing review comments (Copilot + CodeRabbit) already cover the major issues in proxy-failover/src/index.ts (permissive type guard, unhandled response.json(), invalid PROXY_PORT parsing), chat/tsconfig.json (outDir with noEmit), proxy-failover/package.json (inconsistent package name), and chat/src/index.ts (missing guaranteed cleanup). I did not duplicate those.

New comments raised (2 MINOR)

  1. examples/starters/mcp-client/src/index.ts:83 — Top-level await diverges from the chat starter's defensive main().catch(...) pattern and can produce a cryptic unhandled-rejection dump if copied into a non-ESM context.
  2. examples/starters/proxy-failover/src/index.ts:130 — Top-level await leaves any unexpected rejection to Node's default formatter, undermining the starter's goal of clean, user-friendly error messages.

Blocking assessment

  • No hardcoded secrets or credentials.
  • No new critical security vulnerabilities.
  • No public SDK API breakage.
  • No non-negotiable CLAUDE.md rule violations in the added code.
  • Fewer than 3 MAJOR issues newly raised.

Decision: Approve with minor inline suggestions. The existing major feedback should be addressed before merge, but those points are already tracked by prior reviewers.

}
}

await main();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 MINOR: Top-level await may fail cryptically on older Node / non-ESM consumers.

The starter uses "type": "module" and Node 20, so top-level await is technically fine. However, if a user copies this into a CJS project or runs it through a transpiler that doesn't preserve TLA, the file will fail to load. Wrapping the call in an async IIFE and handling rejection explicitly mirrors the chat starter's pattern and gives a cleaner failure surface.

Suggested fix:

main().catch((error: unknown) => {
  console.error(error instanceof Error ? error.message : error);
  process.exitCode = 1;
});

const host = process.env.PROXY_HOST ?? "127.0.0.1";
const port = Number.parseInt(process.env.PROXY_PORT ?? "55669", 10);

await checkProxyStatus(host, port);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 MINOR: Top-level await leaves unhandled rejections to Node's default formatter.

If checkProxyStatus rejects for any reason not already caught inside the function, the process will print Node's default unhandled-rejection output rather than the clean error message this starter aims for. The chat starter wraps its entry point in main().catch(...) for consistent, user-friendly failures.

Suggested fix:

checkProxyStatus(host, port).catch((error: unknown) => {
  console.error(error instanceof Error ? error.message : error);
  process.exitCode = 1;
});

@murdore
murdore merged commit e737e18 into release Jul 17, 2026
18 checks passed
@murdore
murdore deleted the feat/cookbook-starters branch July 17, 2026 01:31
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 9.89.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

This branch was successfully deployed

1 active deployment
Preview — 34b81311 Deployed Jul 17, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants