Skip to content

fix(server): Cursor sandboxed threads find their helper when running from source - #13571

Merged
juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/cursor-sandbox-helper
Sep 25, 2026
Merged

juliusmarminge merged 1 commit into
t3code/codex-turn-mappingfrom
v2/cursor-sandbox-helper

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Restricted-mode (sandboxed) Cursor threads fail when T3 runs from source (vp run dev, node apps/server/dist/bin.mjs) with "Local SDK sandboxing was requested, but sandboxing is not supported in this environment."

Cause

@cursor/sdk 1.0.31 finds its platform package through platform-package-locator: starting at dirname(process.argv[1]) and then dirname(process.execPath), it walks up parent directories looking for <dir>/node_modules/@cursor/sdk-<platform>-<arch>/<file> (or @cursor/february-*). pnpm's isolated layout installs that optional dependency only as a sibling inside the virtual store (node_modules/.pnpm/@cursor+sdk@1.0.31/node_modules/@cursor/sdk-linux-x64). apps/server/node_modules/@cursor/ contains only sdk, so the walk from apps/server/src never finds the package. Without cursorsandbox, isSandboxSupported returns false and the SDK refuses sandboxed runs.

Two other lookups use the same locator and were silently degraded too:

  • rg fell back to whatever ripgrep is on PATH, or none.
  • The tree-sitter vendor natives were missing, which disables shell command analysis.

Fix

Add publicHoistPattern: ["@cursor/sdk-*"] to pnpm-workspace.yaml. pnpm then links the installed platform package into the root node_modules/@cursor/, which the upward walk from apps/server/... reaches.

  • supportedArchitectures still filters optionals, so only the matching platform package is linked. On this Linux box that is sdk-linux-x64.
  • The lockfile does not change.
  • No version pin to keep in sync with @cursor/sdk, unlike declaring the five platform packages as server optionalDependencies.

Effect on packaged builds

  • Desktop: unaffected. build-desktop-artifact.ts runs its own staged vp install --prod with a generated pnpm-workspace.yaml that does not carry publicHoistPattern. stageCursorSdkPlatformPackages still copies sdk-* from beside the real SDK directory into resources/node_modules/@cursor. The root-level link is a symlink to the same store directory, and the asar globs already exclude **/node_modules/@cursor/sdk-*.
  • CLI archive / npx t3: unaffected. build-cli-archive.ts installs runtime externals with nodeLinker: hoisted into a separate stage dir, from its own generated workspace config.

Verification

  • Locator probe. It runs the SDK's own platform-package-locator module, sliced out of dist/esm/index.js, with argv[1] set to each server entry: apps/server/src/bin.ts, apps/server/dist/bin.mjs, and apps/server/scripts/record-cursor-agent-sdk-replay-fixture.ts.
    • Before: cursorsandbox: null, rg: null, vendor: null for all three.
    • After: cursorsandbox, rg and vendor all resolve under <repo>/node_modules/@cursor/sdk-linux-x64/… for all three.
  • Live sandboxed Cursor turn. Agent.create({ model: { id: "composer-2.5" }, local: { cwd, autoReview: false, sandboxOptions: { enabled: true } } }) with argv[1] at apps/server/src/bin.ts, prompt "Run cat hello.txt".
    • Before: Local SDK sandboxing was requested, but sandboxing is not supported in this environment.
    • After: status: finished, output sandbox-ok.
  • vp i: lockfile up to date. The only new entry in the root node_modules is the @cursor/sdk-linux-x64 symlink.
  • cd apps/server && vp test run src/orchestration-v2/testkit/OrchestratorReplayFixtures.integration.test.ts -t cursor: 10 passed.
  • vp test run scripts/build-desktop-artifact.test.ts scripts/lib/cursor-sdk-packaging.test.ts: 67 passed, 6 failed. The same 6 fail on the base branch without this change, after a reinstall to the base layout. The causes are environmental on this box:
    • cursor-sdk-packaging.test.ts asserts there is no node_modules above TMPDIR, and /tmp/node_modules exists.
    • Five Windows sidecar tests fail in asar packing with "expected native binaries … but none were unpacked".
  • cd apps/server && vp exec tsc --noEmit -p .: no error TS or warning TS.
  • vp run knip:check: one unused export, THREAD_DETAILS_PANEL_SPLIT_BUTTON_SURFACE_CLASS in apps/web. It comes from the base branch's head commit and is unrelated to this change.
  • Not run: a packaged desktop or CLI build, and macOS/Windows installs. Their staging paths do not read this setting.

Model: Claude Opus 5.5 (Claude Code)

🤖 Generated with Claude Code

…from source

@cursor/sdk locates its platform package (cursorsandbox, rg, tree-sitter
natives) by walking up from the entry script looking for
node_modules/@cursor/sdk-<platform>-<arch>. pnpm's isolated layout keeps that
optional dependency inside the virtual store next to the SDK, so the walk from
apps/server never reaches it and restricted-mode threads fail with "sandboxing
is not supported in this environment". Publicly hoisting @cursor/sdk-* links
the installed platform package into the root node_modules, which the walk
reaches.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Sep 25, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 1f8fb38

Macroscope's review found this PR approvable — This small workspace configuration fix makes the already-supported Cursor sandbox helpers discoverable during source-based server runs. Its effect is localized to dependency layout and existing Cursor execution, with staged desktop and CLI packaging paths remaining separately configured.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire — 4.9 KiB — 6.8 KiB ✅
Codex Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Codex Live turn WebSocket wire — 1.1 KiB — 2.0 KiB ✅
Codex Live turn WebSocket decoded — 20.4 KiB — 29.3 KiB ✅
Codex Live turn messages — 1 — 8 ✅
Claude Total thread wire — 4.9 KiB — 6.8 KiB ✅
Claude Thread snapshot wire — 3.7 KiB — 4.9 KiB ✅
Claude Live turn WebSocket wire — 1.2 KiB — 2.0 KiB ✅
Claude Live turn WebSocket decoded — 20.8 KiB — 29.3 KiB ✅
Claude Live turn messages — 2 — 8 ✅

Baseline: unavailable · PR result: 1f8fb38 · Source CI: failure

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@juliusmarminge
juliusmarminge merged commit e24ad9a into t3code/codex-turn-mapping Sep 25, 2026
21 of 24 checks passed
@juliusmarminge
juliusmarminge deleted the v2/cursor-sandbox-helper branch September 25, 2026 04:51
juliusmarminge added a commit that referenced this pull request Sep 25, 2026
…from source (#13571)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant