feat: scaffold Stagehand code-mode MCP host - #2597
Conversation
|
There was a problem hiding this comment.
6 issues found and verified against the latest diff
Confidence score: 3/5
- In
packages/integrations/src/codemode/executor.ts, the native executor path appears non-interruptible once execution starts because abort is only checked pre-run and bothexecute/closesharethis.queue; a hung snippet can block shutdown and tie up the worker indefinitely—add in-flight cancellation checks and ensureclosecan preempt or bypass a blocked execution path. - In
packages/integrations/src/codemode/executor.ts, the 256 KB result cap is enforced only after fullJSON.stringify, so very large snippet outputs can still cause memory spikes before truncation, with potential OOM/instability under hostile or accidental large returns—enforce limits during serialization/streaming or short-circuit oversized structures before full stringification. - Across
packages/integrations/src/codemode/tool-contract.ts,packages/integrations/src/codemode/executor.ts,packages/integrations/scripts/generate-codemode-content.mjs, andpackages/integrations/src/codemode/snippet.ts, key new contract/executor/escaping/binding behaviors lack registered focused tests, increasing regression risk for public codemode behavior and CI blind spots—add and register targeted tests for queueing/cancellation, schema/result formatting, content escaping with--check, andexecuteStagehandSnippetvalidation paths.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/integrations/src/codemode/tool-contract.ts">
<violation number="1" location="packages/integrations/src/codemode/tool-contract.ts:24">
P3: Current CI cannot exercise this new public contract because the package has no registered tests. Add focused schema and result-formatting tests, then register a package test task.
(Based on your team's feedback about unit tests for new behavior.) .</violation>
</file>
<file name="packages/integrations/src/codemode/executor.ts">
<violation number="1" location="packages/integrations/src/codemode/executor.ts:25">
P3: This new executor has no committed focused tests for queueing, lazy lifecycle, error cleanup, or serialization edge cases, leaving its public native/MCP behavior unguarded. Add executor-level tests covering a normal persistent call and key failure/close paths.
(Based on your team's feedback about unit tests for new behavior.) .</violation>
<violation number="2" location="packages/integrations/src/codemode/executor.ts:84">
P2: For the native (non-MCP) executor path, a non-terminating snippet can never be interrupted: the AbortSignal is only checked once before the code starts, and `execute`/`close` both serialize through `this.queue`. A snippet that loops forever leaves the in-flight call unresolved, so `close()` (which waits on the queue) never resolves and the persistent browser/process leaks on shutdown. Consider passing the signal through to the snippet so an abort can terminate the run, or otherwise bound execution time.</violation>
<violation number="3" location="packages/integrations/src/codemode/executor.ts:188">
P2: The size guard only kicks in after `JSON.stringify` has fully built the result string in memory, so a snippet that returns a very large value still consumes unbounded memory before the 256 KB truncation is applied. This undermines MAX_RESULT_BYTES as a safety/memory bound in an agent-facing code executor that has no sandbox. Truncating incrementally (e.g., streaming serialization) or imposing a forced/capped serialization would keep memory usage proportional to the configured limit.</violation>
</file>
<file name="packages/integrations/scripts/generate-codemode-content.mjs">
<violation number="1" location="packages/integrations/scripts/generate-codemode-content.mjs:28">
P3: Generated-content escaping and stale-file validation have no automated coverage; add focused tests for special characters plus current and stale `--check` output.
(Based on your team's feedback about unit tests for new behavior.)</violation>
</file>
<file name="packages/integrations/src/codemode/snippet.ts">
<violation number="1" location="packages/integrations/src/codemode/snippet.ts:11">
P3: Regression coverage is absent for `executeStagehandSnippet`, including binding validation and injected dependency behavior. Add focused unit tests for normal execution, reserved/invalid names, and optional `stagehand`.
(Based on your team's feedback about adding unit tests for new behavior.) .</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
dab19ae to
171765f
Compare
There was a problem hiding this comment.
All reported issues were addressed across 9 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
8517905 to
2cfa7b0
Compare
There was a problem hiding this comment.
All reported issues were addressed across 15 files
Architecture diagram
sequenceDiagram
participant MCP_Client as MCP Client
participant StdioTransport as Stdio Transport
participant ServerEntry as stdio-server.ts
participant McpHost as McpServer Instance
participant Shutdown as closeCodeModeStdio()
Note over MCP_Client,Shutdown: NEW: Stagehand code-mode MCP host startup and lifecycle
MCP_Client->>StdioTransport: spawn process (node dist/codemode/stdio-server.mjs)
StdioTransport->>ServerEntry: stdin/stdout/stderr connected
ServerEntry->>ServerEntry: createCodeModeMcpHost()
ServerEntry->>McpHost: NEW: McpServer("stagehand-codemode", "4.0.0")
McpHost-->>ServerEntry: ready
ServerEntry->>ServerEntry: connectCodeModeStdio(server)
ServerEntry->>McpHost: connect(new StdioServerTransport())
McpHost-->>ServerEntry: connected
ServerEntry->>StdioTransport: stderr: "Stagehand code-mode MCP host listening on stdio"
Note over StdioTransport,McpHost: MCP initialization handshake
MCP_Client->>StdioTransport: initialize request
StdioTransport->>McpHost: forward initialize
McpHost-->>StdioTransport: capabilities (no tools)
StdioTransport-->>MCP_Client: capabilities
Note over MCP_Client,Shutdown: Shutdown scenarios
alt stdin EOF (normal shutdown)
ServerEntry->>ServerEntry: stdin "end" event
ServerEntry->>McpHost: close()
ServerEntry->>Shutdown: closeCodeModeStdio([server])
Shutdown->>McpHost: close()
alt cleanup completes within 5s
McpHost-->>Shutdown: resolved
Shutdown-->>ServerEntry: true
ServerEntry->>ServerEntry: process.exit(0)
else cleanup timeout
Shutdown->>Shutdown: setTimeout(5000)
Shutdown-->>ServerEntry: false
ServerEntry->>StdioTransport: stderr: "Failed to close..."
ServerEntry->>ServerEntry: process.exit(1)
end
else SIGINT (Ctrl+C)
ServerEntry->>ServerEntry: signal handler
ServerEntry->>McpHost: close()
ServerEntry->>Shutdown: closeCodeModeStdio([server])
Shutdown-->>ServerEntry: result
ServerEntry->>ServerEntry: process.exit(130)
else SIGTERM
ServerEntry->>ServerEntry: signal handler
ServerEntry->>McpHost: close()
ServerEntry->>Shutdown: closeCodeModeStdio([server])
Shutdown-->>ServerEntry: result
ServerEntry->>ServerEntry: process.exit(143)
end
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 6 files (changes from recent commits).
Confidence score: 5/5
- In
packages/integrations/tests/stdio-server.test.ts,waitForOutputcan leave its timeout/listener active when the stream ends/errors early or whenclient.connectthrows beforeawait ready, which can cause dangling async work and flaky/hanging test runs—ensure cleanup runs on all exit paths (match, error, end, and thrown connect) viafinally/shared teardown.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/integrations/tests/stdio-server.test.ts">
<violation number="1" location="packages/integrations/tests/stdio-server.test.ts:50">
P3: waitForOutput only clears its timer/listener when the expected string is matched; if the stream errors or ends first, or if client.connect throws before await ready (ready is created outside the try), the 10s timeout and data listener linger and can produce a late unhandled rejection. Consider rejecting promptly on stream error/end/close and creating the promise inside the try so an early connect failure doesn't leave a dangling timer.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Why
The code-mode product work spans three distinct review domains: process hosting, browser code execution, and agent guidance. This bottom PR isolates the package and Model Context Protocol (MCP) host so its build, transport, and shutdown behavior can be reviewed without the execution engine or prompt content.
Stack
code_executeregistrationSKILL.md,REFERENCE.md, generated exports, package assets, and guidance loading checksEach PR is intended to build, test, and make a truthful claim independently.
What changed
@browserbasehq/stagehand-integrationsworkspace packageSIGINTandSIGTERMIntentionally not included
E2E Test Matrix
pnpm --filter @browserbasehq/stagehand-integrations typecheck && pnpm --filter @browserbasehq/stagehand-integrations build && pnpm --filter @browserbasehq/stagehand-integrations test:unit{"initialized":true,"toolsCapability":null,"readyMessage":true}pnpm exec turbo run test:unit --filter=@browserbasehq/stagehand-integrationspnpm checkChangeset
None. This introduces a private workspace package and does not publish a release.