Skip to content

release: 0.35.1#88

Open
stainless-app[bot] wants to merge 36 commits intomainfrom
release-please--branches--main--changes--next--components--hyperspell
Open

release: 0.35.1#88
stainless-app[bot] wants to merge 36 commits intomainfrom
release-please--branches--main--changes--next--components--hyperspell

Conversation

@stainless-app
Copy link
Copy Markdown
Contributor

@stainless-app stainless-app bot commented Mar 20, 2026

Automated Release PR

0.35.1 (2026-04-08)

Full Changelog: v0.35.0...v0.35.1

Features

Bug Fixes

  • internal: gitignore generated oidc dir (a305f3d)

Chores

  • ci: escape input path in publish-npm workflow (40c8402)
  • ci: skip lint on metadata-only changes (14012e7)
  • configure new SDK language (2b1db35)
  • internal: fix MCP server import ordering (aa4d800)
  • internal: fix MCP server TS errors that occur with required client options (b7abcfb)
  • internal: improve local docs search for MCP servers (eee2438)
  • internal: improve local docs search for MCP servers (f218072)
  • internal: support custom-instructions-path flag in MCP servers (c6d4043)
  • internal: support local docs search in MCP servers (4a9b2cf)
  • internal: support type annotations when running MCP in local execution mode (41a4e6a)
  • internal: update gitignore (9270ff5)
  • internal: update multipart form array serialization (97f213b)
  • mcp-server: add support for session id, forward client info (9e3018f)
  • mcp-server: log client info (5f1ad6d)
  • tests: bump steady to v0.19.4 (e614b67)
  • tests: bump steady to v0.19.5 (eadfc98)
  • tests: bump steady to v0.19.6 (4ed8bba)
  • tests: bump steady to v0.19.7 (6aaa435)
  • tests: bump steady to v0.20.1 (bb96b8b)
  • tests: bump steady to v0.20.2 (2a71a6e)
  • update SDK settings (4ee9dca)
  • update SDK settings (752879e)

Refactors

  • tests: switch from prism to steady (75ac934)

This pull request is managed by Stainless's GitHub App.

The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.

For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.

🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions

@stainless-app
Copy link
Copy Markdown
Contributor Author

stainless-app bot commented Mar 20, 2026

🧪 Testing

To try out this version of the SDK:

npm install 'https://pkg.stainless.com/s/hyperspell-typescript/9451cde625b2736fee26be6e5181e6b1a0ffc5c2/dist.tar.gz'

Expires at: Fri, 08 May 2026 03:31:30 GMT
Updated at: Wed, 08 Apr 2026 03:31:30 GMT

@canaries-inc
Copy link
Copy Markdown

canaries-inc bot commented Mar 20, 2026

Canary encountered an internal error while analyzing this PR.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 6972295 to d19a5b9 Compare March 21, 2026 05:08
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No new review comments were generated, indicating the PR appears clean to the automated review.
  • No critical, significant, or high-risk issues were identified in the heuristic analysis.
  • 8 out of 11 changed files were reviewed with zero issues flagged across all severity levels.
  • No existing unresolved comments remain, suggesting previous concerns have been addressed.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from d19a5b9 to 76a7033 Compare March 21, 2026 05:14
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No new review comments were generated, indicating the PR appears clean from an automated review perspective.
  • No critical, significant, or high-risk issues were identified in the heuristic analysis.
  • 8 out of 11 changed files were reviewed with no issues found, providing reasonable coverage confidence.
  • No existing unresolved comments that could indicate lingering concerns.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 76a7033 to abd5f3a Compare March 21, 2026 21:30
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No new review comments were generated, indicating the PR appears clean from an automated review perspective.
  • No critical, significant, or high-risk issues were identified in the heuristic analysis.
  • 15 out of 18 changed files were reviewed, providing good coverage with no issues found.
  • No existing unresolved comments that would block merging.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from abd5f3a to 651d17f Compare March 22, 2026 08:09
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 15/18 changed files reviewed (83% coverage)

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 651d17f to fc292db Compare March 23, 2026 08:03
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 15/18 changed files reviewed (83% coverage)

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from fc292db to 08cc52a Compare March 23, 2026 22:30
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No new review comments were generated, indicating the PR is clean from an automated review perspective.
  • No critical, significant, or high-risk issues were identified in the heuristic analysis.
  • 15 out of 18 changed files were reviewed with zero issues flagged, providing good coverage confidence.
  • No existing unresolved comments carry over from previous reviews that would block merging.

@stainless-app
Copy link
Copy Markdown
Contributor Author

stainless-app bot commented Mar 24, 2026

Release version edited manually

The Pull Request version has been manually set to 0.35.1 and will be used for the release.

If you instead want to use the version number 0.36.0 generated from conventional commits, just remove the label autorelease: custom version from this Pull Request.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 08cc52a to 15abf4d Compare March 24, 2026 05:10
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 15/19 changed files reviewed (79% coverage)

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 15abf4d to 2dbef30 Compare March 24, 2026 05:14
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 16/20 changed files reviewed (80% coverage)

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 2dbef30 to b86942f Compare March 24, 2026 05:16
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 16/20 changed files reviewed (80% coverage)

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from b86942f to dd246c5 Compare March 24, 2026 17:30
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 16/20 changed files reviewed (80% coverage)

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch 2 times, most recently from 0b83ccb to d4e4451 Compare March 25, 2026 03:29
@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No new review comments were generated, indicating the PR is clean with no identified issues.
  • No existing unresolved comments to consider, meaning there are no lingering concerns from previous reviews.
  • 16 out of 21 changed files were reviewed with no issues found, providing good coverage confidence.
  • Heuristic analysis shows zero critical, significant, high-risk, or medium issues detected.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No new review comments were generated, indicating the PR appears clean from an automated review perspective.
  • No critical, significant, or high-risk issues were identified in the heuristic analysis.
  • Coverage of 16/21 changed files is reasonable, and no unresolved existing comments are blocking the merge.
  • The absence of any flagged issues across all severity levels supports a safe-to-merge assessment.

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from d4e4451 to a7b2b11 Compare March 26, 2026 17:30
@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch 2 times, most recently from e3e797a to e90547c Compare April 2, 2026 18:28
Comment on lines 8 to +10
import { Hyperspell, ClientOptions } from 'hyperspell';

async function tseval(code: string) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Buffer is not a global in Deno environments; the file uses node:path and node:util prefixed imports suggesting Deno execution, so Buffer.from(...) will throw ReferenceError: Buffer is not defined unless explicitly imported from node:buffer.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 8-10, the `tseval` function uses `Buffer.from()` but `Buffer` is not a global in Deno environments. Add `import { Buffer } from 'node:buffer';` at the top of the file alongside the other `node:` prefixed imports (`node:path`, `node:util`) to ensure `Buffer` is explicitly available.

Comment on lines 271 to 278
const log_lines: string[] = [];
const err_lines: string[] = [];
const console = {
const originalConsole = globalThis.console;
globalThis.console = {
...originalConsole,
log: (...args: unknown[]) => {
log_lines.push(util.format(...args));
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Mutating globalThis.console is not safe if two requests execute concurrently: the second request overwrites the first's interception, causing log lines to route to the wrong request's arrays, and the finally restore in one request undoes the other's setup mid-execution.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In file `packages/mcp-server/src/code-tool-worker.ts`, lines 271-278 (and the corresponding finally block), the code mutates `globalThis.console` which is shared across concurrent request handlers. Two simultaneous fetch calls will stomp on each other's console override, routing log output to the wrong request's `log_lines`/`err_lines` arrays, and the `finally` restore from one request will undo the other's setup. Fix this by avoiding global mutation: instead of replacing `globalThis.console`, pass custom log/error functions as part of the execution context (e.g., inject them via a context object or closure into the tseval'd code), or ensure the worker is strictly single-threaded and document that assumption, or use an AsyncLocalStorage-based approach to track per-request console state without global mutation.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — packages/mcp-server/src/code-tool-worker.ts contains two unresolved critical bugs that will cause runtime failures: Buffer.from(...) is used as a global in a Deno environment where it is not available, causing a ReferenceError on execution, and globalThis.console is mutated in a non-atomic way that corrupts log routing under any concurrent request load. This PR successfully adds the Gmail Actions integration literals, the effort parameter to MemorySearchParams, and the LocalDocsSearch module, but these improvements are overshadowed by the unresolved correctness issues in the MCP server that have been flagged across multiple review rounds without being addressed. Additionally, packages/mcp-server/src/instructions.ts uses a static import fs from 'fs/promises' that will crash at module load time in non-Node runtimes, and packages/mcp-server/src/options.ts returns an McpOptions object silently missing properties like stainlessApiKey and codeAllowedMethods.

Key Findings:

  • Buffer.from(base64Output, 'base64') in code-tool-worker.ts treats Buffer as a global, but the file's Deno-style export default { fetch } pattern and node: prefixed imports confirm a Deno runtime context where Buffer is not globally available — this will throw ReferenceError: Buffer is not defined on every invocation.
  • The globalThis.console mutation pattern in the fetch handler of code-tool-worker.ts is fundamentally unsafe for concurrent execution: a second overlapping request will capture the already-patched console as its originalConsole, and the finally block restoring the original in one request will silently destroy the interception setup by the other, corrupting both request's stdout/stderr capture.
  • The static top-level import fs from 'fs/promises' in instructions.ts will cause the entire module to fail to load in Deno or Cloudflare Workers environments at startup, not just when the file-reading code path is exercised — this is a module-load-time crash, not a runtime path issue.
  • The McpOptions object returned from the builder in options.ts is structurally incomplete, silently omitting fields like stainlessApiKey and codeAllowedMethods that are defined in the McpOptions type, which could cause subtle downstream failures or type unsafety depending on how callers use the returned object.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • packages/mcp-server/src/instructions.ts
  • packages/mcp-server/src/options.ts

Comment on lines 271 to 278
const log_lines: string[] = [];
const err_lines: string[] = [];
const console = {
const originalConsole = globalThis.console;
globalThis.console = {
...originalConsole,
log: (...args: unknown[]) => {
log_lines.push(util.format(...args));
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: 🐛 Mutating globalThis.console is shared state across all concurrent requests: if two fetch calls overlap, request B will overwrite request A's interceptor, and when A's finally block runs globalThis.console = originalConsole it will silently discard B's interceptor mid-flight, causing B's console.log/console.error calls to go uncaptured (or to the real console).

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts at lines 271-278, the diff replaces a local `const console` with a mutation of `globalThis.console`. Because `fetch` is an async handler that can be invoked concurrently, this creates a race condition: concurrent requests share the same `globalThis.console` reference, so one request can stomp another's interceptor, and the `finally` restore can remove a still-active interceptor from a concurrent request. Fix this by passing a custom console object directly to the user code instead of monkey-patching the global. For example, thread a `{ log, error }` console shim as a second argument to `run_`, or inject it via the proxy, so each request operates on its own isolated capture object with no global mutation.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR introduces multiple unresolved correctness bugs in packages/mcp-server/src/code-tool-worker.ts that remain unfixed across several review rounds. The globalThis.console mutation is a confirmed race condition where concurrent requests will corrupt each other's log interception and silently discard interceptors mid-flight, and the use of Buffer as a global will throw ReferenceError in Deno environments where this file is executed. While the PR's goals are reasonable — adding Gmail Actions support, an effort parameter to MemorySearchParams, and migrating the mock server — the core MCP worker has critical concurrency and runtime-compatibility bugs that could cause data loss and crashes in production.

Key Findings:

  • In code-tool-worker.ts, mutating globalThis.console inside the fetch handler is not safe for concurrent requests: overlapping requests will overwrite each other's interceptors, causing logs to route to the wrong request context and the finally block to silently discard a live interceptor — this is a confirmed race condition flagged in both the new review and two prior unresolved comments.
  • Also in code-tool-worker.ts, Buffer.from(...) is used as a global on lines 7-16, but in Deno environments (which this file targets based on its export default { fetch } pattern and Deno stack-trace parsing) Buffer is not globally available without an explicit import, meaning this will throw ReferenceError on every invocation — flagged twice in prior reviews and still unresolved.
  • In options.ts, the returned McpOptions object is missing several properties from defaultOptions that are defined in the McpOptions type (stainlessApiKey, codeAllowHttpGets, codeAllowedMethods, etc.), which can cause silent runtime failures when callers depend on those defaults being present.
  • In instructions.ts, the static import fs from 'fs/promises' will fail at module load time in non-Node runtimes (Deno, Cloudflare Workers), meaning the entire MCP server module will fail to initialize even when the file-reading code path is never reached.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • packages/mcp-server/src/options.ts
  • packages/mcp-server/src/instructions.ts

Comment on lines 8 to +10
import { Hyperspell, ClientOptions } from 'hyperspell';

async function tseval(code: string) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Buffer is a Node.js global; the rest of the file (e.g. parseError's stack comment "Deno uses V8") and the data:application/typescript import syntax strongly indicate this runs on Deno, where Buffer is not a guaranteed global and will throw ReferenceError: Buffer is not defined at runtime.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 8-10, the tseval function uses `Buffer.from(code).toString('base64')` to base64-encode the TypeScript source string. This file runs in a Deno environment (evidenced by the 'Deno uses V8' comment in parseError and the use of data:application/typescript imports which are Deno-specific). `Buffer` is a Node.js global and is not reliably available in Deno without explicit import, causing a ReferenceError at runtime. Replace `Buffer.from(code).toString('base64')` with a Deno/browser-compatible alternative such as `btoa(unescape(encodeURIComponent(code)))` to handle arbitrary Unicode input correctly.

Comment on lines 271 to 278
const log_lines: string[] = [];
const err_lines: string[] = [];
const console = {
const originalConsole = globalThis.console;
globalThis.console = {
...originalConsole,
log: (...args: unknown[]) => {
log_lines.push(util.format(...args));
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Mutating globalThis.console in an async handler creates a race condition: if two requests overlap, one request's finally block will restore the console to the second request's overridden version (not the true original), causing log/error lines to leak between requests or be lost entirely.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 271-278, the diff introduces a race condition by saving and restoring `globalThis.console` in an async request handler. When two requests overlap, the second request's `finally` block may restore `globalThis.console` to the first request's overridden console rather than the true original. Fix this by avoiding mutation of `globalThis.console` entirely — instead, pass a custom console object (with overridden `log` and `error`) directly to the evaluated code, or use AsyncLocalStorage to isolate per-request console state.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — packages/mcp-server/src/code-tool-worker.ts contains two critical unresolved bugs that have persisted across multiple review rounds without being fixed: Buffer is used as a global in a Deno environment where it is not available, which will throw ReferenceError: Buffer is not defined at runtime, and globalThis.console is mutated in an async request handler without any concurrency guard, creating a race condition where overlapping requests will corrupt each other's log capture and restore the wrong originalConsole in the finally block. While the PR itself is well-scoped — expanding Gmail Actions type support, adding the effort parameter to MemorySearchParams, and introducing LocalDocsSearch — these two high-severity correctness issues in code-tool-worker.ts remain unaddressed despite being flagged in at least three prior review passes, and an additional concern in options.ts about missing properties in the returned McpOptions object has also gone unresolved.

Key Findings:

  • Buffer.from(...) in code-tool-worker.ts will throw ReferenceError: Buffer is not defined at runtime in Deno, which does not expose Buffer as a global — this is a crash-on-execution bug that has been flagged across multiple review rounds and remains unpatched.
  • Mutating globalThis.console inside the async fetch handler in code-tool-worker.ts is unsafe under concurrency: if two requests overlap, the second request's finally block restores an already-overridden console rather than the true original, causing log lines to leak between requests or be silently dropped.
  • In options.ts, the returned McpOptions object omits several properties present in defaultOptions (e.g., stainlessApiKey, codeAllowHttpGets, codeAllowedMethods) — callers depending on those fields will silently receive undefined rather than the intended defaults.
  • The static import fs from 'fs/promises' at the top of instructions.ts will cause module-load failure in non-Node runtimes (Deno, Cloudflare Workers) regardless of whether the file-reading code path is actually invoked.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • packages/mcp-server/src/options.ts
  • packages/mcp-server/src/instructions.ts

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from e90547c to edc9a15 Compare April 2, 2026 21:20
Comment on lines 271 to 278
const log_lines: string[] = [];
const err_lines: string[] = [];
const console = {
const originalConsole = globalThis.console;
globalThis.console = {
...originalConsole,
log: (...args: unknown[]) => {
log_lines.push(util.format(...args));
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Mutating globalThis.console is not safe under concurrent requests: if two requests are in-flight simultaneously (e.g., both reach await run_(...)), the second request overwrites the console set by the first, causing log lines to be captured into the wrong request's log_lines/err_lines arrays and potentially leaving globalThis.console in a corrupted state after finally restores only the version saved by the first request.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts around lines 271-278, the diff replaces a local `const console` shadow with a mutation of `globalThis.console`. This introduces a race condition: under concurrent async requests, two handlers can interleave at await points, causing each to stomp the other's console override and mix up captured log/error lines. Fix by avoiding global mutation entirely — for example, pass a custom console object directly into the evaluated code's scope rather than monkey-patching `globalThis.console`, or use AsyncLocalStorage to isolate per-request console state.

import { Hyperspell, ClientOptions } from 'hyperspell';

async function tseval(code: string) {
return import('data:application/typescript;charset=utf-8;base64,' + Buffer.from(code).toString('base64'));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Buffer is a Node.js global and is not natively available in Deno unless Node.js compatibility mode is enabled; if this worker runs in a standard Deno environment, Buffer.from(code).toString('base64') will throw ReferenceError: Buffer is not defined. Use the Web-standard btoa(encodeURIComponent(code).replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)))) or explicitly import Buffer from node:buffer.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `packages/mcp-server/src/code-tool-worker.ts`, line 11, the `tseval` function uses the global `Buffer` which is Node.js-specific and unavailable in Deno without Node.js compat mode. Replace the global `Buffer` usage with an explicit import from `node:buffer`: add `const { Buffer: NodeBuffer } = await import('node:buffer');` before the return statement and replace `Buffer.from(code).toString('base64')` with `NodeBuffer.from(code).toString('base64')`. Alternatively, if the environment is guaranteed to have Node.js compat, add a top-level import `import { Buffer } from 'node:buffer';` at the top of the file.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — packages/mcp-server/src/code-tool-worker.ts contains two unresolved, repeatedly flagged correctness bugs: mutating globalThis.console in an async fetch handler creates a race condition where concurrent requests cross-contaminate each other's log_lines/err_lines capture, and Buffer.from(code).toString('base64') will throw ReferenceError: Buffer is not defined in the Deno runtime this worker targets. Both issues have been raised in multiple previous review rounds and remain unaddressed. The PR's additions — Gmail Actions union types, the effort parameter in MemorySearchParams, and the Prism→Steady test tooling migration — are well-scoped and low-risk, but the blocking bugs in code-tool-worker.ts and the missing properties in the McpOptions return value in options.ts prevent a safe merge.

Key Findings:

  • In code-tool-worker.ts, globalThis.console is overwritten inside each fetch() handler without any concurrency guard; when two requests are in-flight simultaneously, request B's assignment clobbers request A's interception, and A's finally block then restores B's overridden console, permanently corrupting both requests' log capture — this has been flagged in at least four separate review rounds.
  • Buffer.from(code).toString('base64') in code-tool-worker.ts relies on a Node.js global that is not available in standard Deno environments; the rest of the file (Deno-style data:application/typescript imports, Deno stack-trace parsing) confirms this runs on Deno, meaning every invocation of the base64-encoding path will throw ReferenceError: Buffer is not defined.
  • In packages/mcp-server/src/options.ts, the returned McpOptions object omits properties (stainlessApiKey, codeAllowHttpGets, codeAllowedMethods, etc.) that are present in defaultOptions and declared in the McpOptions type, leaving callers with silently incomplete configuration objects.
  • The static import fs from 'fs/promises' at the top of instructions.ts will cause a module-load-time failure in non-Node runtimes (Deno, Cloudflare Workers), even when the file-reading code path is never reached, making the MCP server non-portable by construction.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • packages/mcp-server/src/options.ts
  • packages/mcp-server/src/instructions.ts

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from edc9a15 to f29ed6a Compare April 3, 2026 05:39
Comment on lines 8 to +10
import { Hyperspell, ClientOptions } from 'hyperspell';

async function tseval(code: string) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: The code parameter originates directly from user-supplied request body (req.json()) and is executed without any sandboxing — an attacker who can reach this endpoint can run arbitrary code in the worker process with full access to the environment, credentials, and network.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 8-10, the `tseval` function dynamically imports user-supplied code via a data URL. The `code` argument originates from the raw request body with no sandboxing. Evaluate whether the endpoint that calls this worker is protected by authentication/authorization, and consider whether the execution environment (Deno/Cloudflare Worker) provides any meaningful isolation. At minimum, document the trust boundary explicitly and ensure no unauthenticated path can reach this handler.

Comment on lines 271 to 272
const log_lines: string[] = [];
const err_lines: string[] = [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Mutating globalThis.console is shared state — concurrent async requests will interleave, causing one request's patched console to be overwritten by another's mid-execution, so log_lines/err_lines will capture output from the wrong request.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 271-278 (the diff adding `globalThis.console = {...}`), there is a race condition: `globalThis.console` is a single shared global. When two async `fetch` requests run concurrently and both reach the `await run_(...)` call, each request will overwrite the other's patched console, so logs will be captured in the wrong request's `log_lines`/`err_lines` arrays. Fix this by not mutating `globalThis.console` at all — instead, pass a custom console object directly into `run_` (e.g. as a second argument), or use AsyncLocalStorage to scope the console interception per-request, ensuring concurrent requests do not interfere with each other.

@@ -1,5 +1,6 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import fs from 'fs/promises';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: A static top-level import fs from 'fs/promises' will cause module initialization to fail in non-Node.js runtimes (Deno, Cloudflare Workers, edge environments), whereas code-tool.ts deliberately uses a dynamic await import('node:fs') to avoid this exact problem. This will silently break any environment that doesn't support fs/promises at module load time.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/instructions.ts, line 3, remove the static top-level `import fs from 'fs/promises';` and instead use a dynamic import inside `fetchLatestInstructionsFromFile` (around line 54): replace `return await fs.readFile(path, 'utf-8');` with `const fs = await import('fs/promises'); return await fs.readFile(path, 'utf-8');`. This matches the pattern in code-tool.ts which uses `await import('node:fs')` to avoid breaking non-Node.js environments at module load time.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — code-tool-worker.ts executes user-supplied code from the request body directly via eval/dynamic execution with no sandboxing, representing a critical remote code execution vulnerability that gives any caller full access to the process environment and credentials. Compounding this, the globalThis.console mutation in the same file creates a confirmed race condition under concurrent requests where log lines and error lines will bleed across requests, a bug flagged repeatedly in at least eight prior unresolved review comments that have gone unaddressed. The PR does deliver meaningful value — expanding gmail_actions support across multiple type files and introducing LocalDocsSearch for offline MCP documentation — but the security and correctness issues in code-tool-worker.ts, plus the static import fs from 'fs/promises' in instructions.ts that will crash module initialization in Deno/edge runtimes, make this unsafe to ship.

Key Findings:

  • Arbitrary code execution risk in code-tool-worker.ts: the code parameter from req.json() is executed without sandboxing, allowing any caller to run arbitrary code with full access to the worker process, environment variables, and network — a critical security vulnerability.
  • Race condition in globalThis.console mutation (lines 270-278 of code-tool-worker.ts): concurrent async requests will overwrite each other's console interceptor, causing log_lines/err_lines to capture output from the wrong request; this exact bug has been raised in at least 8 previous unresolved review comments and remains unfixed.
  • Static top-level import fs from 'fs/promises' in instructions.ts will cause module initialization failure in non-Node.js runtimes (Deno, Cloudflare Workers), silently breaking those environments at startup — inconsistent with the deliberate dynamic await import('node:fs') pattern already used in code-tool.ts.
  • McpOptions object returned in options.ts (lines 179-185) is missing several properties (stainlessApiKey, codeAllowHttpGets, codeAllowedMethods, etc.) defined in the McpOptions type, a pre-existing unresolved correctness issue that could cause silent misconfiguration.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • packages/mcp-server/src/instructions.ts
  • packages/mcp-server/src/options.ts

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from f29ed6a to fce5750 Compare April 3, 2026 21:30
Comment on lines 8 to +10
import { Hyperspell, ClientOptions } from 'hyperspell';

async function tseval(code: string) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: The code argument passed to tseval originates directly from the request body (req.json()) with no sandboxing beyond the proxy — a malicious caller can execute arbitrary code in the worker process by crafting the code field of the request payload.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts at lines 8-10, the tseval function dynamically imports and executes arbitrary TypeScript code that comes directly from an untrusted HTTP request body. Ensure this worker runs in a fully isolated sandbox (e.g., a separate Deno/Worker process with no access to secrets or the filesystem), enforce strict origin/auth checks before the fetch handler is invoked, or document the trust boundary explicitly if the endpoint is internal-only.

Comment on lines 271 to 278
const log_lines: string[] = [];
const err_lines: string[] = [];
const console = {
const originalConsole = globalThis.console;
globalThis.console = {
...originalConsole,
log: (...args: unknown[]) => {
log_lines.push(util.format(...args));
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: 🐛 Mutating globalThis.console is not safe under concurrent requests — if two requests are in-flight simultaneously, Request B will overwrite globalThis.console with its own capture object, so Request A's console.log calls will be recorded into B's log_lines, and the finally restores will race each other. The previous local const console shadowing was request-scoped; this new approach makes console capture a shared mutable global that breaks under concurrency.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 271-278, the diff replaces a local `const console = {...}` with a mutation of `globalThis.console`. This creates a race condition when multiple requests are handled concurrently: whichever request last sets `globalThis.console` wins, causing cross-request log capture pollution and lost logs. Fix this by using an AsyncLocalStorage or similar per-request context to pass the capture console to the evaluated code, rather than mutating the shared global. Alternatively, if evaluated code must use globalThis.console, serialize request handling or find another isolation mechanism.


export interface MemoryUploadParams {
/**
* The file to ingest.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Changing file from Uploadable to string breaks callers passing File, Blob, Buffer, or ReadableStream objects, which are the expected input types for a multipart file upload using multipartFormRequestOptions. A plain string value passed to multipartFormRequestOptions will be sent as-is (e.g. a filename string), not as actual binary file content, silently producing malformed uploads.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `src/resources/memories.ts`, line 844, the `file` field in `MemoryUploadParams` was changed from `Uploadable` to `string`. This breaks the ability to pass actual file objects (File, Blob, Buffer, ReadableStream) to the upload method, which relies on `multipartFormRequestOptions` for multipart form data. Revert this field back to `Uploadable` to preserve correct upload behavior and maintain API compatibility.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR introduces critical security and correctness issues that must be resolved before merging. The code-tool-worker.ts file executes user-supplied code from req.json() without any sandboxing, allowing arbitrary code execution by any caller who can reach the endpoint; this is a severe remote code execution vulnerability. Additionally, globalThis.console mutation in the same file creates a well-documented race condition under concurrent requests where log lines will bleed between requests and finally restores will corrupt state, and this issue has been flagged in no fewer than eight previous unresolved review comments with zero remediation. The memories.ts change narrowing file from Uploadable to string is a breaking API regression that will silently corrupt multipart uploads for callers passing File, Blob, Buffer, or ReadableStream objects.

Key Findings:

  • In code-tool-worker.ts, the code field from req.json() is passed directly to tseval with no input validation, sandboxing, or allowlisting — an attacker with network access to this worker endpoint can execute arbitrary code in the worker process, constituting a critical RCE vulnerability.
  • The globalThis.console mutation pattern in code-tool-worker.ts (lines 270-278) is fundamentally unsafe for async concurrent handlers: two overlapping requests will cross-contaminate each other's log_lines arrays and the finally block's restore will set console to the wrong captured object — this has been flagged in 8 separate previous review comments and remains entirely unaddressed.
  • The file parameter type change in src/resources/memories.ts from Uploadable (which includes File, Blob, Buffer, ReadableStream) to string is a breaking change that will cause multipart form uploads to be sent as raw string bodies, silently producing malformed requests rather than failing loudly.
  • A pre-existing and still-open concern in packages/mcp-server/src/instructions.ts uses a static top-level import fs from 'fs/promises' which will crash module initialization in Deno or Cloudflare Workers environments, and packages/mcp-server/src/options.ts returns an McpOptions object missing several required properties (stainlessApiKey, codeAllowHttpGets, codeAllowedMethods), both of which remain unresolved from prior reviews.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • src/resources/memories.ts
  • packages/mcp-server/src/instructions.ts
  • packages/mcp-server/src/options.ts

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from fce5750 to 7d81670 Compare April 7, 2026 08:11
import { Hyperspell, ClientOptions } from 'hyperspell';

async function tseval(code: string) {
return import('data:application/typescript;charset=utf-8;base64,' + Buffer.from(code).toString('base64'));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Buffer is a Node.js global not available in Deno or edge runtimes; the parseError function explicitly mentions Deno and the module uses export default { fetch } (edge worker pattern), so this will throw ReferenceError: Buffer is not defined at runtime in those environments.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts at line 11, the `tseval` function uses `Buffer.from(code).toString('base64')` to base64-encode the TypeScript code. `Buffer` is a Node.js-only global and is not available in Deno or edge runtimes (the file uses `export default { fetch }` pattern and `parseError` mentions Deno explicitly). Replace `Buffer.from(code).toString('base64')` with a runtime-agnostic base64 encoding such as `btoa(unescape(encodeURIComponent(code)))` to handle Unicode safely across all environments.


export interface MemoryUploadParams {
/**
* The file to ingest.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: Changing file from Uploadable to string is a breaking change — callers passing File, Blob, Buffer, or ReadableStream objects will now get TypeScript type errors. The upload method still calls multipartFormRequestOptions, which is designed for actual binary file uploads, so restricting to string may silently break real file upload use cases at runtime.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In file `src/resources/memories.ts`, line 844, the type of `file` in `MemoryUploadParams` was changed from `Uploadable` to `string`. This is a breaking change for any caller passing `File`, `Blob`, `Buffer`, or `ReadableStream` objects, and may silently break binary file uploads since the `upload` method still uses `multipartFormRequestOptions`. If the intent is to support both file paths (strings) and actual file objects, restore the type to `Uploadable` (or use a union like `Uploadable | string`). If only string file paths are now supported, verify that `multipartFormRequestOptions` handles plain strings correctly and update the method documentation accordingly.

Comment on lines 271 to 272
const log_lines: string[] = [];
const err_lines: string[] = [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: 🔴 Mutating globalThis.console is not concurrency-safe in a server handling multiple simultaneous requests — request B will capture request A's patched console as its originalConsole, and log lines from different requests will bleed into each other's log_lines/err_lines arrays until the finally block restores the wrong reference.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 271-278, the diff replaces a local `const console` shadow with direct mutation of `globalThis.console`. This is unsafe under concurrent requests: each request saves and restores `globalThis.console`, but overlapping requests can interleave such that (1) one request's `log` override overwrites another's, and (2) the 'original' captured by request B is already request A's patched console. Fix by keeping the original approach of passing a custom console-like object directly to user code (e.g., inject it as a parameter or use a module-scoped override only inside `tseval`) instead of mutating the shared global.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR has multiple critical, unresolved correctness bugs that have been flagged repeatedly across prior reviews without being addressed. In code-tool-worker.ts, the use of Buffer as a global will throw ReferenceError: Buffer is not defined in Deno environments (the intended runtime), and the mutation of globalThis.console creates a well-documented race condition where concurrent requests will bleed log lines into each other's log_lines/err_lines arrays. Additionally, the type change of file from Uploadable to string in src/resources/memories.ts is a breaking API change that will silently break callers passing File, Blob, or Buffer objects despite the underlying multipartFormRequestOptions call still expecting binary data. While the PR's goals — MCP local search, session tracking, and Gmail Actions support — are valuable, the core runtime and API correctness issues make this unsafe to ship.

Key Findings:

  • Buffer.from(code) in code-tool-worker.ts is used as a Node.js global in what is clearly a Deno/edge runtime context (evidenced by export default { fetch }, node: import prefixes, and Deno-specific stack trace parsing in parseError); this will throw a ReferenceError at runtime and has been flagged in at least 5 separate prior review comments without resolution.
  • The globalThis.console mutation pattern in code-tool-worker.ts (lines 270-278) is not concurrency-safe: two overlapping async requests will overwrite each other's console interceptor, causing log output to be attributed to the wrong request — this has been flagged in at least 6 prior review comments and remains unaddressed.
  • Changing memories.ts upload's file parameter from Uploadable to string is a breaking type change — existing callers passing File, Blob, Buffer, or ReadableStream will get TypeScript errors, and the method still calls multipartFormRequestOptions which is designed for actual binary uploads, creating a semantic mismatch.
  • In packages/mcp-server/src/instructions.ts, a static top-level import fs from 'fs/promises' will cause module initialization failure in non-Node.js runtimes at load time (not just at call time), and in packages/mcp-server/src/options.ts the returned McpOptions object is missing properties like stainlessApiKey, codeAllowHttpGets, and codeAllowedMethods that are defined in the type — both pre-existing issues that remain open.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • src/resources/memories.ts
  • packages/mcp-server/src/instructions.ts
  • packages/mcp-server/src/options.ts

@stainless-app stainless-app bot force-pushed the release-please--branches--main--changes--next--components--hyperspell branch from 7d81670 to 2b4d27c Compare April 8, 2026 03:31
Comment on lines 271 to 272
const log_lines: string[] = [];
const err_lines: string[] = [];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Correctness: 🐛 Mutating globalThis.console is not safe under concurrent requests. If two requests overlap, Request B captures Request A's overriding console as its originalConsole, and when B's finally block restores it, A's capturing function becomes the permanent global console — leaking captured log lines across requests indefinitely.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In packages/mcp-server/src/code-tool-worker.ts, lines 271-272 introduce a race condition: `globalThis.console` is mutated for the duration of an async request, but concurrent requests can interleave their save/restore operations, causing one request's capturing console to leak as the global after another request's `finally` block runs. Fix this by avoiding mutation of the shared global — instead, pass a custom console object directly into the evaluated code's scope (e.g. inject it as a variable alongside `client`), or use a per-invocation wrapper that does not mutate `globalThis`.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown


Confidence Score: 1/5 - Blocking Issues

Not safe to merge — this PR introduces multiple critical correctness issues that remain unresolved across 18 prior review comments and are confirmed again in the current review. Specifically, the mutation of globalThis.console in code-tool-worker.ts creates a well-documented race condition under concurrent requests where one request's finally block can permanently install another request's capturing function as the global console, leaking log lines across requests. Additionally, local-docs-search.ts will throw an unhandled "query is empty" exception from MiniSearch.search('') when an empty string is passed, with no guard in place. While the PR meaningfully expands the Gmail Actions integration and adds the effort parameter to MemorySearchParams, these runtime-crashing bugs and the unresolved security concern about unsandboxed code execution via tseval in code-tool-worker.ts make this unsafe to ship.

Key Findings:

  • The globalThis.console mutation pattern in code-tool-worker.ts (lines 270-278) is a confirmed race condition: concurrent async requests will interleave such that Request B captures Request A's patched console as originalConsole, and when B's finally block restores it, A's interceptor becomes the permanent global — this bug has appeared in 12 separate unresolved review comments and is flagged again at score 8.5 in the current review.
  • In local-docs-search.ts, this.methodIndex.search(query) and this.proseIndex.search(query) are called without any empty-string guard; MiniSearch throws a runtime "query is empty" error for this input, meaning any caller that passes an empty query string will receive an unhandled exception rather than an empty result set.
  • The code-tool-worker.ts file uses Buffer as a global (e.g., Buffer.from(code)), but multiple unresolved comments note that Buffer is not available as a global in Deno environments (evidenced by the export default { fetch } edge-worker pattern and Deno-specific stack trace parsing), meaning this will throw ReferenceError: Buffer is not defined at runtime in the intended deployment environment.
  • The options.ts McpOptions return object is missing several properties from defaultOptions (stainlessApiKey, codeAllowHttpGets, codeAllowedMethods, etc.), and instructions.ts uses a static top-level import fs from 'fs/promises' that will cause module initialization failure in non-Node runtimes — both flagged as unresolved correctness issues in prior reviews.
Files requiring special attention
  • packages/mcp-server/src/code-tool-worker.ts
  • packages/mcp-server/src/local-docs-search.ts
  • packages/mcp-server/src/instructions.ts
  • packages/mcp-server/src/options.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants