@schoolai/shipyard 3.11.0 → 3.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{auth-GGM253LQ.js → auth-AUY74PMB.js} +3 -3
- package/dist/capability-detector-worker.js +8 -8
- package/dist/{chunk-R3XQ6W7L.js → chunk-4SYLDZTY.js} +4 -4
- package/dist/{chunk-C6QOTETH.js → chunk-5LWD5W7O.js} +24 -10
- package/dist/chunk-5LWD5W7O.js.map +1 -0
- package/dist/{chunk-IJHF4OM4.js → chunk-5W5N5U2S.js} +2 -2
- package/dist/{chunk-L7ELOV3S.js → chunk-FVZ5BDZS.js} +4 -4
- package/dist/chunk-FVZ5BDZS.js.map +1 -0
- package/dist/{chunk-RW2OTTUA.js → chunk-KYLYGFMH.js} +4 -4
- package/dist/{chunk-QJP7JCIS.js → chunk-LRNGLC4V.js} +41 -3
- package/dist/chunk-LRNGLC4V.js.map +1 -0
- package/dist/{chunk-A2UK6TW2.js → chunk-LZSMNUAI.js} +18 -1
- package/dist/{chunk-A2UK6TW2.js.map → chunk-LZSMNUAI.js.map} +1 -1
- package/dist/{chunk-Z37T5W6S.js → chunk-P2HZDIN7.js} +12 -7
- package/dist/chunk-P2HZDIN7.js.map +1 -0
- package/dist/{chunk-ZRJTZLRF.js → chunk-QKJNVVQ3.js} +4 -4
- package/dist/{chunk-2EQOL57Z.js → chunk-TFRYQDDG.js} +2 -2
- package/dist/{chunk-YXPPZQBJ.js → chunk-VL5RUCRF.js} +164 -37
- package/dist/chunk-VL5RUCRF.js.map +1 -0
- package/dist/{chunk-3WEEGJJN.js → chunk-X5KCX6ZS.js} +2 -2
- package/dist/{chunk-GM6MH4CD.js → chunk-XIEOWUPV.js} +2 -2
- package/dist/{chunk-6LINHACK.js → chunk-Y5UWRARP.js} +47 -24
- package/dist/chunk-Y5UWRARP.js.map +1 -0
- package/dist/cursor-runner.js +88 -62
- package/dist/cursor-runner.js.map +1 -1
- package/dist/electron-utility.js +5 -5
- package/dist/{git-repo-QNGPCJLI.js → git-repo-CTZJS3ER.js} +6 -4
- package/dist/index.js +8 -8
- package/dist/{logger-2F3CBS3V.js → logger-AN7EUK2B.js} +7 -5
- package/dist/{login-U256OVOJ.js → login-YB34LF4L.js} +6 -6
- package/dist/{logout-HY3MPOY5.js → logout-GUXVSWLZ.js} +5 -5
- package/dist/{mcp-servers-ICHOWXZB.js → mcp-servers-OAPQNDA7.js} +4 -4
- package/dist/{roi-YM5OOWHG.js → roi-NXJHL5X2.js} +3 -3
- package/dist/{serve-D5GKV2RU.js → serve-P3U2C5YH.js} +1175 -739
- package/dist/{serve-D5GKV2RU.js.map → serve-P3U2C5YH.js.map} +1 -1
- package/dist/{skills-W2Y6TWHA.js → skills-2UBVHFQ5.js} +2 -2
- package/dist/{start-JY26XC5R.js → start-Y34X3WVF.js} +10 -10
- package/package.json +1 -1
- package/dist/chunk-6LINHACK.js.map +0 -1
- package/dist/chunk-C6QOTETH.js.map +0 -1
- package/dist/chunk-L7ELOV3S.js.map +0 -1
- package/dist/chunk-QJP7JCIS.js.map +0 -1
- package/dist/chunk-YXPPZQBJ.js.map +0 -1
- package/dist/chunk-Z37T5W6S.js.map +0 -1
- /package/dist/{auth-GGM253LQ.js.map → auth-AUY74PMB.js.map} +0 -0
- /package/dist/{chunk-R3XQ6W7L.js.map → chunk-4SYLDZTY.js.map} +0 -0
- /package/dist/{chunk-IJHF4OM4.js.map → chunk-5W5N5U2S.js.map} +0 -0
- /package/dist/{chunk-RW2OTTUA.js.map → chunk-KYLYGFMH.js.map} +0 -0
- /package/dist/{chunk-ZRJTZLRF.js.map → chunk-QKJNVVQ3.js.map} +0 -0
- /package/dist/{chunk-2EQOL57Z.js.map → chunk-TFRYQDDG.js.map} +0 -0
- /package/dist/{chunk-3WEEGJJN.js.map → chunk-X5KCX6ZS.js.map} +0 -0
- /package/dist/{chunk-GM6MH4CD.js.map → chunk-XIEOWUPV.js.map} +0 -0
- /package/dist/{git-repo-QNGPCJLI.js.map → git-repo-CTZJS3ER.js.map} +0 -0
- /package/dist/{logger-2F3CBS3V.js.map → logger-AN7EUK2B.js.map} +0 -0
- /package/dist/{login-U256OVOJ.js.map → login-YB34LF4L.js.map} +0 -0
- /package/dist/{logout-HY3MPOY5.js.map → logout-GUXVSWLZ.js.map} +0 -0
- /package/dist/{mcp-servers-ICHOWXZB.js.map → mcp-servers-OAPQNDA7.js.map} +0 -0
- /package/dist/{roi-YM5OOWHG.js.map → roi-NXJHL5X2.js.map} +0 -0
- /package/dist/{skills-W2Y6TWHA.js.map → skills-2UBVHFQ5.js.map} +0 -0
- /package/dist/{start-JY26XC5R.js.map → start-Y34X3WVF.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/session/cursor-runner.ts","../src/shared/capabilities/runtime/cursor-ripgrep.ts","../src/services/session/cursor-init-error-formatter.ts","../src/services/session/cursor-runner-error.ts"],"sourcesContent":["/**\n * cursor-runner — forked Node child that owns the `@cursor/sdk` lifecycle\n * outside the daemon's V8 isolate (plan v2 §2).\n *\n * The daemon spawns this entry via `child_process.fork(require.resolve(\n * './cursor-runner.js'))` once per Cursor task. The child:\n * 1. waits for an `init` IPC message,\n * 2. calls `Agent.create()` from `@cursor/sdk`,\n * 3. on each `push_message`, calls `agent.send()` and iterates\n * `Run.stream()`, forwarding every `SDKMessage` back to the daemon,\n * 4. on `interrupt`, cancels the in-flight run,\n * 5. on `close`, disposes the agent and exits 0.\n *\n * Native panics (sqlite, FFI) crash THIS child only. The daemon-side\n * supervisor (S2b) observes the child exit, emits `subprocess_died`, and\n * the session FSM tears down cleanly.\n *\n * Per-tool gating uses the `.cursor/hooks.json` `preToolUse` hook script +\n * cursor-hook-socket (cursor-hook-socket.ts) — @cursor/sdk@1.0.13 has no\n * public respond-to-request API.\n */\n\nimport {\n Agent,\n Cursor,\n type InteractionUpdate,\n type Run,\n type SDKAgent,\n type SDKMessage,\n type SDKUserMessage,\n type SendOptions,\n type SettingSource,\n} from '@cursor/sdk';\nimport { ContentBlockSchema, HARNESS_SERVER_NAME } from '@shipyard/loro-schema';\n\nimport { configureCursorRipgrepPath } from '../../shared/capabilities/runtime/cursor-ripgrep.js';\nimport {\n buildCursorUserPrompt,\n type CursorResolvedSkillBody,\n type CursorUserInput,\n} from './cursor-content-builder.js';\nimport { formatCursorInitError, type ModelInfo } from './cursor-init-error-formatter.js';\nimport { serializeCursorRunnerError } from './cursor-runner-error.js';\nimport {\n type DaemonToRunner,\n parseDaemonToRunner,\n type RunnerToDaemon,\n} from './cursor-runner-protocol.js';\n\nconfigureCursorRipgrepPath();\n\n/**\n * Real token usage from a `turn-ended` interaction update. Captured during\n * `onDelta` and forwarded on `run_complete` so the daemon can map real counts\n * onto the `TurnResult` instead of marking everything as estimated.\n */\ninterface TurnUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n}\n\n/** Named subagent catalog shape as it arrives over IPC (mirrors the protocol). */\ntype RunnerAgents = Record<\n string,\n {\n description: string;\n prompt: string;\n model?: { id: string } | 'inherit';\n mcpServers?: string[];\n }\n>;\n\ninterface RunnerState {\n agent: SDKAgent | null;\n currentRun: Run | null;\n currentGeneration: number;\n taskId: string;\n harnessToken: string;\n /**\n * Stable per-runner identity for the runner-scoped harness path. When set,\n * the harness MCP entry uses `x-shipyard-runner-id: harnessRunnerId` instead\n * of `x-shipyard-task-id: taskId`, keeping the `mcpServers` map (and thus the\n * SDK executor cache key) byte-identical across task switches. Empty string\n * = legacy per-task harness path.\n */\n harnessRunnerId: string;\n /** Harness MCP server URL, retained so reinit can rebuild the entry. */\n harnessUrl: string;\n /** Workspace cwd, retained so reinit can rebuild `local.cwd`. */\n cwd: string;\n /** Cursor API key, retained so reinit can recreate the Agent. */\n apiKey: string;\n /**\n * Pool-managed flag. When true, `close` disposes the Agent but does NOT\n * `process.exit(0)` — the runner acks `pooled_idle` and the daemon keeps the\n * warm process alive for the next claim.\n */\n pooled: boolean;\n /**\n * Cursor model id supplied at init. Threaded into every\n * `SendOptions.model.id` when Fast Mode is on so the runtime knows which\n * model the params belong to.\n */\n modelId: string;\n /**\n * Live Fast Mode flag. Initial value from `init`; updated by\n * `set_fast_mode` IPC. The runner attaches Fast Mode params only when\n * both this is true AND `fastModeParam` is non-null.\n */\n fastMode: boolean;\n /**\n * Resolved Fast Mode `{id, value}` binding for `modelId`, sourced from\n * the daemon's discovery cache. Null = no binding known; the runner\n * sends the plain `agent.send(message)` shape regardless of `fastMode`.\n */\n fastModeParam: { id: string; value: string } | null;\n /**\n * Live MCP server set, seeded at init/reinit and updated by `set_mcp_servers`\n * IPC. `@cursor/sdk@1.0.17` takes the MCP set as a per-RUN parameter\n * (`SendOptions.mcpServers`, applied via the local `RunExecutor`'s\n * `mcpServersOverride` on every `agent.send()`); there is NO\n * `agent.setMcpServers`. So we store the current set here and thread it into\n * each send — visibility changes apply live on the next turn, no restart. The\n * harness MCP entry is composed into this at init/reinit and preserved on\n * every `set_mcp_servers` update.\n */\n mcpServers: Record<string, unknown>;\n /**\n * In-flight `handleInit`/`handleReinit` promise — resolves when init has\n * settled (agent created, or init_error/reinit_error sent; never rejects).\n * `handlePushMessage` awaits it so a `push_message` that races ahead of\n * `Agent.create` waits for the agent instead of erroring \"not initialized.\"\n */\n initSettled: Promise<void> | null;\n /**\n * Native Cursor SDK conversation mode. Sourced from the `init` IPC; persists\n * for the agent's lifetime. `'plan'` tells composer-2.5 to use its built-in\n * `createPlan` tool instead of writing files (soft signal — hooks.json is the\n * hard enforcement layer). `undefined` = SDK default (`'agent'` mode).\n */\n mode?: 'agent' | 'plan';\n}\n\nconst state: RunnerState = {\n agent: null,\n currentRun: null,\n currentGeneration: 0,\n taskId: '',\n harnessToken: '',\n harnessRunnerId: '',\n harnessUrl: '',\n cwd: '',\n apiKey: '',\n pooled: false,\n modelId: '',\n fastMode: false,\n fastModeParam: null,\n mcpServers: {},\n initSettled: null,\n mode: undefined,\n};\n\nfunction send(msg: RunnerToDaemon): void {\n /**\n * `process.send` is only defined when this module is started via\n * `fork()` with an IPC channel. If it is undefined (e.g. the file is\n * accidentally executed directly), there is no way to reach the\n * parent — the runner is unusable; log to stderr and drop.\n */\n if (typeof process.send !== 'function') {\n process.stderr.write(\n `${JSON.stringify({ level: 'error', event: 'runner_no_ipc_channel', dropped: msg.kind })}\\n`\n );\n return;\n }\n process.send(msg);\n}\n\nfunction log(level: 'info' | 'warn' | 'error', message: string, data?: unknown): void {\n send({ kind: 'log', level, message, data });\n}\n\n/**\n * Runner-side throttle for `stream_activity` heartbeats. `onDelta` fires per\n * output chunk (text/thinking/shell-output deltas) — far too often to forward\n * each as IPC. Coalesce to at most one heartbeat per this interval. Kept well\n * below the daemon's stall window (180s) so the daemon reliably sees liveness\n * within it; the daemon applies its own coarser throttle on receipt.\n */\nconst STREAM_ACTIVITY_IPC_THROTTLE_MS = 2_000;\n/** Wall-clock of the last forwarded `stream_activity`. Reset per turn in `handlePushMessage`. */\nlet lastStreamActivitySentAt = 0;\n\n/**\n * Forward a throttled liveness heartbeat for the active generation. Called from\n * `onDelta` — ANY interaction update means the run is producing output, so the\n * daemon's stall watchdog should measure true silence rather than step cadence.\n * Drops stale-generation calls (the daemon would filter them anyway).\n */\nfunction maybeSendStreamActivity(generation: number): void {\n if (state.currentGeneration !== generation) return;\n const now = Date.now();\n if (now - lastStreamActivitySentAt < STREAM_ACTIVITY_IPC_THROTTLE_MS) return;\n lastStreamActivitySentAt = now;\n send({ kind: 'stream_activity', generation });\n}\n\nconst INIT_MODEL_LIST_TIMEOUT_MS = 5000;\n\nasync function sendInitErrorFromAgentCreateFailure(args: {\n apiKey: string;\n modelId: string;\n err: unknown;\n}): Promise<void> {\n const originalError = args.err instanceof Error ? args.err.message : String(args.err);\n /**\n * On Agent.create failure, probe Cursor.models.list() once to capture\n * the authoritative {id, aliases} set. If the requested model is in\n * that set, the failure is unrelated to model resolution; if not, the\n * id is stale and the log line names the replacement immediately.\n *\n * Best-effort: the list call may itself fail (offline, auth, rate-\n * limited). The formatter handles a null `availableModels` by falling\n * back to the original error verbatim — no information loss vs the\n * pre-Item-1 behavior.\n */\n let availableModels: ModelInfo[] | null = null;\n let listError: string | undefined;\n /**\n * @cursor/sdk@1.0.13's CursorRequestOptions has no AbortSignal or timeout\n * field — a hung backend would block init_error indefinitely and wedge\n * the session FSM in \"initializing\". 5s cap restores the pre-Item-1\n * upper bound (the original code sent init_error immediately) at the\n * cost of degrading the diagnostic when Cursor's API is slow.\n */\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n const listPromise = Cursor.models.list({ apiKey: args.apiKey });\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(\n () => reject(new Error(`timed out after ${INIT_MODEL_LIST_TIMEOUT_MS}ms`)),\n INIT_MODEL_LIST_TIMEOUT_MS\n );\n });\n const models = await Promise.race([listPromise, timeoutPromise]);\n availableModels = models.map((m) => ({ id: m.id, aliases: m.aliases }));\n } catch (listErr) {\n listError = listErr instanceof Error ? listErr.message : String(listErr);\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n const serialized = serializeCursorRunnerError(args.err);\n send({\n kind: 'init_error',\n error: formatCursorInitError({\n requestedModelId: args.modelId,\n originalError,\n availableModels,\n listError,\n }),\n ...(serialized.errorName !== undefined ? { errorName: serialized.errorName } : {}),\n ...(serialized.errorCode !== undefined ? { errorCode: serialized.errorCode } : {}),\n ...(serialized.statusCode !== undefined ? { statusCode: serialized.statusCode } : {}),\n retryable: serialized.isRetryable,\n });\n}\n\n/**\n * Build the harness MCP entry. Uses the runner-scoped header\n * (`x-shipyard-runner-id`) when `harnessRunnerId` is set — that keeps the\n * entry byte-identical across the runner's whole life (init→reinit) so the\n * SDK executor cache key never changes on task switch. Falls back to the\n * legacy per-task header (`x-shipyard-task-id`) for non-pooled spawns.\n */\nfunction buildHarnessServerEntry(args: {\n harnessUrl: string;\n harnessToken: string;\n harnessRunnerId: string;\n taskId: string;\n}): {\n type: 'http';\n url: string;\n headers: Record<string, string>;\n} {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${args.harnessToken}`,\n };\n if (args.harnessRunnerId.length > 0) {\n headers['x-shipyard-runner-id'] = args.harnessRunnerId;\n } else {\n headers['x-shipyard-task-id'] = args.taskId;\n }\n return {\n type: 'http',\n url: args.harnessUrl,\n headers,\n };\n}\n\n/**\n * Compose the SDK `local` option. `settingSources: ['user', 'project']` is\n * parity with Claude/Codex — those runtimes auto-discover the user's installed\n * skills and the repo's project-level rules; leaving settingSources at the\n * default (`[]`) silently disabled Cursor's equivalent. User-authored markdown\n * on the user's own machine; same trust posture as the other agents.\n * Cross-runtime *portability* of those skills is tracked separately in #3955.\n *\n * `cwd: [cwd, skillsDir]` — `cwd[0]` is the repo workspace; `skillsDir` (cwd[1])\n * is Shipyard's task-scoped `~/.shipyard/cursor-skills/{taskId}` dir, which hosts\n * the permission-hook substrate (`.cursor/hooks.json` + hmac + allow). The SDK\n * resolves the WORKSPACE (rules/skills discovery) from `cwd[0]` ONLY\n * (`getExplicitLocalWorkspaceRef` → `n[0]`), so `cwd[1]` is NOT a prompt or\n * rules channel — the Shipyard prompt is delivered via the harness MCP server's\n * `initialize.instructions` instead. `cwd[1]` is retained because it is how the\n * SDK discovers the per-task hook substrate; dropping it would silently disable\n * Cursor permission gating.\n */\nfunction buildLocalOption(\n cwd: string,\n skillsDir: string\n): {\n cwd: string | string[];\n settingSources: SettingSource[];\n} {\n const settingSources: SettingSource[] = ['user', 'project'];\n return {\n ...(skillsDir ? { cwd: [cwd, skillsDir] } : { cwd }),\n settingSources,\n };\n}\n\n/**\n * Named subagent catalog as an SDK option. Omitted when the catalog is empty —\n * passing `agents: {}` would register an empty map and override any agents the\n * SDK might discover itself.\n */\nfunction buildAgentsOption(agents: RunnerAgents | undefined): Record<string, never> {\n return agents !== undefined && Object.keys(agents).length > 0\n ? // eslint-disable-next-line no-restricted-syntax -- AgentDefinition union (model field) requires boundary cast\n { agents: agents as never }\n : {};\n}\n\n/**\n * Acquire the Agent for a task. Priority order:\n * 1. `injectedAgentId` — cross-runtime structured handoff (Wave 7.5). The\n * daemon pre-wrote a fabricated conversation to SQLite; we MUST resume\n * that id or the conversation never surfaces. A same-id `Agent.create()`\n * would PRIMARY-KEY-conflict on the agents row.\n * 2. `resumeAgentId` — persisted from a prior `init_ok`. SDK reads the prior\n * conversation from its SQLite checkpoint store. If the store entry is\n * gone (user wiped ~/.cursor/, etc.) the resume throws; we catch and fall\n * through to `Agent.create` so the spawn succeeds without prior context.\n * 3. `Agent.create` — fresh agent. Default path for never-spawned tasks.\n *\n * Conversation history not preserved on path 3 is acceptable — Shipyard's\n * JSONL is the authoritative log; the SDK's checkpoint store is a latency /\n * context win, not the source of truth.\n */\nasync function acquireAgent(args: {\n apiKey: string;\n taskId: string;\n modelId: string;\n local: ReturnType<typeof buildLocalOption>;\n mcpServers: Record<string, unknown>;\n agentsOption: Record<string, never>;\n injectedAgentId?: string;\n resumeAgentId?: string;\n mode?: 'agent' | 'plan';\n}): Promise<SDKAgent> {\n const baseOptions = {\n apiKey: args.apiKey,\n model: { id: args.modelId },\n local: args.local,\n // eslint-disable-next-line no-restricted-syntax -- McpServerConfig union types require boundary cast\n mcpServers: args.mcpServers as never,\n ...args.agentsOption,\n ...(args.mode !== undefined ? { mode: args.mode } : {}),\n };\n async function createFreshAgent(): Promise<SDKAgent> {\n return Agent.create({ ...baseOptions, name: `shipyard-task-${args.taskId}` });\n }\n if (args.injectedAgentId !== undefined) {\n return Agent.resume(args.injectedAgentId, baseOptions);\n }\n if (args.resumeAgentId !== undefined) {\n try {\n const resumed = await Agent.resume(args.resumeAgentId, baseOptions);\n log('info', 'runner_resume_agent_succeeded', { agentId: args.resumeAgentId });\n return resumed;\n } catch (resumeErr) {\n log('warn', 'runner_resume_agent_failed_falling_back_to_create', {\n agentId: args.resumeAgentId,\n error: resumeErr instanceof Error ? resumeErr.message : String(resumeErr),\n });\n return createFreshAgent();\n }\n }\n return createFreshAgent();\n}\n\n/** Snapshot MCP status for init/reinit ok messages (Cursor has no live stream). */\nfunction buildMcpStatusSnapshot(mcpServers: Record<string, unknown>): Array<{\n name: string;\n status: string;\n}> {\n return Object.keys(mcpServers).map((name) => ({\n name,\n /**\n * Cursor local runtime does not expose a stable MCP-status stream during\n * init. Emit a non-empty snapshot so daemon-side init metadata never\n * races with an empty MCP list.\n */\n status: 'connected',\n }));\n}\n\nasync function handleInit(args: {\n taskId: string;\n cwd: string;\n apiKey: string;\n modelId: string;\n mcpServers: Record<string, unknown>;\n harnessUrl: string;\n harnessToken: string;\n harnessRunnerId: string;\n pooled: boolean;\n skillsDir: string;\n generation: number;\n injectedAgentId?: string;\n resumeAgentId?: string;\n fastMode: boolean;\n fastModeParam: { id: string; value: string } | null;\n agents?: RunnerAgents;\n mode?: 'agent' | 'plan';\n}): Promise<void> {\n state.currentGeneration = args.generation;\n state.taskId = args.taskId;\n state.harnessToken = args.harnessToken;\n state.harnessRunnerId = args.harnessRunnerId;\n state.harnessUrl = args.harnessUrl;\n state.cwd = args.cwd;\n state.apiKey = args.apiKey;\n state.pooled = args.pooled;\n state.modelId = args.modelId;\n state.fastMode = args.fastMode;\n state.fastModeParam = args.fastModeParam;\n state.mode = args.mode;\n try {\n /**\n * The daemon validates `mcpServers` shape before sending. We pass\n * through as-is; a malformed entry will surface as an\n * `Agent.create()` rejection rather than a runner crash.\n */\n const mcpServers: Record<string, unknown> = {\n ...args.mcpServers,\n [HARNESS_SERVER_NAME]: buildHarnessServerEntry({\n harnessUrl: args.harnessUrl,\n harnessToken: args.harnessToken,\n harnessRunnerId: args.harnessRunnerId,\n taskId: args.taskId,\n }),\n };\n state.mcpServers = mcpServers;\n const agent = await acquireAgent({\n apiKey: args.apiKey,\n taskId: args.taskId,\n modelId: args.modelId,\n local: buildLocalOption(args.cwd, args.skillsDir),\n mcpServers,\n agentsOption: buildAgentsOption(args.agents),\n ...(args.injectedAgentId !== undefined && { injectedAgentId: args.injectedAgentId }),\n ...(args.resumeAgentId !== undefined && { resumeAgentId: args.resumeAgentId }),\n ...(args.mode !== undefined && { mode: args.mode }),\n });\n state.agent = agent;\n send({\n kind: 'init_ok',\n sessionId: agent.agentId,\n tools: [],\n model: args.modelId,\n mcpStatus: buildMcpStatusSnapshot(mcpServers),\n });\n } catch (err) {\n await sendInitErrorFromAgentCreateFailure({\n apiKey: args.apiKey,\n modelId: args.modelId,\n err,\n });\n }\n}\n\n/**\n * Warm-pool reinit (C9). The runner was kept alive after its prior task\n * closed; the daemon is now claiming it for a NEW task. We cancel any active\n * run, dispose the prior Agent, update state, and create a fresh Agent on the\n * SAME warm process — so its `localExecutorCache` is reused (cache HIT on the\n * next send) because the harness entry uses the stable `harnessRunnerId`.\n *\n * FAIL CLOSED: on ANY throw we emit `reinit_error` and do NOT exit. The daemon\n * kills + respawns a fresh cold runner, so a broken warm process can never\n * serve the task — worst case is \"no speedup,\" never breakage or a cross-task\n * leak.\n */\nasync function handleReinit(args: {\n taskId: string;\n modelId: string;\n mcpServers: Record<string, unknown>;\n harnessRunnerId: string;\n harnessToken: string;\n skillsDir: string;\n generation: number;\n resumeAgentId?: string;\n fastMode: boolean;\n fastModeParam: { id: string; value: string } | null;\n agents?: RunnerAgents;\n mode?: 'agent' | 'plan';\n}): Promise<void> {\n try {\n /** Cancel any straggler run from the prior task before swapping Agents. */\n if (state.currentRun) {\n await state.currentRun.cancel().catch(() => {});\n state.currentRun = null;\n }\n /** Dispose the prior Agent; the warm executor cache stays in the process. */\n if (state.agent) {\n await state.agent[Symbol.asyncDispose]().catch(() => {});\n state.agent = null;\n }\n state.currentGeneration = args.generation;\n state.taskId = args.taskId;\n state.modelId = args.modelId;\n state.harnessToken = args.harnessToken;\n state.harnessRunnerId = args.harnessRunnerId;\n state.fastMode = args.fastMode;\n state.fastModeParam = args.fastModeParam;\n state.mode = args.mode;\n const mcpServers: Record<string, unknown> = {\n ...args.mcpServers,\n [HARNESS_SERVER_NAME]: buildHarnessServerEntry({\n harnessUrl: state.harnessUrl,\n harnessToken: args.harnessToken,\n harnessRunnerId: args.harnessRunnerId,\n taskId: args.taskId,\n }),\n };\n state.mcpServers = mcpServers;\n const agent = await acquireAgent({\n apiKey: state.apiKey,\n taskId: args.taskId,\n modelId: args.modelId,\n local: buildLocalOption(state.cwd, args.skillsDir),\n mcpServers,\n agentsOption: buildAgentsOption(args.agents),\n ...(args.resumeAgentId !== undefined && { resumeAgentId: args.resumeAgentId }),\n ...(args.mode !== undefined && { mode: args.mode }),\n });\n state.agent = agent;\n send({ kind: 'reinit_ok', sessionId: agent.agentId });\n } catch (err) {\n send({\n kind: 'reinit_error',\n error: err instanceof Error ? err.message : String(err),\n retryable: false,\n });\n }\n}\n\n/**\n * Parse a `turn-ended` update's `usage` block into `TurnUsage`, or null when\n * absent/invalid. As of @cursor/sdk 1.0.17 `turn-ended` is a first-class member\n * of the typed `InteractionUpdate` union with `usage?: { inputTokens,\n * outputTokens, cacheReadTokens, cacheWriteTokens }` (each a plain `z.number()`),\n * so we narrow via the discriminated `type` rather than widening to `unknown`.\n *\n * The integer/non-negative guard is a DOMAIN constraint, not structural: the\n * SDK schema's `z.number()` admits Infinity / fractional / negative, but our IPC\n * schema requires `int().nonnegative()`. A schema-invalid value would get the\n * whole `summary_completed` frame rejected at parse and wedge the compaction SM,\n * so we reject it here — preTokens is then omitted and the estimated-baseline\n * fallback applies. `Number.isInteger` also rejects NaN/Infinity/non-numbers.\n */\nfunction parseTurnEndedUsage(update: InteractionUpdate): TurnUsage | null {\n /*\n * `== null` (not `=== undefined`): the schema types `usage` as optional-not-null,\n * but this is a forked-child boundary parsing external SDK data — tolerate a\n * future `usage: null` rather than throwing on destructure and crashing the runner.\n */\n if (update.type !== 'turn-ended' || update.usage == null) return null;\n const { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens } = update.usage;\n if (\n Number.isInteger(inputTokens) &&\n inputTokens >= 0 &&\n Number.isInteger(outputTokens) &&\n outputTokens >= 0 &&\n Number.isInteger(cacheReadTokens) &&\n cacheReadTokens >= 0 &&\n Number.isInteger(cacheWriteTokens) &&\n cacheWriteTokens >= 0\n ) {\n return { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens };\n }\n return null;\n}\n\n/**\n * B2: translate a Cursor `onDelta` interaction-update into a runner→daemon IPC\n * signal. Cursor's native summarization emits `summary-started` /\n * `summary-completed` (both bare `{ type }` — no token counts), so the daemon\n * derives `compaction_completed.preTokens` from the last captured `turn-ended`\n * usage instead. Text/thinking/tool deltas are the public `Run.stream()` path's\n * responsibility and are ignored here. All update kinds below are members of the\n * typed `InteractionUpdate` union (@cursor/sdk 1.0.17), so each narrows by `type`.\n */\nfunction forwardSummaryUpdate(\n update: InteractionUpdate,\n generation: number,\n latestUsage: { ref: TurnUsage | null },\n tokenDeltaAccumulator: { count: number }\n): void {\n if (update.type === 'summary-started') {\n send({ kind: 'summary_started', generation });\n return;\n }\n if (update.type === 'summary-completed') {\n const raw = latestUsage.ref;\n /*\n * inputTokensRaw equivalent: input + cache reads + cache writes = total context fill,\n * the quantity the fill-bar renders. Absent when no turn-ended fired yet this turn.\n */\n const preTokens =\n raw !== null ? raw.inputTokens + raw.cacheReadTokens + raw.cacheWriteTokens : undefined;\n send({\n kind: 'summary_completed',\n generation,\n ...(preTokens !== undefined ? { preTokens } : {}),\n });\n return;\n }\n /**\n * `user-message-appended` fires once per `agent.send()` when the SDK has\n * durably written the user turn to its local SQLite checkpoint store. The\n * daemon logs the ack for durability triage; no state mutation needed yet.\n */\n if (update.type === 'user-message-appended') {\n send({ kind: 'user_message_persisted', generation, sessionId: update.userMessage.session_id });\n return;\n }\n /**\n * `token-delta` carries the SDK's running token count during streaming.\n * Accumulated as a SECOND signal — NOT a replacement for `turn-ended.usage`,\n * which carries the input/output/cache breakdown needed for pricing.\n */\n if (update.type === 'token-delta') {\n tokenDeltaAccumulator.count += update.tokens;\n return;\n }\n const usage = parseTurnEndedUsage(update);\n if (usage !== null) {\n latestUsage.ref = usage;\n log('info', 'cursor_turn_usage_received', { generation, ...usage });\n }\n}\n\nasync function streamRun(\n run: Run,\n generation: number,\n latestUsage: { ref: TurnUsage | null },\n tokenDeltaAccumulator: { count: number }\n): Promise<void> {\n try {\n for await (const event of run.stream()) {\n /**\n * If the generation rolled forward (interrupt + new push), stop\n * forwarding events from the stale run. The daemon will already\n * be ignoring them, but stopping here saves IPC traffic.\n */\n if (state.currentGeneration !== generation) {\n log('info', 'runner_stream_aborted_stale_generation', {\n generation,\n currentGeneration: state.currentGeneration,\n });\n return;\n }\n const message: SDKMessage = event;\n send({ kind: 'sdk_message', generation, payload: message });\n }\n const result = await run.wait();\n /**\n * `Run.createdAt` (run.d.ts:42) is the authoritative SDK-side run-start\n * timestamp. The daemon currently synthesizes one from `Date.now()` at\n * the IPC boundary, which can drift by the IPC + cold-build latency\n * (sometimes seconds). Forwarding the SDK's value gives accurate\n * per-run timing for the cost/latency dashboard.\n */\n const createdAt = run.createdAt;\n send({\n kind: 'run_complete',\n generation,\n result,\n ...(latestUsage.ref !== null ? { usage: latestUsage.ref } : {}),\n ...(createdAt !== undefined ? { createdAt } : {}),\n ...(tokenDeltaAccumulator.count > 0 ? { tokenDeltaTotal: tokenDeltaAccumulator.count } : {}),\n });\n } catch (err) {\n const serialized = serializeCursorRunnerError(err);\n send({\n kind: 'run_error',\n generation,\n ...serialized,\n });\n } finally {\n if (state.currentRun === run) {\n state.currentRun = null;\n }\n }\n}\n\n/**\n * Upper bound on how long `agent.send()` may take to return a `Run`. The SDK\n * does not resolve `send()` until it has flipped the run from QUEUED to RUNNING,\n * which it gates on an un-abortable model-validation round-trip to api2.cursor.sh\n * (`resolveLocalModelSelection` runs BEFORE `markRunStarting`). If that round-trip\n * wedges (TLS up, no response) the run sits in QUEUED until undici's 300s\n * headersTimeout — a silent 5-minute stall. `SendOptions` exposes no `signal`/\n * timeout, so we race the call and surface a fast, retryable error instead.\n */\nconst SEND_START_TIMEOUT_MS = 30_000;\n\n/**\n * `agent.send()` bounded by SEND_START_TIMEOUT_MS. On timeout, rejects with a\n * retryable error (duck-typed `isRetryable` is read by serializeCursorRunnerError)\n * so the daemon surfaces \"send a message to retry\" rather than a 5-min hang.\n */\nasync function sendWithStartTimeout(\n agent: SDKAgent,\n message: string | SDKUserMessage,\n sendOptions: SendOptions\n): Promise<Run> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n agent.send(message, sendOptions),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(\n Object.assign(\n new Error(\n `Cursor did not start the run within ${SEND_START_TIMEOUT_MS / 1000}s (model validation / handshake stalled). Send a message to try again.`\n ),\n { name: 'CursorSendStartTimeout', isRetryable: true }\n )\n );\n }, SEND_START_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\nasync function handlePushMessage(args: {\n generation: number;\n content: unknown[];\n skillBodies?: CursorResolvedSkillBody[];\n forceLocalRun: boolean;\n}): Promise<void> {\n /**\n * A push_message can arrive while Agent.create is still in flight: the daemon\n * sends `init` then the first turn back-to-back, and the runner's IPC dispatch\n * is NOT serialized (process.on('message') fires `void dispatch(...)` per\n * message). Without this wait, the first turn hits the guard below before\n * `Agent.create` resolves and fails with \"cursor agent not initialized.\"\n * `initSettled` resolves when init/reinit finishes (success or a sent\n * init_error — it never rejects; the catch is belt-and-suspenders).\n */\n if (!state.agent && state.initSettled) {\n await state.initSettled.catch(() => undefined);\n }\n const agent = state.agent;\n if (!agent) {\n send({\n kind: 'run_error',\n generation: args.generation,\n error: 'cursor agent not initialized',\n errorName: 'ConfigurationError',\n isRetryable: false,\n });\n return;\n }\n state.currentGeneration = args.generation;\n /*\n * New turn: clear the heartbeat throttle so the first streamed delta of this\n * turn forwards a stream_activity immediately instead of being coalesced\n * against the previous turn's last heartbeat.\n */\n lastStreamActivitySentAt = 0;\n /**\n * `args.content` arrives as `unknown[]` over IPC (the wire schema uses\n * `z.array(z.unknown())` for forward-compat — see comment in\n * cursor-runner-protocol.ts). Validate at the boundary via Zod rather\n * than cast: lint:extra forbids type assertions outside `as const`/`as never`,\n * and Zod gives us a runtime guarantee that matches the type.\n */\n const parsedContent = ContentBlockSchema.array().safeParse(args.content);\n if (!parsedContent.success) {\n log('warn', 'runner_push_message_invalid_content', {\n errorCount: parsedContent.error.issues.length,\n firstIssue: parsedContent.error.issues[0],\n });\n return;\n }\n const userInput: CursorUserInput = buildCursorUserPrompt(\n parsedContent.data,\n (entry) => log(entry.event.includes('error') ? 'warn' : 'info', entry.event, entry),\n { skillBodies: args.skillBodies }\n );\n if (userInput.text === '' && userInput.images.length === 0) {\n log('warn', 'runner_push_message_empty_after_build');\n return;\n }\n if (userInput.images.length > 0) {\n log('info', 'runner_push_message_with_images', {\n count: userInput.images.length,\n totalBytes: userInput.images.reduce((acc, img) => {\n const data = 'data' in img ? img.data : '';\n return acc + Math.floor((data.length * 3) / 4);\n }, 0),\n });\n }\n try {\n const message: string | SDKUserMessage =\n userInput.images.length > 0\n ? { text: userInput.text, images: userInput.images }\n : userInput.text;\n /**\n * Two send-option layers combine here:\n *\n * B2 — subscribe to the interaction-update stream so Cursor's native\n * server-managed summarization surfaces as `summary_started` /\n * `summary_completed` IPC messages. These updates flow ONLY through\n * `onDelta` — the public `Run.stream()` `SDKMessage` union has no summary\n * variant (verified against @cursor/sdk@1.0.13). Without this the daemon's\n * estimated context fill-bar never resets after Cursor compacts. `onDelta`\n * is unconditional.\n *\n * Fast Mode — attaches `SendOptions.model.params = [{id, value}]`, but only\n * when both knobs line up (the runner must NOT send an empty `params: []`).\n * Busy recovery may also attach `local.force`, but only when the daemon has\n * generation-guarded the retry.\n */\n /**\n * Mutable ref shared between the `onDelta` closure and `streamRun` so\n * the latest `turn-ended` usage can be forwarded on `run_complete`\n * without a module-level variable (each push_message gets its own ref,\n * avoiding any cross-turn contamination).\n */\n const latestUsage: { ref: TurnUsage | null } = { ref: null };\n const tokenDeltaAccumulator = { count: 0 };\n /**\n * `idempotencyKey` prevents the SDK from creating a duplicate run if the\n * runner crashes mid-`agent.send()` and we re-attempt with the same\n * generation after `Agent.resume()`. `${taskId}-${generation}` is unique\n * per turn (generation is bumped every turn or interrupt), so a clean\n * retry under the same key collapses server-side. Without this, an\n * Agent.resume-then-resend window can produce a duplicate run that the\n * SDK queues behind the original and we see two responses for one turn.\n */\n const sendOptions: SendOptions = {\n idempotencyKey: `${state.taskId}-${args.generation}`,\n /**\n * Per-RUN MCP set (live visibility). `@cursor/sdk@1.0.17` resolves\n * `opts.mcpServers ?? this.options.mcpServers` per send and forwards it to\n * the local `RunExecutor` as `mcpServersOverride`, so the set applied on\n * THIS turn reflects the latest `set_mcp_servers` IPC. Boundary cast: same\n * `McpServerConfig`-union reason as `Agent.create({ mcpServers: ... })`.\n */\n // eslint-disable-next-line no-restricted-syntax -- McpServerConfig union types require boundary cast\n mcpServers: state.mcpServers as never,\n onDelta: ({ update }) => {\n /*\n * Any interaction update means the run is producing output mid-step, so\n * feed the stall watchdog — it must measure true silence, not the\n * cadence of completed steps.\n */\n maybeSendStreamActivity(args.generation);\n forwardSummaryUpdate(update, args.generation, latestUsage, tokenDeltaAccumulator);\n },\n onStep: () => {\n /*\n * Guard against a stale generation completing after the daemon\n * incremented #generation for a new run (same pattern as streamRun's\n * stale-gen guard).\n */\n if (state.currentGeneration !== args.generation) return;\n send({ kind: 'step_progress', generation: args.generation });\n },\n ...(state.fastMode && state.fastModeParam !== null\n ? { model: { id: state.modelId, params: [state.fastModeParam] } }\n : {}),\n ...(args.forceLocalRun ? { local: { force: true } } : {}),\n };\n const run = await sendWithStartTimeout(agent, message, sendOptions);\n state.currentRun = run;\n await streamRun(run, args.generation, latestUsage, tokenDeltaAccumulator);\n } catch (err) {\n const serialized = serializeCursorRunnerError(err);\n send({\n kind: 'run_error',\n generation: args.generation,\n ...serialized,\n });\n }\n}\n\nasync function handleInterrupt(generation: number): Promise<void> {\n if (!state.currentRun) {\n log('info', 'runner_interrupt_no_active_run', { generation });\n return;\n }\n try {\n await state.currentRun.cancel();\n } catch (err) {\n log('warn', 'runner_interrupt_failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n\nasync function handleClose(): Promise<void> {\n try {\n if (state.currentRun) {\n await state.currentRun.cancel();\n }\n } catch {\n /**\n * Closing — already on the exit path, swallow.\n */\n }\n try {\n if (state.agent) {\n await state.agent[Symbol.asyncDispose]();\n }\n } catch {\n /** swallow — same reason */\n }\n state.agent = null;\n state.currentRun = null;\n /**\n * Pool-managed runner: keep the process (and its warm `localExecutorCache`)\n * alive. Reset to a quiescent state and ack `pooled_idle` so the daemon can\n * reuse us for the next matching task via `reinit`. The Agent is disposed\n * above; only the heavyweight executor cache survives.\n */\n if (state.pooled) {\n state.taskId = '';\n state.fastMode = false;\n state.fastModeParam = null;\n state.mode = undefined;\n send({ kind: 'pooled_idle' });\n return;\n }\n process.exit(0);\n}\n\n/**\n * Translate an `init` IPC message into `handleInit` args. Pure — extracted from\n * `dispatch` so the conditional-spread branches for optional fields don't load\n * the switch's cognitive complexity past budget.\n */\nfunction buildHandleInitArgs(\n msg: Extract<DaemonToRunner, { kind: 'init' }>\n): Parameters<typeof handleInit>[0] {\n return {\n taskId: msg.taskId,\n cwd: msg.cwd,\n apiKey: msg.apiKey,\n modelId: msg.modelId,\n mcpServers: msg.mcpServers,\n harnessUrl: msg.harnessUrl,\n harnessToken: msg.harnessToken,\n harnessRunnerId: msg.harnessRunnerId ?? '',\n pooled: msg.pooled ?? false,\n skillsDir: msg.skillsDir,\n generation: msg.generation,\n ...(msg.injectedAgentId !== undefined && { injectedAgentId: msg.injectedAgentId }),\n ...(msg.resumeAgentId !== undefined && { resumeAgentId: msg.resumeAgentId }),\n fastMode: msg.fastMode ?? false,\n fastModeParam: msg.fastModeParam ?? null,\n ...(msg.agents !== undefined && { agents: msg.agents }),\n ...(msg.mode !== undefined && { mode: msg.mode }),\n };\n}\n\n/**\n * Translate a `reinit` IPC message into `handleReinit` args. Pure — extracted\n * from `dispatch` for the same reason as `buildHandleInitArgs`: the\n * conditional-spread branches for optional fields would otherwise load the\n * switch's cognitive complexity past budget.\n */\nfunction buildHandleReinitArgs(\n msg: Extract<DaemonToRunner, { kind: 'reinit' }>\n): Parameters<typeof handleReinit>[0] {\n return {\n taskId: msg.taskId,\n modelId: msg.modelId,\n mcpServers: msg.mcpServers,\n harnessRunnerId: msg.harnessRunnerId,\n harnessToken: msg.harnessToken,\n skillsDir: msg.skillsDir,\n generation: msg.generation,\n ...(msg.resumeAgentId !== undefined && { resumeAgentId: msg.resumeAgentId }),\n fastMode: msg.fastMode ?? false,\n fastModeParam: msg.fastModeParam ?? null,\n ...(msg.agents !== undefined && { agents: msg.agents }),\n ...(msg.mode !== undefined && { mode: msg.mode }),\n };\n}\n\nasync function dispatch(raw: unknown): Promise<void> {\n const msg = parseDaemonToRunner(raw);\n if (msg === null) {\n log('warn', 'runner_invalid_ipc_message', { raw });\n return;\n }\n switch (msg.kind) {\n case 'init':\n state.initSettled = handleInit(buildHandleInitArgs(msg));\n return;\n case 'reinit':\n state.initSettled = handleReinit(buildHandleReinitArgs(msg));\n return;\n case 'set_pooled':\n /**\n * Flip the pooled flag so the next `close` keeps (pooled=true) or exits\n * (pooled=false) the process. Per-state, not per-turn.\n */\n state.currentGeneration = msg.generation;\n state.pooled = msg.pooled;\n log('info', 'runner_set_pooled_recorded', { pooled: msg.pooled });\n return;\n case 'push_message':\n await handlePushMessage({\n generation: msg.generation,\n content: msg.content,\n skillBodies: msg.skillBodies,\n forceLocalRun: msg.forceLocalRun ?? false,\n });\n return;\n case 'interrupt':\n await handleInterrupt(msg.generation);\n return;\n case 'set_model':\n /**\n * `@cursor/sdk` accepts `model` via `SendOptions` on each\n * `send()` call; there is no `agent.setModel()`. The runner\n * stores the new id and applies it on the next push. (Wired\n * in S2b — for S2a we just acknowledge.)\n */\n state.currentGeneration = msg.generation;\n log('info', 'runner_set_model_recorded', { modelId: msg.modelId });\n return;\n case 'set_mcp_servers':\n /**\n * Live per-send MCP visibility. `@cursor/sdk@1.0.17` has no\n * `agent.setMcpServers` — the MCP set is a per-RUN parameter applied via\n * `SendOptions.mcpServers` on every `agent.send()`. So we store the new\n * set (re-composing the harness MCP entry, which the daemon's\n * `resolveServersForTask` payload omits) and the NEXT `push_message`\n * carries it. No agent recreate, no restart banner — the Cursor\n * subprocess no longer raises `mcp_mid_thread_reload_needed`.\n */\n state.currentGeneration = msg.generation;\n state.mcpServers = {\n ...msg.servers,\n [HARNESS_SERVER_NAME]: buildHarnessServerEntry({\n harnessUrl: state.harnessUrl,\n harnessToken: state.harnessToken,\n harnessRunnerId: state.harnessRunnerId,\n taskId: state.taskId,\n }),\n };\n log('info', 'runner_set_mcp_servers_applied_live', {\n count: Object.keys(state.mcpServers).length,\n });\n return;\n case 'set_harness_task_id':\n state.taskId = msg.taskId;\n state.harnessToken = msg.token;\n state.currentGeneration = msg.generation;\n log('info', 'runner_harness_task_id_recorded', { taskId: msg.taskId });\n return;\n case 'set_permission_mode':\n /**\n * R1 plan mode: the daemon rewrote the mode file and hooks.json before\n * sending this. The runner records the generation and logs for triage.\n * No action needed — the next hook invocation reads the new mode file.\n */\n state.currentGeneration = msg.generation;\n log('info', 'runner_set_permission_mode_recorded', { mode: msg.mode });\n return;\n case 'set_fast_mode':\n /**\n * Fast Mode is per-state, not per-turn — record the new flag without\n * bumping the generation. The next `push_message` will read\n * `state.fastMode` when building `SendOptions`.\n */\n state.currentGeneration = msg.generation;\n state.fastMode = msg.fastMode;\n log('info', 'runner_set_fast_mode_recorded', { fastMode: msg.fastMode });\n return;\n case 'close':\n await handleClose();\n return;\n default: {\n /**\n * Compile-time exhaustiveness — adding a new variant to the\n * protocol forces this switch to be updated.\n */\n const _exhaustive: never = msg;\n log('error', 'runner_unhandled_message_kind', {\n msg: _exhaustive,\n });\n return;\n }\n }\n}\n\nprocess.on('message', (raw) => {\n /**\n * `dispatch` is async but the IPC handler is sync. Swallow any\n * promise rejection that escapes dispatch's own try/catch — those\n * are programmer errors, and crashing the runner over them just\n * trades a logged warning for a process exit + supervisor respawn\n * cycle.\n */\n void dispatch(raw).catch((err: unknown) => {\n log('error', 'runner_dispatch_unhandled_rejection', {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n});\n\nprocess.on('disconnect', () => {\n /**\n * Parent went away (daemon crash, fork channel torn down). Exit\n * with a non-zero code so the supervisor records the abnormal\n * termination.\n */\n process.exit(1);\n});\n\n/**\n * Crash-on-uncaught: any uncaught error or unhandled rejection in\n * native code (sqlite, FFI) or SDK internals SHOULD bring this child\n * down — the daemon-side supervisor records the exit and the session\n * FSM tears down. Silent recovery here would mask real bugs.\n */\nprocess.on('uncaughtException', (err) => {\n process.stderr.write(\n `${JSON.stringify({\n level: 'error',\n event: 'runner_uncaught_exception',\n error: err.message,\n stack: err.stack,\n })}\\n`\n );\n process.exit(2);\n});\n\nprocess.on('unhandledRejection', (reason) => {\n process.stderr.write(\n `${JSON.stringify({\n level: 'error',\n event: 'runner_unhandled_rejection',\n reason: reason instanceof Error ? reason.message : String(reason),\n })}\\n`\n );\n process.exit(3);\n});\n","import { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join } from 'node:path';\n\nexport interface CursorRipgrepDeps {\n env?: NodeJS.ProcessEnv;\n resolve?: (id: string) => string;\n exists?: (path: string) => boolean;\n platform?: NodeJS.Platform;\n arch?: string;\n}\n\nexport type CursorRipgrepConfigureResult =\n | { status: 'already-configured'; path: string }\n | { status: 'configured'; path: string }\n | { status: 'missing'; path: null }\n | { status: 'resolve-error'; path: null; error: unknown };\n\n/**\n * Point @cursor/sdk at the ripgrep binary bundled in its platform package.\n * The SDK currently has no public configureRipgrepPath export, so this is the\n * narrow chokepoint for the documented env override it already honors.\n */\nexport function configureCursorRipgrepPath(\n deps: CursorRipgrepDeps = {}\n): CursorRipgrepConfigureResult {\n const env = deps.env ?? process.env;\n if (env.CURSOR_RIPGREP_PATH) {\n return { status: 'already-configured', path: env.CURSOR_RIPGREP_PATH };\n }\n\n try {\n const rg = resolveCursorBundledRipgrepPath(deps);\n if (rg === null) return { status: 'missing', path: null };\n env.CURSOR_RIPGREP_PATH = rg;\n return { status: 'configured', path: rg };\n } catch (error) {\n return { status: 'resolve-error', path: null, error };\n }\n}\n\nexport function resolveCursorBundledRipgrepPath(deps: CursorRipgrepDeps = {}): string | null {\n const resolve = deps.resolve ?? createRequire(import.meta.url).resolve;\n const exists = deps.exists ?? existsSync;\n const platform = deps.platform ?? process.platform;\n const arch = deps.arch ?? process.arch;\n\n const sdkMain = resolve('@cursor/sdk');\n let sdkRoot = dirname(sdkMain);\n while (sdkRoot !== dirname(sdkRoot) && basename(sdkRoot) !== 'sdk') {\n sdkRoot = dirname(sdkRoot);\n }\n if (basename(sdkRoot) !== 'sdk') return null;\n\n const bin = platform === 'win32' ? 'rg.exe' : 'rg';\n const rg = join(sdkRoot, '..', `sdk-${platform}-${arch}`, 'bin', bin);\n return exists(rg) ? rg : null;\n}\n","/**\n * Pure helper that formats a structured `init_error` message for the daemon\n * when `Agent.create()` rejects.\n *\n * The Cursor SDK delegates model-id resolution to the backend, so an unknown\n * `composer-X.Y` id surfaces as an opaque `ModelNotFound` (or similar)\n * server error. Shipyard's catalog (`cursor-model-catalog.ts`) hardcodes\n * `composer-2.5` based on Cursor's docs; if Cursor renames the model\n * server-side, every spawn fails and our only signal is the opaque SDK\n * message. We've shipped 5 Cursor fixes without ever exercising the literal\n * model string — see PR history in #3680, #3744, #3752, #3758, #3787.\n *\n * On failure, the runner calls `Cursor.models.list()` once and feeds the\n * result through this formatter. The resulting `init_error.error` string\n * names the requested id, the original SDK error, and the available ids +\n * aliases — enough to identify a model-id mismatch from the daemon log\n * alone, without re-running with extra debug flags.\n *\n * Pure function: no I/O, no side effects, exhaustively unit-testable.\n * Lives alongside the runner per the FC/IS pattern in `engineering-standards.md`.\n */\n\nexport interface ModelInfo {\n id: string;\n aliases?: readonly string[];\n}\n\nexport interface CursorInitErrorInput {\n /** The model id Shipyard sent to `Agent.create()`. */\n requestedModelId: string;\n /** The SDK's original failure message (preserved verbatim at the end). */\n originalError: string;\n /**\n * Result of `Cursor.models.list()`. `null` means the list call itself\n * failed (offline, auth invalid, rate-limited) — formatter falls back\n * to the original error without speculating about available models.\n */\n availableModels: readonly ModelInfo[] | null;\n /** Optional: the error string from the failed list call, for triage. */\n listError?: string;\n}\n\nexport function formatCursorInitError(input: CursorInitErrorInput): string {\n const { requestedModelId, originalError, availableModels, listError } = input;\n if (availableModels === null) {\n const listPart = listError\n ? ` (Cursor.models.list() also failed: ${listError})`\n : ' (Cursor.models.list() unavailable)';\n return `Agent.create failed for model '${requestedModelId}'. ${originalError}${listPart}`;\n }\n if (availableModels.length === 0) {\n return `Agent.create failed for model '${requestedModelId}'. Cursor.models.list() returned no models. ${originalError}`;\n }\n const requested = requestedModelId.toLowerCase();\n const exactMatch = availableModels.find(\n (m) =>\n m.id.toLowerCase() === requested ||\n (m.aliases ?? []).some((a) => a.toLowerCase() === requested)\n );\n const idsList = availableModels.map((m) => m.id).join(', ');\n const aliasParts = availableModels\n .filter((m) => (m.aliases?.length ?? 0) > 0)\n .map((m) => `${m.id}=[${(m.aliases ?? []).join('|')}]`);\n const aliasesList = aliasParts.length > 0 ? aliasParts.join(', ') : '(none)';\n const matchPart = exactMatch\n ? ` The id IS in the available set (${exactMatch.id}) — failure is unrelated to model resolution.`\n : ` The id is NOT in the available set — likely renamed or deprecated server-side.`;\n return `Agent.create failed for model '${requestedModelId}'.${matchPart} Available ids: ${idsList}. Aliases: ${aliasesList}. Original: ${originalError}`;\n}\n","/**\n * Serialize thrown values from `@cursor/sdk` into the wire shape the daemon\n * expects on `run_error` / `init_error` IPC messages.\n *\n * Pure FC/IS helper — no I/O. Duck-types SDK error fields because errors\n * arrive as live class instances inside the runner process.\n */\n\nexport interface CursorRunnerErrorWire {\n error: string;\n errorName?: string;\n errorCode?: string;\n statusCode?: number;\n isRetryable: boolean;\n}\n\nfunction readStringField(rec: Record<string, unknown>, key: string): string | undefined {\n const value = rec[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction readNumberField(rec: Record<string, unknown>, key: string): number | undefined {\n const value = rec[key];\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readBooleanField(rec: Record<string, unknown>, key: string): boolean | undefined {\n const value = rec[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\n/**\n * Extract message, SDK error `name`, `code`, `status`, and `isRetryable`\n * from a thrown value for IPC transport to the daemon-side classifier.\n */\nexport function serializeCursorRunnerError(err: unknown): CursorRunnerErrorWire {\n if (typeof err === 'object' && err !== null) {\n // eslint-disable-next-line no-restricted-syntax -- unknown thrown value narrowed by typeof; Record probe for duck-typed SDK errors\n const rec = err as Record<string, unknown>;\n const message =\n typeof rec.message === 'string' && rec.message.length > 0 ? rec.message : String(err);\n const wire: CursorRunnerErrorWire = {\n error: message,\n isRetryable: readBooleanField(rec, 'isRetryable') ?? false,\n };\n const errorName = readStringField(rec, 'name');\n const errorCode = readStringField(rec, 'code');\n const statusCode = readNumberField(rec, 'status');\n if (errorName !== undefined) wire.errorName = errorName;\n if (errorCode !== undefined) wire.errorCode = errorCode;\n if (statusCode !== undefined) wire.statusCode = statusCode;\n return wire;\n }\n return { error: String(err), isRetryable: false };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/services/session/cursor-runner.ts","../src/shared/capabilities/runtime/cursor-ripgrep.ts","../src/services/session/cursor-init-error-formatter.ts","../src/services/session/cursor-runner-error.ts","../src/services/session/cursor-tool-execution-edge.ts"],"sourcesContent":["/**\n * cursor-runner — forked Node child that owns the `@cursor/sdk` lifecycle\n * outside the daemon's V8 isolate (plan v2 §2).\n *\n * The daemon spawns this entry via `child_process.fork(require.resolve(\n * './cursor-runner.js'))` once per Cursor task. The child:\n * 1. waits for an `init` IPC message,\n * 2. calls `Agent.create()` from `@cursor/sdk`,\n * 3. on each `push_message`, calls `agent.send()` and iterates\n * `Run.stream()`, forwarding every `SDKMessage` back to the daemon,\n * 4. on `interrupt`, cancels the in-flight run,\n * 5. on `close`, disposes the agent and exits 0.\n *\n * Native panics (sqlite, FFI) crash THIS child only. The daemon-side\n * supervisor (S2b) observes the child exit, emits `subprocess_died`, and\n * the session FSM tears down cleanly.\n *\n * Per-tool gating uses the `.cursor/hooks.json` `preToolUse` hook script +\n * cursor-hook-socket (cursor-hook-socket.ts) — @cursor/sdk@1.0.13 has no\n * public respond-to-request API.\n */\n\nimport {\n Agent,\n type InteractionUpdate,\n type Run,\n type SDKAgent,\n type SDKMessage,\n type SDKUserMessage,\n type SendOptions,\n type SettingSource,\n} from '@cursor/sdk';\nimport { ContentBlockSchema, HARNESS_SERVER_NAME } from '@shipyard/loro-schema';\n\nimport { configureCursorRipgrepPath } from '../../shared/capabilities/runtime/cursor-ripgrep.js';\nimport {\n buildCursorUserPrompt,\n type CursorResolvedSkillBody,\n type CursorUserInput,\n} from './cursor-content-builder.js';\nimport { sendInitErrorFromAgentCreateFailure } from './cursor-init-error-formatter.js';\nimport { serializeCursorRunnerError } from './cursor-runner-error.js';\nimport {\n type DaemonToRunner,\n parseDaemonToRunner,\n type RunnerToDaemon,\n} from './cursor-runner-protocol.js';\nimport { decideToolExecutionEdge } from './cursor-tool-execution-edge.js';\n\nconfigureCursorRipgrepPath();\n\n/**\n * Real token usage from a `turn-ended` interaction update. Captured during\n * `onDelta` and forwarded on `run_complete` so the daemon can map real counts\n * onto the `TurnResult` instead of marking everything as estimated.\n */\ninterface TurnUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheWriteTokens: number;\n}\n\n/** Named subagent catalog shape as it arrives over IPC (mirrors the protocol). */\ntype RunnerAgents = Record<\n string,\n {\n description: string;\n prompt: string;\n model?: { id: string } | 'inherit';\n mcpServers?: string[];\n }\n>;\n\ninterface RunnerState {\n agent: SDKAgent | null;\n currentRun: Run | null;\n currentGeneration: number;\n taskId: string;\n harnessToken: string;\n /**\n * Stable per-runner identity for the runner-scoped harness path. When set,\n * the harness MCP entry uses `x-shipyard-runner-id: harnessRunnerId` instead\n * of `x-shipyard-task-id: taskId`, keeping the `mcpServers` map (and thus the\n * SDK executor cache key) byte-identical across task switches. Empty string\n * = legacy per-task harness path.\n */\n harnessRunnerId: string;\n /** Harness MCP server URL, retained so reinit can rebuild the entry. */\n harnessUrl: string;\n /** Workspace cwd, retained so reinit can rebuild `local.cwd`. */\n cwd: string;\n /** Cursor API key, retained so reinit can recreate the Agent. */\n apiKey: string;\n /**\n * Pool-managed flag. When true, `close` disposes the Agent but does NOT\n * `process.exit(0)` — the runner acks `pooled_idle` and the daemon keeps the\n * warm process alive for the next claim.\n */\n pooled: boolean;\n /**\n * Cursor model id supplied at init. Threaded into every\n * `SendOptions.model.id` when Fast Mode is on so the runtime knows which\n * model the params belong to.\n */\n modelId: string;\n /**\n * Live Fast Mode flag. Initial value from `init`; updated by\n * `set_fast_mode` IPC. The runner attaches Fast Mode params only when\n * both this is true AND `fastModeParam` is non-null.\n */\n fastMode: boolean;\n /**\n * Resolved Fast Mode `{id, value}` binding for `modelId`, sourced from\n * the daemon's discovery cache. Null = no binding known; the runner\n * sends the plain `agent.send(message)` shape regardless of `fastMode`.\n */\n fastModeParam: { id: string; value: string } | null;\n /**\n * Live MCP server set, seeded at init/reinit and updated by `set_mcp_servers`\n * IPC. `@cursor/sdk@1.0.17` takes the MCP set as a per-RUN parameter\n * (`SendOptions.mcpServers`, applied via the local `RunExecutor`'s\n * `mcpServersOverride` on every `agent.send()`); there is NO\n * `agent.setMcpServers`. So we store the current set here and thread it into\n * each send — visibility changes apply live on the next turn, no restart. The\n * harness MCP entry is composed into this at init/reinit and preserved on\n * every `set_mcp_servers` update.\n */\n mcpServers: Record<string, unknown>;\n /**\n * In-flight `handleInit`/`handleReinit` promise — resolves when init has\n * settled (agent created, or init_error/reinit_error sent; never rejects).\n * `handlePushMessage` awaits it so a `push_message` that races ahead of\n * `Agent.create` waits for the agent instead of erroring \"not initialized.\"\n */\n initSettled: Promise<void> | null;\n /**\n * Native Cursor SDK conversation mode. Sourced from the `init` IPC; persists\n * for the agent's lifetime. `'plan'` tells composer-2.5 to use its built-in\n * `createPlan` tool instead of writing files (soft signal — hooks.json is the\n * hard enforcement layer). `undefined` = SDK default (`'agent'` mode).\n */\n mode?: 'agent' | 'plan';\n}\n\nconst state: RunnerState = {\n agent: null,\n currentRun: null,\n currentGeneration: 0,\n taskId: '',\n harnessToken: '',\n harnessRunnerId: '',\n harnessUrl: '',\n cwd: '',\n apiKey: '',\n pooled: false,\n modelId: '',\n fastMode: false,\n fastModeParam: null,\n mcpServers: {},\n initSettled: null,\n mode: undefined,\n};\n\nfunction send(msg: RunnerToDaemon): void {\n /**\n * `process.send` is only defined when this module is started via\n * `fork()` with an IPC channel. If it is undefined (e.g. the file is\n * accidentally executed directly), there is no way to reach the\n * parent — the runner is unusable; log to stderr and drop.\n */\n if (typeof process.send !== 'function') {\n process.stderr.write(\n `${JSON.stringify({ level: 'error', event: 'runner_no_ipc_channel', dropped: msg.kind })}\\n`\n );\n return;\n }\n process.send(msg);\n}\n\nfunction log(level: 'info' | 'warn' | 'error', message: string, data?: unknown): void {\n send({ kind: 'log', level, message, data });\n}\n\n/**\n * Runner-side throttle for `stream_activity` heartbeats. `onDelta` fires per\n * output chunk (text/thinking/shell-output deltas) — far too often to forward\n * each as IPC. Coalesce to at most one heartbeat per this interval. Kept well\n * below the daemon's stall window (180s) so the daemon reliably sees liveness\n * within it; the daemon applies its own coarser throttle on receipt.\n */\nconst STREAM_ACTIVITY_IPC_THROTTLE_MS = 2_000;\n/** Wall-clock of the last forwarded `stream_activity`. Reset per turn in `handlePushMessage`. */\nlet lastStreamActivitySentAt = 0;\n/**\n * Count of `tool-call-started` updates minus `tool-call-completed` updates for\n * the current turn. Used to emit `tool_execution` IPC edges only on the 0→1\n * (started) and 1→0 (settled) transitions — intermediate count changes produce\n * no IPC traffic. Reset at the start of every turn in `handlePushMessage`\n * and on pooled release (`handleClose`) so a stale count can never survive\n * into a different turn or task.\n */\nlet inFlightToolCount = 0;\n\n/**\n * Forward a throttled liveness heartbeat for the active generation. Called from\n * `onDelta` — ANY interaction update means the run is producing output, so the\n * daemon's stall watchdog should measure true silence rather than step cadence.\n * Drops stale-generation calls (the daemon would filter them anyway).\n */\nfunction maybeSendStreamActivity(generation: number): void {\n if (state.currentGeneration !== generation) return;\n const now = Date.now();\n if (now - lastStreamActivitySentAt < STREAM_ACTIVITY_IPC_THROTTLE_MS) return;\n lastStreamActivitySentAt = now;\n send({ kind: 'stream_activity', generation });\n}\n\n/**\n * Build the harness MCP entry. Uses the runner-scoped header\n * (`x-shipyard-runner-id`) when `harnessRunnerId` is set — that keeps the\n * entry byte-identical across the runner's whole life (init→reinit) so the\n * SDK executor cache key never changes on task switch. Falls back to the\n * legacy per-task header (`x-shipyard-task-id`) for non-pooled spawns.\n */\nfunction buildHarnessServerEntry(args: {\n harnessUrl: string;\n harnessToken: string;\n harnessRunnerId: string;\n taskId: string;\n}): {\n type: 'http';\n url: string;\n headers: Record<string, string>;\n} {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${args.harnessToken}`,\n };\n if (args.harnessRunnerId.length > 0) {\n headers['x-shipyard-runner-id'] = args.harnessRunnerId;\n } else {\n headers['x-shipyard-task-id'] = args.taskId;\n }\n return {\n type: 'http',\n url: args.harnessUrl,\n headers,\n };\n}\n\n/**\n * Compose the SDK `local` option. `settingSources: ['user', 'project']` is\n * parity with Claude/Codex — those runtimes auto-discover the user's installed\n * skills and the repo's project-level rules; leaving settingSources at the\n * default (`[]`) silently disabled Cursor's equivalent. User-authored markdown\n * on the user's own machine; same trust posture as the other agents.\n * Cross-runtime *portability* of those skills is tracked separately in #3955.\n *\n * `cwd: [cwd, skillsDir]` — `cwd[0]` is the repo workspace; `skillsDir` (cwd[1])\n * is Shipyard's task-scoped `~/.shipyard/cursor-skills/{taskId}` dir, which hosts\n * the permission-hook substrate (`.cursor/hooks.json` + hmac + allow). The SDK\n * resolves the WORKSPACE (rules/skills discovery) from `cwd[0]` ONLY\n * (`getExplicitLocalWorkspaceRef` → `n[0]`), so `cwd[1]` is NOT a prompt or\n * rules channel — the Shipyard prompt is delivered via the harness MCP server's\n * `initialize.instructions` instead. `cwd[1]` is retained because it is how the\n * SDK discovers the per-task hook substrate; dropping it would silently disable\n * Cursor permission gating.\n */\nfunction buildLocalOption(\n cwd: string,\n skillsDir: string\n): {\n cwd: string | string[];\n settingSources: SettingSource[];\n} {\n const settingSources: SettingSource[] = ['user', 'project'];\n return {\n ...(skillsDir ? { cwd: [cwd, skillsDir] } : { cwd }),\n settingSources,\n };\n}\n\n/**\n * Named subagent catalog as an SDK option. Omitted when the catalog is empty —\n * passing `agents: {}` would register an empty map and override any agents the\n * SDK might discover itself.\n */\nfunction buildAgentsOption(agents: RunnerAgents | undefined): Record<string, never> {\n return agents !== undefined && Object.keys(agents).length > 0\n ? // eslint-disable-next-line no-restricted-syntax -- AgentDefinition union (model field) requires boundary cast\n { agents: agents as never }\n : {};\n}\n\n/**\n * Acquire the Agent for a task. Priority order:\n * 1. `injectedAgentId` — cross-runtime structured handoff (Wave 7.5). The\n * daemon pre-wrote a fabricated conversation to SQLite; we MUST resume\n * that id or the conversation never surfaces. A same-id `Agent.create()`\n * would PRIMARY-KEY-conflict on the agents row.\n * 2. `resumeAgentId` — persisted from a prior `init_ok`. SDK reads the prior\n * conversation from its SQLite checkpoint store. If the store entry is\n * gone (user wiped ~/.cursor/, etc.) the resume throws; we catch and fall\n * through to `Agent.create` so the spawn succeeds without prior context.\n * 3. `Agent.create` — fresh agent. Default path for never-spawned tasks.\n *\n * Conversation history not preserved on path 3 is acceptable — Shipyard's\n * JSONL is the authoritative log; the SDK's checkpoint store is a latency /\n * context win, not the source of truth.\n */\nasync function acquireAgent(args: {\n apiKey: string;\n taskId: string;\n modelId: string;\n local: ReturnType<typeof buildLocalOption>;\n mcpServers: Record<string, unknown>;\n agentsOption: Record<string, never>;\n injectedAgentId?: string;\n resumeAgentId?: string;\n mode?: 'agent' | 'plan';\n}): Promise<SDKAgent> {\n const baseOptions = {\n apiKey: args.apiKey,\n model: { id: args.modelId },\n local: args.local,\n // eslint-disable-next-line no-restricted-syntax -- McpServerConfig union types require boundary cast\n mcpServers: args.mcpServers as never,\n ...args.agentsOption,\n ...(args.mode !== undefined ? { mode: args.mode } : {}),\n };\n async function createFreshAgent(): Promise<SDKAgent> {\n return Agent.create({ ...baseOptions, name: `shipyard-task-${args.taskId}` });\n }\n if (args.injectedAgentId !== undefined) {\n return Agent.resume(args.injectedAgentId, baseOptions);\n }\n if (args.resumeAgentId !== undefined) {\n try {\n const resumed = await Agent.resume(args.resumeAgentId, baseOptions);\n log('info', 'runner_resume_agent_succeeded', { agentId: args.resumeAgentId });\n return resumed;\n } catch (resumeErr) {\n log('warn', 'runner_resume_agent_failed_falling_back_to_create', {\n agentId: args.resumeAgentId,\n error: resumeErr instanceof Error ? resumeErr.message : String(resumeErr),\n });\n return createFreshAgent();\n }\n }\n return createFreshAgent();\n}\n\n/** Snapshot MCP status for init/reinit ok messages (Cursor has no live stream). */\nfunction buildMcpStatusSnapshot(mcpServers: Record<string, unknown>): Array<{\n name: string;\n status: string;\n}> {\n return Object.keys(mcpServers).map((name) => ({\n name,\n /**\n * Cursor local runtime does not expose a stable MCP-status stream during\n * init. Emit a non-empty snapshot so daemon-side init metadata never\n * races with an empty MCP list.\n */\n status: 'connected',\n }));\n}\n\nasync function handleInit(args: {\n taskId: string;\n cwd: string;\n apiKey: string;\n modelId: string;\n mcpServers: Record<string, unknown>;\n harnessUrl: string;\n harnessToken: string;\n harnessRunnerId: string;\n pooled: boolean;\n skillsDir: string;\n generation: number;\n injectedAgentId?: string;\n resumeAgentId?: string;\n fastMode: boolean;\n fastModeParam: { id: string; value: string } | null;\n agents?: RunnerAgents;\n mode?: 'agent' | 'plan';\n}): Promise<void> {\n state.currentGeneration = args.generation;\n state.taskId = args.taskId;\n state.harnessToken = args.harnessToken;\n state.harnessRunnerId = args.harnessRunnerId;\n state.harnessUrl = args.harnessUrl;\n state.cwd = args.cwd;\n state.apiKey = args.apiKey;\n state.pooled = args.pooled;\n state.modelId = args.modelId;\n state.fastMode = args.fastMode;\n state.fastModeParam = args.fastModeParam;\n state.mode = args.mode;\n try {\n /**\n * The daemon validates `mcpServers` shape before sending. We pass\n * through as-is; a malformed entry will surface as an\n * `Agent.create()` rejection rather than a runner crash.\n */\n const mcpServers: Record<string, unknown> = {\n ...args.mcpServers,\n [HARNESS_SERVER_NAME]: buildHarnessServerEntry({\n harnessUrl: args.harnessUrl,\n harnessToken: args.harnessToken,\n harnessRunnerId: args.harnessRunnerId,\n taskId: args.taskId,\n }),\n };\n state.mcpServers = mcpServers;\n const agent = await acquireAgent({\n apiKey: args.apiKey,\n taskId: args.taskId,\n modelId: args.modelId,\n local: buildLocalOption(args.cwd, args.skillsDir),\n mcpServers,\n agentsOption: buildAgentsOption(args.agents),\n ...(args.injectedAgentId !== undefined && { injectedAgentId: args.injectedAgentId }),\n ...(args.resumeAgentId !== undefined && { resumeAgentId: args.resumeAgentId }),\n ...(args.mode !== undefined && { mode: args.mode }),\n });\n state.agent = agent;\n send({\n kind: 'init_ok',\n sessionId: agent.agentId,\n tools: [],\n model: args.modelId,\n mcpStatus: buildMcpStatusSnapshot(mcpServers),\n });\n } catch (err) {\n await sendInitErrorFromAgentCreateFailure({\n apiKey: args.apiKey,\n modelId: args.modelId,\n err,\n send,\n });\n }\n}\n\n/**\n * Warm-pool reinit (C9). The runner was kept alive after its prior task\n * closed; the daemon is now claiming it for a NEW task. We cancel any active\n * run, dispose the prior Agent, update state, and create a fresh Agent on the\n * SAME warm process — so its `localExecutorCache` is reused (cache HIT on the\n * next send) because the harness entry uses the stable `harnessRunnerId`.\n *\n * FAIL CLOSED: on ANY throw we emit `reinit_error` and do NOT exit. The daemon\n * kills + respawns a fresh cold runner, so a broken warm process can never\n * serve the task — worst case is \"no speedup,\" never breakage or a cross-task\n * leak.\n */\nasync function handleReinit(args: {\n taskId: string;\n modelId: string;\n mcpServers: Record<string, unknown>;\n harnessRunnerId: string;\n harnessToken: string;\n skillsDir: string;\n generation: number;\n resumeAgentId?: string;\n fastMode: boolean;\n fastModeParam: { id: string; value: string } | null;\n agents?: RunnerAgents;\n mode?: 'agent' | 'plan';\n}): Promise<void> {\n try {\n /** Cancel any straggler run from the prior task before swapping Agents. */\n if (state.currentRun) {\n await state.currentRun.cancel().catch(() => {});\n state.currentRun = null;\n }\n /** Dispose the prior Agent; the warm executor cache stays in the process. */\n if (state.agent) {\n await state.agent[Symbol.asyncDispose]().catch(() => {});\n state.agent = null;\n }\n state.currentGeneration = args.generation;\n state.taskId = args.taskId;\n state.modelId = args.modelId;\n state.harnessToken = args.harnessToken;\n state.harnessRunnerId = args.harnessRunnerId;\n state.fastMode = args.fastMode;\n state.fastModeParam = args.fastModeParam;\n state.mode = args.mode;\n const mcpServers: Record<string, unknown> = {\n ...args.mcpServers,\n [HARNESS_SERVER_NAME]: buildHarnessServerEntry({\n harnessUrl: state.harnessUrl,\n harnessToken: args.harnessToken,\n harnessRunnerId: args.harnessRunnerId,\n taskId: args.taskId,\n }),\n };\n state.mcpServers = mcpServers;\n const agent = await acquireAgent({\n apiKey: state.apiKey,\n taskId: args.taskId,\n modelId: args.modelId,\n local: buildLocalOption(state.cwd, args.skillsDir),\n mcpServers,\n agentsOption: buildAgentsOption(args.agents),\n ...(args.resumeAgentId !== undefined && { resumeAgentId: args.resumeAgentId }),\n ...(args.mode !== undefined && { mode: args.mode }),\n });\n state.agent = agent;\n send({ kind: 'reinit_ok', sessionId: agent.agentId });\n } catch (err) {\n send({\n kind: 'reinit_error',\n error: err instanceof Error ? err.message : String(err),\n retryable: false,\n });\n }\n}\n\n/**\n * Parse a `turn-ended` update's `usage` block into `TurnUsage`, or null when\n * absent/invalid. As of @cursor/sdk 1.0.17 `turn-ended` is a first-class member\n * of the typed `InteractionUpdate` union with `usage?: { inputTokens,\n * outputTokens, cacheReadTokens, cacheWriteTokens }` (each a plain `z.number()`),\n * so we narrow via the discriminated `type` rather than widening to `unknown`.\n *\n * The integer/non-negative guard is a DOMAIN constraint, not structural: the\n * SDK schema's `z.number()` admits Infinity / fractional / negative, but our IPC\n * schema requires `int().nonnegative()`. A schema-invalid value would get the\n * whole `summary_completed` frame rejected at parse and wedge the compaction SM,\n * so we reject it here — preTokens is then omitted and the estimated-baseline\n * fallback applies. `Number.isInteger` also rejects NaN/Infinity/non-numbers.\n */\nfunction parseTurnEndedUsage(update: InteractionUpdate): TurnUsage | null {\n /*\n * `== null` (not `=== undefined`): the schema types `usage` as optional-not-null,\n * but this is a forked-child boundary parsing external SDK data — tolerate a\n * future `usage: null` rather than throwing on destructure and crashing the runner.\n */\n if (update.type !== 'turn-ended' || update.usage == null) return null;\n const { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens } = update.usage;\n if (\n Number.isInteger(inputTokens) &&\n inputTokens >= 0 &&\n Number.isInteger(outputTokens) &&\n outputTokens >= 0 &&\n Number.isInteger(cacheReadTokens) &&\n cacheReadTokens >= 0 &&\n Number.isInteger(cacheWriteTokens) &&\n cacheWriteTokens >= 0\n ) {\n return { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens };\n }\n return null;\n}\n\n/**\n * B2: translate a Cursor `onDelta` interaction-update into a runner→daemon IPC\n * signal. Cursor's native summarization emits `summary-started` /\n * `summary-completed` (both bare `{ type }` — no token counts), so the daemon\n * derives `compaction_completed.preTokens` from the last captured `turn-ended`\n * usage instead. Text/thinking/tool deltas are the public `Run.stream()` path's\n * responsibility and are ignored here. All update kinds below are members of the\n * typed `InteractionUpdate` union (@cursor/sdk 1.0.17), so each narrows by `type`.\n */\nfunction forwardSummaryUpdate(\n update: InteractionUpdate,\n generation: number,\n latestUsage: { ref: TurnUsage | null },\n tokenDeltaAccumulator: { count: number }\n): void {\n if (update.type === 'summary-started') {\n send({ kind: 'summary_started', generation });\n return;\n }\n if (update.type === 'summary-completed') {\n const raw = latestUsage.ref;\n /*\n * inputTokensRaw equivalent: input + cache reads + cache writes = total context fill,\n * the quantity the fill-bar renders. Absent when no turn-ended fired yet this turn.\n */\n const preTokens =\n raw !== null ? raw.inputTokens + raw.cacheReadTokens + raw.cacheWriteTokens : undefined;\n send({\n kind: 'summary_completed',\n generation,\n ...(preTokens !== undefined ? { preTokens } : {}),\n });\n return;\n }\n /**\n * `user-message-appended` fires once per `agent.send()` when the SDK has\n * durably written the user turn to its local SQLite checkpoint store. The\n * daemon logs the ack for durability triage; no state mutation needed yet.\n */\n if (update.type === 'user-message-appended') {\n send({ kind: 'user_message_persisted', generation, sessionId: update.userMessage.session_id });\n return;\n }\n /**\n * `token-delta` carries the SDK's running token count during streaming.\n * Accumulated as a SECOND signal — NOT a replacement for `turn-ended.usage`,\n * which carries the input/output/cache breakdown needed for pricing.\n */\n if (update.type === 'token-delta') {\n tokenDeltaAccumulator.count += update.tokens;\n return;\n }\n const usage = parseTurnEndedUsage(update);\n if (usage !== null) {\n latestUsage.ref = usage;\n log('info', 'cursor_turn_usage_received', { generation, ...usage });\n }\n}\n\nasync function streamRun(\n run: Run,\n generation: number,\n latestUsage: { ref: TurnUsage | null },\n tokenDeltaAccumulator: { count: number }\n): Promise<void> {\n try {\n for await (const event of run.stream()) {\n /**\n * If the generation rolled forward (interrupt + new push), stop\n * forwarding events from the stale run. The daemon will already\n * be ignoring them, but stopping here saves IPC traffic.\n */\n if (state.currentGeneration !== generation) {\n log('info', 'runner_stream_aborted_stale_generation', {\n generation,\n currentGeneration: state.currentGeneration,\n });\n return;\n }\n const message: SDKMessage = event;\n send({ kind: 'sdk_message', generation, payload: message });\n }\n const result = await run.wait();\n /**\n * `Run.createdAt` (run.d.ts:42) is the authoritative SDK-side run-start\n * timestamp. The daemon currently synthesizes one from `Date.now()` at\n * the IPC boundary, which can drift by the IPC + cold-build latency\n * (sometimes seconds). Forwarding the SDK's value gives accurate\n * per-run timing for the cost/latency dashboard.\n */\n const createdAt = run.createdAt;\n send({\n kind: 'run_complete',\n generation,\n result,\n ...(latestUsage.ref !== null ? { usage: latestUsage.ref } : {}),\n ...(createdAt !== undefined ? { createdAt } : {}),\n ...(tokenDeltaAccumulator.count > 0 ? { tokenDeltaTotal: tokenDeltaAccumulator.count } : {}),\n });\n } catch (err) {\n const serialized = serializeCursorRunnerError(err);\n send({\n kind: 'run_error',\n generation,\n ...serialized,\n });\n } finally {\n if (state.currentRun === run) {\n state.currentRun = null;\n }\n }\n}\n\n/**\n * Upper bound on how long `agent.send()` may take to return a `Run`. The SDK\n * does not resolve `send()` until it has flipped the run from QUEUED to RUNNING,\n * which it gates on an un-abortable model-validation round-trip to api2.cursor.sh\n * (`resolveLocalModelSelection` runs BEFORE `markRunStarting`). If that round-trip\n * wedges (TLS up, no response) the run sits in QUEUED until undici's 300s\n * headersTimeout — a silent 5-minute stall. `SendOptions` exposes no `signal`/\n * timeout, so we race the call and surface a fast, retryable error instead.\n */\nconst SEND_START_TIMEOUT_MS = 30_000;\n\n/**\n * `agent.send()` bounded by SEND_START_TIMEOUT_MS. On timeout, rejects with a\n * retryable error (duck-typed `isRetryable` is read by serializeCursorRunnerError)\n * so the daemon surfaces \"send a message to retry\" rather than a 5-min hang.\n */\nasync function sendWithStartTimeout(\n agent: SDKAgent,\n message: string | SDKUserMessage,\n sendOptions: SendOptions\n): Promise<Run> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n agent.send(message, sendOptions),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(\n Object.assign(\n new Error(\n `Cursor did not start the run within ${SEND_START_TIMEOUT_MS / 1000}s (model validation / handshake stalled). Send a message to try again.`\n ),\n { name: 'CursorSendStartTimeout', isRetryable: true }\n )\n );\n }, SEND_START_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\nasync function handlePushMessage(args: {\n generation: number;\n content: unknown[];\n skillBodies?: CursorResolvedSkillBody[];\n forceLocalRun: boolean;\n}): Promise<void> {\n /**\n * A push_message can arrive while Agent.create is still in flight: the daemon\n * sends `init` then the first turn back-to-back, and the runner's IPC dispatch\n * is NOT serialized (process.on('message') fires `void dispatch(...)` per\n * message). Without this wait, the first turn hits the guard below before\n * `Agent.create` resolves and fails with \"cursor agent not initialized.\"\n * `initSettled` resolves when init/reinit finishes (success or a sent\n * init_error — it never rejects; the catch is belt-and-suspenders).\n */\n if (!state.agent && state.initSettled) {\n await state.initSettled.catch(() => undefined);\n }\n const agent = state.agent;\n if (!agent) {\n send({\n kind: 'run_error',\n generation: args.generation,\n error: 'cursor agent not initialized',\n errorName: 'ConfigurationError',\n isRetryable: false,\n });\n return;\n }\n state.currentGeneration = args.generation;\n /*\n * New turn: clear the heartbeat throttle so the first streamed delta of this\n * turn forwards a stream_activity immediately instead of being coalesced\n * against the previous turn's last heartbeat. Also reset the in-flight tool\n * counter so tool-execution liveness edges start fresh from 0 each turn.\n */\n lastStreamActivitySentAt = 0;\n inFlightToolCount = 0;\n /**\n * `args.content` arrives as `unknown[]` over IPC (the wire schema uses\n * `z.array(z.unknown())` for forward-compat — see comment in\n * cursor-runner-protocol.ts). Validate at the boundary via Zod rather\n * than cast: lint:extra forbids type assertions outside `as const`/`as never`,\n * and Zod gives us a runtime guarantee that matches the type.\n */\n const parsedContent = ContentBlockSchema.array().safeParse(args.content);\n if (!parsedContent.success) {\n log('warn', 'runner_push_message_invalid_content', {\n errorCount: parsedContent.error.issues.length,\n firstIssue: parsedContent.error.issues[0],\n });\n return;\n }\n const userInput: CursorUserInput = buildCursorUserPrompt(\n parsedContent.data,\n (entry) => log(entry.event.includes('error') ? 'warn' : 'info', entry.event, entry),\n { skillBodies: args.skillBodies }\n );\n if (userInput.text === '' && userInput.images.length === 0) {\n log('warn', 'runner_push_message_empty_after_build');\n return;\n }\n if (userInput.images.length > 0) {\n log('info', 'runner_push_message_with_images', {\n count: userInput.images.length,\n totalBytes: userInput.images.reduce((acc, img) => {\n const data = 'data' in img ? img.data : '';\n return acc + Math.floor((data.length * 3) / 4);\n }, 0),\n });\n }\n try {\n const message: string | SDKUserMessage =\n userInput.images.length > 0\n ? { text: userInput.text, images: userInput.images }\n : userInput.text;\n /**\n * Two send-option layers combine here:\n *\n * B2 — subscribe to the interaction-update stream so Cursor's native\n * server-managed summarization surfaces as `summary_started` /\n * `summary_completed` IPC messages. These updates flow ONLY through\n * `onDelta` — the public `Run.stream()` `SDKMessage` union has no summary\n * variant (verified against @cursor/sdk@1.0.13). Without this the daemon's\n * estimated context fill-bar never resets after Cursor compacts. `onDelta`\n * is unconditional.\n *\n * Fast Mode — attaches `SendOptions.model.params = [{id, value}]`, but only\n * when both knobs line up (the runner must NOT send an empty `params: []`).\n * Busy recovery may also attach `local.force`, but only when the daemon has\n * generation-guarded the retry.\n */\n /**\n * Mutable ref shared between the `onDelta` closure and `streamRun` so\n * the latest `turn-ended` usage can be forwarded on `run_complete`\n * without a module-level variable (each push_message gets its own ref,\n * avoiding any cross-turn contamination).\n */\n const latestUsage: { ref: TurnUsage | null } = { ref: null };\n const tokenDeltaAccumulator = { count: 0 };\n /**\n * `idempotencyKey` prevents the SDK from creating a duplicate run if the\n * runner crashes mid-`agent.send()` and we re-attempt with the same\n * generation after `Agent.resume()`. `${taskId}-${generation}` is unique\n * per turn (generation is bumped every turn or interrupt), so a clean\n * retry under the same key collapses server-side. Without this, an\n * Agent.resume-then-resend window can produce a duplicate run that the\n * SDK queues behind the original and we see two responses for one turn.\n */\n const sendOptions: SendOptions = {\n idempotencyKey: `${state.taskId}-${args.generation}`,\n /**\n * Per-RUN MCP set (live visibility). `@cursor/sdk@1.0.17` resolves\n * `opts.mcpServers ?? this.options.mcpServers` per send and forwards it to\n * the local `RunExecutor` as `mcpServersOverride`, so the set applied on\n * THIS turn reflects the latest `set_mcp_servers` IPC. Boundary cast: same\n * `McpServerConfig`-union reason as `Agent.create({ mcpServers: ... })`.\n */\n // eslint-disable-next-line no-restricted-syntax -- McpServerConfig union types require boundary cast\n mcpServers: state.mcpServers as never,\n onDelta: ({ update }) => {\n /*\n * Any interaction update means the run is producing output mid-step, so\n * feed the stall watchdog — it must measure true silence, not the\n * cadence of completed steps.\n */\n maybeSendStreamActivity(args.generation);\n /*\n * Track tool-call-started / tool-call-completed boundaries so the\n * daemon can arm an extended stall window while a tool is in flight.\n * Only emit IPC on the 0→1 (started) and 1→0 (settled) transitions —\n * intermediate count changes (2nd parallel tool start, etc.) produce\n * no IPC traffic. Stale-generation guard mirrors maybeSendStreamActivity.\n */\n if (state.currentGeneration === args.generation) {\n const edge = decideToolExecutionEdge(inFlightToolCount, update.type);\n inFlightToolCount = edge.count;\n if (edge.edge !== null) {\n send({ kind: 'tool_execution', generation: args.generation, phase: edge.edge });\n }\n }\n forwardSummaryUpdate(update, args.generation, latestUsage, tokenDeltaAccumulator);\n },\n onStep: () => {\n /*\n * Guard against a stale generation completing after the daemon\n * incremented #generation for a new run (same pattern as streamRun's\n * stale-gen guard).\n */\n if (state.currentGeneration !== args.generation) return;\n send({ kind: 'step_progress', generation: args.generation });\n },\n ...(state.fastMode && state.fastModeParam !== null\n ? { model: { id: state.modelId, params: [state.fastModeParam] } }\n : {}),\n ...(args.forceLocalRun ? { local: { force: true } } : {}),\n };\n const run = await sendWithStartTimeout(agent, message, sendOptions);\n state.currentRun = run;\n await streamRun(run, args.generation, latestUsage, tokenDeltaAccumulator);\n } catch (err) {\n const serialized = serializeCursorRunnerError(err);\n send({\n kind: 'run_error',\n generation: args.generation,\n ...serialized,\n });\n }\n}\n\nasync function handleInterrupt(generation: number): Promise<void> {\n if (!state.currentRun) {\n log('info', 'runner_interrupt_no_active_run', { generation });\n return;\n }\n try {\n await state.currentRun.cancel();\n } catch (err) {\n log('warn', 'runner_interrupt_failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n\nasync function handleClose(): Promise<void> {\n try {\n if (state.currentRun) {\n await state.currentRun.cancel();\n }\n } catch {\n /**\n * Closing — already on the exit path, swallow.\n */\n }\n try {\n if (state.agent) {\n await state.agent[Symbol.asyncDispose]();\n }\n } catch {\n /** swallow — same reason */\n }\n state.agent = null;\n state.currentRun = null;\n /**\n * Pool-managed runner: keep the process (and its warm `localExecutorCache`)\n * alive. Reset to a quiescent state and ack `pooled_idle` so the daemon can\n * reuse us for the next matching task via `reinit`. The Agent is disposed\n * above; only the heavyweight executor cache survives.\n */\n if (state.pooled) {\n state.taskId = '';\n state.fastMode = false;\n state.fastModeParam = null;\n state.mode = undefined;\n /**\n * Defensive: a turn whose final tool never emitted `tool-call-completed`\n * (killed mid-tool) must not leak its in-flight count into the next\n * pooled task's first turn.\n */\n inFlightToolCount = 0;\n send({ kind: 'pooled_idle' });\n return;\n }\n process.exit(0);\n}\n\n/**\n * Translate an `init` IPC message into `handleInit` args. Pure — extracted from\n * `dispatch` so the conditional-spread branches for optional fields don't load\n * the switch's cognitive complexity past budget.\n */\nfunction buildHandleInitArgs(\n msg: Extract<DaemonToRunner, { kind: 'init' }>\n): Parameters<typeof handleInit>[0] {\n return {\n taskId: msg.taskId,\n cwd: msg.cwd,\n apiKey: msg.apiKey,\n modelId: msg.modelId,\n mcpServers: msg.mcpServers,\n harnessUrl: msg.harnessUrl,\n harnessToken: msg.harnessToken,\n harnessRunnerId: msg.harnessRunnerId ?? '',\n pooled: msg.pooled ?? false,\n skillsDir: msg.skillsDir,\n generation: msg.generation,\n ...(msg.injectedAgentId !== undefined && { injectedAgentId: msg.injectedAgentId }),\n ...(msg.resumeAgentId !== undefined && { resumeAgentId: msg.resumeAgentId }),\n fastMode: msg.fastMode ?? false,\n fastModeParam: msg.fastModeParam ?? null,\n ...(msg.agents !== undefined && { agents: msg.agents }),\n ...(msg.mode !== undefined && { mode: msg.mode }),\n };\n}\n\n/**\n * Translate a `reinit` IPC message into `handleReinit` args. Pure — extracted\n * from `dispatch` for the same reason as `buildHandleInitArgs`: the\n * conditional-spread branches for optional fields would otherwise load the\n * switch's cognitive complexity past budget.\n */\nfunction buildHandleReinitArgs(\n msg: Extract<DaemonToRunner, { kind: 'reinit' }>\n): Parameters<typeof handleReinit>[0] {\n return {\n taskId: msg.taskId,\n modelId: msg.modelId,\n mcpServers: msg.mcpServers,\n harnessRunnerId: msg.harnessRunnerId,\n harnessToken: msg.harnessToken,\n skillsDir: msg.skillsDir,\n generation: msg.generation,\n ...(msg.resumeAgentId !== undefined && { resumeAgentId: msg.resumeAgentId }),\n fastMode: msg.fastMode ?? false,\n fastModeParam: msg.fastModeParam ?? null,\n ...(msg.agents !== undefined && { agents: msg.agents }),\n ...(msg.mode !== undefined && { mode: msg.mode }),\n };\n}\n\nasync function dispatch(raw: unknown): Promise<void> {\n const msg = parseDaemonToRunner(raw);\n if (msg === null) {\n log('warn', 'runner_invalid_ipc_message', { raw });\n return;\n }\n switch (msg.kind) {\n case 'init':\n state.initSettled = handleInit(buildHandleInitArgs(msg));\n return;\n case 'reinit':\n state.initSettled = handleReinit(buildHandleReinitArgs(msg));\n return;\n case 'set_pooled':\n /**\n * Flip the pooled flag so the next `close` keeps (pooled=true) or exits\n * (pooled=false) the process. Per-state, not per-turn.\n */\n state.currentGeneration = msg.generation;\n state.pooled = msg.pooled;\n log('info', 'runner_set_pooled_recorded', { pooled: msg.pooled });\n return;\n case 'push_message':\n await handlePushMessage({\n generation: msg.generation,\n content: msg.content,\n skillBodies: msg.skillBodies,\n forceLocalRun: msg.forceLocalRun ?? false,\n });\n return;\n case 'interrupt':\n await handleInterrupt(msg.generation);\n return;\n case 'set_model':\n /**\n * `@cursor/sdk` accepts `model` via `SendOptions` on each\n * `send()` call; there is no `agent.setModel()`. The runner\n * stores the new id and applies it on the next push. (Wired\n * in S2b — for S2a we just acknowledge.)\n */\n state.currentGeneration = msg.generation;\n log('info', 'runner_set_model_recorded', { modelId: msg.modelId });\n return;\n case 'set_mcp_servers':\n /**\n * Live per-send MCP visibility. `@cursor/sdk@1.0.17` has no\n * `agent.setMcpServers` — the MCP set is a per-RUN parameter applied via\n * `SendOptions.mcpServers` on every `agent.send()`. So we store the new\n * set (re-composing the harness MCP entry, which the daemon's\n * `resolveServersForTask` payload omits) and the NEXT `push_message`\n * carries it. No agent recreate, no restart banner — the Cursor\n * subprocess no longer raises `mcp_mid_thread_reload_needed`.\n */\n state.currentGeneration = msg.generation;\n state.mcpServers = {\n ...msg.servers,\n [HARNESS_SERVER_NAME]: buildHarnessServerEntry({\n harnessUrl: state.harnessUrl,\n harnessToken: state.harnessToken,\n harnessRunnerId: state.harnessRunnerId,\n taskId: state.taskId,\n }),\n };\n log('info', 'runner_set_mcp_servers_applied_live', {\n count: Object.keys(state.mcpServers).length,\n });\n return;\n case 'set_harness_task_id':\n state.taskId = msg.taskId;\n state.harnessToken = msg.token;\n state.currentGeneration = msg.generation;\n log('info', 'runner_harness_task_id_recorded', { taskId: msg.taskId });\n return;\n case 'set_permission_mode':\n /**\n * R1 plan mode: the daemon rewrote the mode file and hooks.json before\n * sending this. The runner records the generation and logs for triage.\n * No action needed — the next hook invocation reads the new mode file.\n */\n state.currentGeneration = msg.generation;\n log('info', 'runner_set_permission_mode_recorded', { mode: msg.mode });\n return;\n case 'set_fast_mode':\n /**\n * Fast Mode is per-state, not per-turn — record the new flag without\n * bumping the generation. The next `push_message` will read\n * `state.fastMode` when building `SendOptions`.\n */\n state.currentGeneration = msg.generation;\n state.fastMode = msg.fastMode;\n log('info', 'runner_set_fast_mode_recorded', { fastMode: msg.fastMode });\n return;\n case 'close':\n await handleClose();\n return;\n default: {\n /**\n * Compile-time exhaustiveness — adding a new variant to the\n * protocol forces this switch to be updated.\n */\n const _exhaustive: never = msg;\n log('error', 'runner_unhandled_message_kind', {\n msg: _exhaustive,\n });\n return;\n }\n }\n}\n\nprocess.on('message', (raw) => {\n /**\n * `dispatch` is async but the IPC handler is sync. Swallow any\n * promise rejection that escapes dispatch's own try/catch — those\n * are programmer errors, and crashing the runner over them just\n * trades a logged warning for a process exit + supervisor respawn\n * cycle.\n */\n void dispatch(raw).catch((err: unknown) => {\n log('error', 'runner_dispatch_unhandled_rejection', {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n});\n\nprocess.on('disconnect', () => {\n /**\n * Parent went away (daemon crash, fork channel torn down). Exit\n * with a non-zero code so the supervisor records the abnormal\n * termination.\n */\n process.exit(1);\n});\n\n/**\n * Crash-on-uncaught: any uncaught error or unhandled rejection in\n * native code (sqlite, FFI) or SDK internals SHOULD bring this child\n * down — the daemon-side supervisor records the exit and the session\n * FSM tears down. Silent recovery here would mask real bugs.\n */\nprocess.on('uncaughtException', (err) => {\n process.stderr.write(\n `${JSON.stringify({\n level: 'error',\n event: 'runner_uncaught_exception',\n error: err.message,\n stack: err.stack,\n })}\\n`\n );\n process.exit(2);\n});\n\nprocess.on('unhandledRejection', (reason) => {\n process.stderr.write(\n `${JSON.stringify({\n level: 'error',\n event: 'runner_unhandled_rejection',\n reason: reason instanceof Error ? reason.message : String(reason),\n })}\\n`\n );\n process.exit(3);\n});\n","import { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join } from 'node:path';\n\nexport interface CursorRipgrepDeps {\n env?: NodeJS.ProcessEnv;\n resolve?: (id: string) => string;\n exists?: (path: string) => boolean;\n platform?: NodeJS.Platform;\n arch?: string;\n}\n\nexport type CursorRipgrepConfigureResult =\n | { status: 'already-configured'; path: string }\n | { status: 'configured'; path: string }\n | { status: 'missing'; path: null }\n | { status: 'resolve-error'; path: null; error: unknown };\n\n/**\n * Point @cursor/sdk at the ripgrep binary bundled in its platform package.\n * The SDK currently has no public configureRipgrepPath export, so this is the\n * narrow chokepoint for the documented env override it already honors.\n */\nexport function configureCursorRipgrepPath(\n deps: CursorRipgrepDeps = {}\n): CursorRipgrepConfigureResult {\n const env = deps.env ?? process.env;\n if (env.CURSOR_RIPGREP_PATH) {\n return { status: 'already-configured', path: env.CURSOR_RIPGREP_PATH };\n }\n\n try {\n const rg = resolveCursorBundledRipgrepPath(deps);\n if (rg === null) return { status: 'missing', path: null };\n env.CURSOR_RIPGREP_PATH = rg;\n return { status: 'configured', path: rg };\n } catch (error) {\n return { status: 'resolve-error', path: null, error };\n }\n}\n\nexport function resolveCursorBundledRipgrepPath(deps: CursorRipgrepDeps = {}): string | null {\n const resolve = deps.resolve ?? createRequire(import.meta.url).resolve;\n const exists = deps.exists ?? existsSync;\n const platform = deps.platform ?? process.platform;\n const arch = deps.arch ?? process.arch;\n\n const sdkMain = resolve('@cursor/sdk');\n let sdkRoot = dirname(sdkMain);\n while (sdkRoot !== dirname(sdkRoot) && basename(sdkRoot) !== 'sdk') {\n sdkRoot = dirname(sdkRoot);\n }\n if (basename(sdkRoot) !== 'sdk') return null;\n\n const bin = platform === 'win32' ? 'rg.exe' : 'rg';\n const rg = join(sdkRoot, '..', `sdk-${platform}-${arch}`, 'bin', bin);\n return exists(rg) ? rg : null;\n}\n","/**\n * Formats and reports `init_error` messages for the Cursor runner.\n *\n * `formatCursorInitError` is the pure formatter: given a requested model id,\n * the original SDK error, and the result of `Cursor.models.list()`, it builds\n * the human-readable diagnostic string. No I/O, no side effects.\n *\n * `sendInitErrorFromAgentCreateFailure` is the impure shell: on\n * `Agent.create()` failure it probes `Cursor.models.list()` (5 s cap), feeds\n * the result to `formatCursorInitError`, and sends the `init_error` IPC\n * message via the injected `send` callback.\n *\n * The Cursor SDK delegates model-id resolution to the backend, so an unknown\n * `composer-X.Y` id surfaces as an opaque `ModelNotFound` (or similar)\n * server error. Shipyard's catalog (`cursor-model-catalog.ts`) hardcodes\n * `composer-2.5` based on Cursor's docs; if Cursor renames the model\n * server-side, every spawn fails and our only signal is the opaque SDK\n * message. We've shipped 5 Cursor fixes without ever exercising the literal\n * model string — see PR history in #3680, #3744, #3752, #3758, #3787.\n *\n * Lives alongside the runner per the FC/IS pattern in `engineering-standards.md`.\n */\n\nimport { Cursor } from '@cursor/sdk';\nimport { serializeCursorRunnerError } from './cursor-runner-error.js';\nimport type { RunnerToDaemon } from './cursor-runner-protocol.js';\n\nexport interface ModelInfo {\n id: string;\n aliases?: readonly string[];\n}\n\nexport interface CursorInitErrorInput {\n /** The model id Shipyard sent to `Agent.create()`. */\n requestedModelId: string;\n /** The SDK's original failure message (preserved verbatim at the end). */\n originalError: string;\n /**\n * Result of `Cursor.models.list()`. `null` means the list call itself\n * failed (offline, auth invalid, rate-limited) — formatter falls back\n * to the original error without speculating about available models.\n */\n availableModels: readonly ModelInfo[] | null;\n /** Optional: the error string from the failed list call, for triage. */\n listError?: string;\n}\n\nexport function formatCursorInitError(input: CursorInitErrorInput): string {\n const { requestedModelId, originalError, availableModels, listError } = input;\n if (availableModels === null) {\n const listPart = listError\n ? ` (Cursor.models.list() also failed: ${listError})`\n : ' (Cursor.models.list() unavailable)';\n return `Agent.create failed for model '${requestedModelId}'. ${originalError}${listPart}`;\n }\n if (availableModels.length === 0) {\n return `Agent.create failed for model '${requestedModelId}'. Cursor.models.list() returned no models. ${originalError}`;\n }\n const requested = requestedModelId.toLowerCase();\n const exactMatch = availableModels.find(\n (m) =>\n m.id.toLowerCase() === requested ||\n (m.aliases ?? []).some((a) => a.toLowerCase() === requested)\n );\n const idsList = availableModels.map((m) => m.id).join(', ');\n const aliasParts = availableModels\n .filter((m) => (m.aliases?.length ?? 0) > 0)\n .map((m) => `${m.id}=[${(m.aliases ?? []).join('|')}]`);\n const aliasesList = aliasParts.length > 0 ? aliasParts.join(', ') : '(none)';\n const matchPart = exactMatch\n ? ` The id IS in the available set (${exactMatch.id}) — failure is unrelated to model resolution.`\n : ` The id is NOT in the available set — likely renamed or deprecated server-side.`;\n return `Agent.create failed for model '${requestedModelId}'.${matchPart} Available ids: ${idsList}. Aliases: ${aliasesList}. Original: ${originalError}`;\n}\n\nconst INIT_MODEL_LIST_TIMEOUT_MS = 5000;\n\nexport async function sendInitErrorFromAgentCreateFailure(args: {\n apiKey: string;\n modelId: string;\n err: unknown;\n send: (msg: RunnerToDaemon) => void;\n}): Promise<void> {\n const originalError = args.err instanceof Error ? args.err.message : String(args.err);\n /**\n * On Agent.create failure, probe Cursor.models.list() once to capture\n * the authoritative {id, aliases} set. If the requested model is in\n * that set, the failure is unrelated to model resolution; if not, the\n * id is stale and the log line names the replacement immediately.\n *\n * Best-effort: the list call may itself fail (offline, auth, rate-\n * limited). The formatter handles a null `availableModels` by falling\n * back to the original error verbatim — no information loss vs the\n * pre-Item-1 behavior.\n */\n let availableModels: ModelInfo[] | null = null;\n let listError: string | undefined;\n /**\n * @cursor/sdk@1.0.13's CursorRequestOptions has no AbortSignal or timeout\n * field — a hung backend would block init_error indefinitely and wedge\n * the session FSM in \"initializing\". 5s cap restores the pre-Item-1\n * upper bound (the original code sent init_error immediately) at the\n * cost of degrading the diagnostic when Cursor's API is slow.\n */\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n const listPromise = Cursor.models.list({ apiKey: args.apiKey });\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(\n () => reject(new Error(`timed out after ${INIT_MODEL_LIST_TIMEOUT_MS}ms`)),\n INIT_MODEL_LIST_TIMEOUT_MS\n );\n });\n const models = await Promise.race([listPromise, timeoutPromise]);\n availableModels = models.map((m) => ({ id: m.id, aliases: m.aliases }));\n } catch (listErr) {\n listError = listErr instanceof Error ? listErr.message : String(listErr);\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n const serialized = serializeCursorRunnerError(args.err);\n args.send({\n kind: 'init_error',\n error: formatCursorInitError({\n requestedModelId: args.modelId,\n originalError,\n availableModels,\n listError,\n }),\n ...(serialized.errorName !== undefined ? { errorName: serialized.errorName } : {}),\n ...(serialized.errorCode !== undefined ? { errorCode: serialized.errorCode } : {}),\n ...(serialized.statusCode !== undefined ? { statusCode: serialized.statusCode } : {}),\n retryable: serialized.isRetryable,\n });\n}\n","/**\n * Serialize thrown values from `@cursor/sdk` into the wire shape the daemon\n * expects on `run_error` / `init_error` IPC messages.\n *\n * Pure FC/IS helper — no I/O. Duck-types SDK error fields because errors\n * arrive as live class instances inside the runner process.\n */\n\nexport interface CursorRunnerErrorWire {\n error: string;\n errorName?: string;\n errorCode?: string;\n statusCode?: number;\n isRetryable: boolean;\n}\n\nfunction readStringField(rec: Record<string, unknown>, key: string): string | undefined {\n const value = rec[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction readNumberField(rec: Record<string, unknown>, key: string): number | undefined {\n const value = rec[key];\n return typeof value === 'number' ? value : undefined;\n}\n\nfunction readBooleanField(rec: Record<string, unknown>, key: string): boolean | undefined {\n const value = rec[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\n/**\n * Extract message, SDK error `name`, `code`, `status`, and `isRetryable`\n * from a thrown value for IPC transport to the daemon-side classifier.\n */\nexport function serializeCursorRunnerError(err: unknown): CursorRunnerErrorWire {\n if (typeof err === 'object' && err !== null) {\n // eslint-disable-next-line no-restricted-syntax -- unknown thrown value narrowed by typeof; Record probe for duck-typed SDK errors\n const rec = err as Record<string, unknown>;\n const message =\n typeof rec.message === 'string' && rec.message.length > 0 ? rec.message : String(err);\n const wire: CursorRunnerErrorWire = {\n error: message,\n isRetryable: readBooleanField(rec, 'isRetryable') ?? false,\n };\n const errorName = readStringField(rec, 'name');\n const errorCode = readStringField(rec, 'code');\n const statusCode = readNumberField(rec, 'status');\n if (errorName !== undefined) wire.errorName = errorName;\n if (errorCode !== undefined) wire.errorCode = errorCode;\n if (statusCode !== undefined) wire.statusCode = statusCode;\n return wire;\n }\n return { error: String(err), isRetryable: false };\n}\n","/**\n * cursor-tool-execution-edge — pure helper for tracking in-flight Cursor\n * tool calls and emitting IPC liveness edges.\n *\n * The @cursor/sdk's `InteractionUpdate` union includes `'tool-call-started'`\n * and `'tool-call-completed'` variants in the `onDelta` callback. Tools like\n * `git commit` (whose pre-commit hooks run `pnpm check` for 3–10 min) emit\n * no `stream_activity` deltas during execution — the SDK is truly silent\n * while the shell/tool subprocess runs. Without this edge the stall watchdog\n * (180s mid-run) false-kills a healthy runner executing a long tool.\n *\n * Solution: track in-flight count; emit an IPC `tool_execution` message only\n * on the 0→1 (started) and 1→0 (settled) transitions so the daemon can arm\n * an extended per-tool stall window on `started` and revert on `settled`.\n *\n * No I/O, no side effects. All exports are deterministic pure functions.\n */\n\nexport interface ToolExecutionEdgeResult {\n /** Updated in-flight tool count after applying the update type. */\n count: number;\n /**\n * Non-null only on a 0→1 (`'started'`) or 1→0 (`'settled'`) transition.\n * Null for any intermediate count change (1→2, 3→2, etc.) — only the\n * boundary edges matter for the daemon's window-switching decision.\n */\n edge: 'started' | 'settled' | null;\n}\n\n/**\n * Given the current in-flight tool count and an `InteractionUpdate` type\n * string, return the new count and (if a liveness edge occurred) the edge\n * direction.\n *\n * - `'tool-call-started'` increments; edge is `'started'` only on 0→1.\n * - `'tool-call-completed'` decrements (clamped at 0); edge is `'settled'`\n * only on 1→0.\n * - Any other type is a no-op: count unchanged, edge null.\n */\nexport function decideToolExecutionEdge(\n inFlightCount: number,\n updateType: string\n): ToolExecutionEdgeResult {\n if (updateType === 'tool-call-started') {\n const newCount = inFlightCount + 1;\n return { count: newCount, edge: newCount === 1 ? 'started' : null };\n }\n if (updateType === 'tool-call-completed') {\n const newCount = Math.max(0, inFlightCount - 1);\n return { count: newCount, edge: inFlightCount === 1 ? 'settled' : null };\n }\n return { count: inFlightCount, edge: null };\n}\n"],"mappings":"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","names":[]}
|
package/dist/electron-utility.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
getDaemonVersion
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QKJNVVQ3.js";
|
|
5
5
|
import {
|
|
6
6
|
installWasmPanicBuffer
|
|
7
7
|
} from "./chunk-7H34LI75.js";
|
|
8
8
|
import {
|
|
9
9
|
logger
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-LRNGLC4V.js";
|
|
11
11
|
import {
|
|
12
12
|
getShipyardHome,
|
|
13
13
|
validateEnv
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-P2HZDIN7.js";
|
|
15
15
|
import "./chunk-CNR7O5YH.js";
|
|
16
16
|
import "./chunk-2H7UOFLK.js";
|
|
17
17
|
|
|
@@ -35,7 +35,7 @@ function isVersionQuery(data) {
|
|
|
35
35
|
}
|
|
36
36
|
async function loadAuthFromConfig(env) {
|
|
37
37
|
if (env.SHIPYARD_USER_TOKEN) return;
|
|
38
|
-
const { loadAuthToken } = await import("./auth-
|
|
38
|
+
const { loadAuthToken } = await import("./auth-AUY74PMB.js");
|
|
39
39
|
const auth = await loadAuthToken();
|
|
40
40
|
if (auth.status === "ok") {
|
|
41
41
|
env.SHIPYARD_USER_TOKEN = auth.token;
|
|
@@ -66,7 +66,7 @@ async function main() {
|
|
|
66
66
|
await loadAuthFromConfig(env);
|
|
67
67
|
crumb("post-auth-load");
|
|
68
68
|
crumb("pre-serve-import");
|
|
69
|
-
const { serve } = await import("./serve-
|
|
69
|
+
const { serve } = await import("./serve-P3U2C5YH.js");
|
|
70
70
|
crumb("post-serve-import");
|
|
71
71
|
const portQueue = [];
|
|
72
72
|
let acceptor = null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
FIND_GIT_REPOS_DIR_CONCURRENCY,
|
|
3
4
|
NEGATIVE_CACHE_TTL_MS,
|
|
4
5
|
_testing,
|
|
5
6
|
detectEnvironments,
|
|
@@ -13,15 +14,16 @@ import {
|
|
|
13
14
|
isGhAvailable,
|
|
14
15
|
isGitRepo,
|
|
15
16
|
parseOwnerRepo
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-Y5UWRARP.js";
|
|
17
18
|
import "./chunk-4T2OQAVL.js";
|
|
18
19
|
import "./chunk-RR6V6SNM.js";
|
|
19
20
|
import "./chunk-ZFKJAYAN.js";
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
21
|
+
import "./chunk-LRNGLC4V.js";
|
|
22
|
+
import "./chunk-P2HZDIN7.js";
|
|
22
23
|
import "./chunk-CNR7O5YH.js";
|
|
23
24
|
import "./chunk-2H7UOFLK.js";
|
|
24
25
|
export {
|
|
26
|
+
FIND_GIT_REPOS_DIR_CONCURRENCY,
|
|
25
27
|
NEGATIVE_CACHE_TTL_MS,
|
|
26
28
|
_testing,
|
|
27
29
|
detectEnvironments,
|
|
@@ -36,4 +38,4 @@ export {
|
|
|
36
38
|
isGitRepo,
|
|
37
39
|
parseOwnerRepo
|
|
38
40
|
};
|
|
39
|
-
//# sourceMappingURL=git-repo-
|
|
41
|
+
//# sourceMappingURL=git-repo-CTZJS3ER.js.map
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-7H34LI75.js";
|
|
5
5
|
import {
|
|
6
6
|
logger
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-LRNGLC4V.js";
|
|
8
8
|
import {
|
|
9
9
|
validateEnv
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-P2HZDIN7.js";
|
|
11
11
|
import "./chunk-CNR7O5YH.js";
|
|
12
12
|
import "./chunk-2H7UOFLK.js";
|
|
13
13
|
|
|
@@ -81,7 +81,7 @@ function parseCliArgs() {
|
|
|
81
81
|
}
|
|
82
82
|
async function loadAuthFromConfig(env) {
|
|
83
83
|
if (env.SHIPYARD_USER_TOKEN) return;
|
|
84
|
-
const { loadAuthToken } = await import("./auth-
|
|
84
|
+
const { loadAuthToken } = await import("./auth-AUY74PMB.js");
|
|
85
85
|
const auth = await loadAuthToken();
|
|
86
86
|
if (auth.status === "ok") {
|
|
87
87
|
env.SHIPYARD_USER_TOKEN = auth.token;
|
|
@@ -101,23 +101,23 @@ async function loadAuthFromConfig(env) {
|
|
|
101
101
|
async function handleSubcommand() {
|
|
102
102
|
const subcommand = process.argv[2];
|
|
103
103
|
if (subcommand === "login") {
|
|
104
|
-
const { loginCommand } = await import("./login-
|
|
104
|
+
const { loginCommand } = await import("./login-YB34LF4L.js");
|
|
105
105
|
const hasCheck = process.argv.includes("--check");
|
|
106
106
|
await loginCommand({ check: hasCheck });
|
|
107
107
|
return true;
|
|
108
108
|
}
|
|
109
109
|
if (subcommand === "logout") {
|
|
110
|
-
const { logoutCommand } = await import("./logout-
|
|
110
|
+
const { logoutCommand } = await import("./logout-GUXVSWLZ.js");
|
|
111
111
|
await logoutCommand();
|
|
112
112
|
return true;
|
|
113
113
|
}
|
|
114
114
|
if (subcommand === "start") {
|
|
115
|
-
const { startCommand } = await import("./start-
|
|
115
|
+
const { startCommand } = await import("./start-Y34X3WVF.js");
|
|
116
116
|
await startCommand();
|
|
117
117
|
return true;
|
|
118
118
|
}
|
|
119
119
|
if (subcommand === "roi") {
|
|
120
|
-
const { roiCommand } = await import("./roi-
|
|
120
|
+
const { roiCommand } = await import("./roi-NXJHL5X2.js");
|
|
121
121
|
await roiCommand();
|
|
122
122
|
return true;
|
|
123
123
|
}
|
|
@@ -129,7 +129,7 @@ async function main() {
|
|
|
129
129
|
const args = parseCliArgs();
|
|
130
130
|
if (args.serve) {
|
|
131
131
|
await loadAuthFromConfig(env);
|
|
132
|
-
const { serve } = await import("./serve-
|
|
132
|
+
const { serve } = await import("./serve-P3U2C5YH.js");
|
|
133
133
|
return serve({ isDev: env.SHIPYARD_DEV });
|
|
134
134
|
}
|
|
135
135
|
logger.error("Use `shipyard start` to run the daemon. Use --help for usage.");
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
flushLogger,
|
|
5
5
|
getLogFilePath,
|
|
6
6
|
logger,
|
|
7
|
-
shouldAttachFileTransport
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
shouldAttachFileTransport,
|
|
8
|
+
shouldDeleteLogFile
|
|
9
|
+
} from "./chunk-LRNGLC4V.js";
|
|
10
|
+
import "./chunk-P2HZDIN7.js";
|
|
10
11
|
import "./chunk-CNR7O5YH.js";
|
|
11
12
|
import "./chunk-2H7UOFLK.js";
|
|
12
13
|
export {
|
|
@@ -14,6 +15,7 @@ export {
|
|
|
14
15
|
flushLogger,
|
|
15
16
|
getLogFilePath,
|
|
16
17
|
logger,
|
|
17
|
-
shouldAttachFileTransport
|
|
18
|
+
shouldAttachFileTransport,
|
|
19
|
+
shouldDeleteLogFile
|
|
18
20
|
};
|
|
19
|
-
//# sourceMappingURL=logger-
|
|
21
|
+
//# sourceMappingURL=logger-AN7EUK2B.js.map
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
ensureAuthenticated,
|
|
4
4
|
getSignalingUrl,
|
|
5
5
|
loginCommand
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-4SYLDZTY.js";
|
|
7
|
+
import "./chunk-5W5N5U2S.js";
|
|
8
|
+
import "./chunk-X5KCX6ZS.js";
|
|
9
9
|
import "./chunk-RMLQ5DRP.js";
|
|
10
10
|
import "./chunk-EHQITHQX.js";
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-LRNGLC4V.js";
|
|
12
|
+
import "./chunk-P2HZDIN7.js";
|
|
13
13
|
import "./chunk-CNR7O5YH.js";
|
|
14
14
|
import "./chunk-2H7UOFLK.js";
|
|
15
15
|
export {
|
|
@@ -17,4 +17,4 @@ export {
|
|
|
17
17
|
getSignalingUrl,
|
|
18
18
|
loginCommand
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=login-
|
|
20
|
+
//# sourceMappingURL=login-YB34LF4L.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
print
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5W5N5U2S.js";
|
|
5
5
|
import {
|
|
6
6
|
deleteConfig,
|
|
7
7
|
getConfigPath
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-X5KCX6ZS.js";
|
|
9
|
+
import "./chunk-LRNGLC4V.js";
|
|
10
|
+
import "./chunk-P2HZDIN7.js";
|
|
11
11
|
import "./chunk-CNR7O5YH.js";
|
|
12
12
|
import "./chunk-2H7UOFLK.js";
|
|
13
13
|
|
|
@@ -23,4 +23,4 @@ async function logoutCommand() {
|
|
|
23
23
|
export {
|
|
24
24
|
logoutCommand
|
|
25
25
|
};
|
|
26
|
-
//# sourceMappingURL=logout-
|
|
26
|
+
//# sourceMappingURL=logout-GUXVSWLZ.js.map
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
redactEnv,
|
|
13
13
|
resetMCPConfigCaches,
|
|
14
14
|
shouldFetchClaudeAiIntegrations
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-KYLYGFMH.js";
|
|
16
16
|
import "./chunk-RR6V6SNM.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-LRNGLC4V.js";
|
|
18
|
+
import "./chunk-P2HZDIN7.js";
|
|
19
19
|
import "./chunk-CNR7O5YH.js";
|
|
20
20
|
import "./chunk-2H7UOFLK.js";
|
|
21
21
|
export {
|
|
@@ -32,4 +32,4 @@ export {
|
|
|
32
32
|
resetMCPConfigCaches,
|
|
33
33
|
shouldFetchClaudeAiIntegrations
|
|
34
34
|
};
|
|
35
|
-
//# sourceMappingURL=mcp-servers-
|
|
35
|
+
//# sourceMappingURL=mcp-servers-OAPQNDA7.js.map
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
import "./chunk-EHQITHQX.js";
|
|
9
9
|
import {
|
|
10
10
|
logger
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LRNGLC4V.js";
|
|
12
12
|
import {
|
|
13
13
|
validateEnv
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-P2HZDIN7.js";
|
|
15
15
|
import "./chunk-CNR7O5YH.js";
|
|
16
16
|
import "./chunk-2H7UOFLK.js";
|
|
17
17
|
|
|
@@ -681,4 +681,4 @@ function renderReport(report, format) {
|
|
|
681
681
|
export {
|
|
682
682
|
roiCommand
|
|
683
683
|
};
|
|
684
|
-
//# sourceMappingURL=roi-
|
|
684
|
+
//# sourceMappingURL=roi-NXJHL5X2.js.map
|