@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.0

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +99 -126
  3. package/dist/cursor-agents-context-registration.js +1 -3
  4. package/dist/cursor-agents-context.js +2 -2
  5. package/dist/cursor-config.js +2 -290
  6. package/dist/cursor-provider-errors.js +3 -58
  7. package/dist/cursor-provider-live-run-drain.js +0 -3
  8. package/dist/cursor-provider-run-finalizer.js +4 -7
  9. package/dist/cursor-provider-run-outcome.js +1 -1
  10. package/dist/cursor-provider-turn-finalize.js +3 -55
  11. package/dist/cursor-provider-turn-prepare.js +8 -144
  12. package/dist/cursor-provider-turn-runner.js +9 -23
  13. package/dist/cursor-provider-turn-send.js +8 -35
  14. package/dist/cursor-runtime-state.js +6 -268
  15. package/dist/cursor-sdk-billed-usage.js +3 -18
  16. package/dist/cursor-sdk-platform-package.js +88 -0
  17. package/dist/cursor-session-agent.js +18 -14
  18. package/dist/cursor-skill-tool.js +12 -22
  19. package/dist/cursor-state.js +5 -8
  20. package/dist/cursor-usage-accounting.js +1 -1
  21. package/docs/cursor-dogfood-checklist.md +4 -4
  22. package/docs/cursor-live-smoke-checklist.md +23 -23
  23. package/docs/cursor-model-ux-spec.md +27 -30
  24. package/docs/cursor-native-tool-replay.md +4 -4
  25. package/docs/cursor-native-tool-visual-audit.md +7 -7
  26. package/docs/cursor-testing-lessons.md +23 -16
  27. package/docs/cursor-tool-surfaces.md +2 -4
  28. package/docs/platform-smoke-implementation.md +5 -5
  29. package/docs/platform-smoke.md +27 -72
  30. package/package.json +3 -17
  31. package/platform-smoke.config.mjs +2 -1
  32. package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
  33. package/scripts/platform-smoke/card-detect.mjs +1 -1
  34. package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
  35. package/scripts/platform-smoke/scenarios.mjs +1 -1
  36. package/scripts/platform-smoke/targets.mjs +14 -5
  37. package/src/cursor-agents-context-registration.ts +0 -5
  38. package/src/cursor-agents-context.ts +1 -3
  39. package/src/cursor-config.ts +8 -379
  40. package/src/cursor-provider-errors.ts +2 -62
  41. package/src/cursor-provider-live-run-drain.ts +0 -3
  42. package/src/cursor-provider-run-finalizer.ts +4 -12
  43. package/src/cursor-provider-run-outcome.ts +0 -3
  44. package/src/cursor-provider-turn-finalize.ts +3 -61
  45. package/src/cursor-provider-turn-prepare.ts +8 -165
  46. package/src/cursor-provider-turn-runner.ts +15 -31
  47. package/src/cursor-provider-turn-send.ts +7 -38
  48. package/src/cursor-provider-turn-types.ts +9 -30
  49. package/src/cursor-runtime-state.ts +6 -345
  50. package/src/cursor-sdk-billed-usage.ts +3 -24
  51. package/src/cursor-sdk-platform-package.ts +106 -0
  52. package/src/cursor-session-agent.ts +16 -12
  53. package/src/cursor-skill-tool.ts +10 -26
  54. package/src/cursor-state.ts +5 -10
  55. package/src/cursor-usage-accounting.ts +1 -3
  56. package/dist/cursor-cloud-lifecycle.js +0 -650
  57. package/dist/cursor-cloud-local-state.js +0 -460
  58. package/dist/cursor-cloud-options.js +0 -145
  59. package/dist/cursor-cloud-reporting.js +0 -222
  60. package/dist/cursor-ripgrep-path.js +0 -27
  61. package/scripts/cloud-runtime-smoke.d.mts +0 -42
  62. package/scripts/cloud-runtime-smoke.mjs +0 -623
  63. package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
  64. package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
  65. package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
  66. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
  67. package/scripts/lib/cloud-smoke-github.d.mts +0 -78
  68. package/scripts/lib/cloud-smoke-github.mjs +0 -331
  69. package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
  70. package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
  71. package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
  72. package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
  73. package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
  74. package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
  75. package/src/cursor-cloud-lifecycle.ts +0 -733
  76. package/src/cursor-cloud-local-state.ts +0 -536
  77. package/src/cursor-cloud-options.ts +0 -182
  78. package/src/cursor-cloud-reporting.ts +0 -267
  79. package/src/cursor-ripgrep-path.ts +0 -32
@@ -10,7 +10,6 @@ import {
10
10
  resolveCursorSdkAbortCause,
11
11
  sanitizeCursorProviderError,
12
12
  } from "./cursor-provider-errors.js";
13
- import type { CursorRuntime } from "./cursor-config.js";
14
13
  import { CursorLiveRunAbortError } from "./cursor-live-run-coordinator.js";
15
14
  import {
16
15
  buildIncompleteCursorToolRunOutcome,
@@ -25,7 +24,6 @@ import type {
25
24
  CursorProviderTurnSend,
26
25
  CursorProviderTurnSendResult,
27
26
  LiveCursorProviderTurnRuntime,
28
- LocalCursorProviderTurnPrepareResult,
29
27
  } from "./cursor-provider-turn-types.js";
30
28
  import { applyCursorUsage } from "./cursor-usage-accounting.js";
31
29
  import { hasUsableText } from "./cursor-record-utils.js";
@@ -35,13 +33,12 @@ export type CursorTurnTerminalEvent =
35
33
  kind: "direct";
36
34
  prepared: CursorProviderTurnPrepareResult;
37
35
  outcome: CursorRunOutcome;
38
- displayOnlyTraceBlock?: string;
39
36
  }
40
37
  | { kind: "error"; prepared: CursorProviderTurnPrepareResult | undefined; error: unknown };
41
38
 
42
39
  function applyLiveRunOutcome(
43
40
  outcome: CursorRunOutcome,
44
- prepared: LocalCursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime },
41
+ prepared: CursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime },
45
42
  context: CursorProviderTurnRunnerParams["context"],
46
43
  ): void {
47
44
  if (prepared.runtime.liveRun.disposed) return;
@@ -71,12 +68,11 @@ export interface CursorRunFinalizerParams {
71
68
  sdkEventDebug: () => CursorSdkEventDebugSink | undefined;
72
69
  sdkProcessErrorGuard: ReturnType<typeof installCursorSdkProcessErrorGuard>;
73
70
  resolvedApiKey: () => string | undefined;
74
- runtimeTarget: () => CursorRuntime | undefined;
75
71
  }
76
72
 
77
73
  export interface StartCursorLiveRunCompletionParams {
78
74
  send: CursorProviderTurnSend;
79
- prepared: LocalCursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime };
75
+ prepared: CursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime };
80
76
  modelId: string;
81
77
  discardIncompleteTools: (outcome: IncompleteCursorToolRunOutcomeInput) => void;
82
78
  }
@@ -114,7 +110,7 @@ export class CursorRunFinalizer {
114
110
  if (!liveRun.disposed) {
115
111
  cursorLiveRuns.markError(
116
112
  liveRun,
117
- sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? runnerParams.options?.apiKey, "local"),
113
+ sanitizeCursorProviderError(error, this.params.resolvedApiKey() ?? runnerParams.options?.apiKey),
118
114
  );
119
115
  }
120
116
  this.safeCleanup(() => sdkEventDebug?.recordWaitResult({ status: "error", error: String(error) }));
@@ -129,7 +125,7 @@ export class CursorRunFinalizer {
129
125
  async applyTerminalEvent(event: CursorTurnTerminalEvent): Promise<void> {
130
126
  if (this.terminalApplied) return;
131
127
  if (event.kind === "direct") {
132
- await this.applyDirectOutcome(event.prepared, event.outcome, event.displayOnlyTraceBlock);
128
+ await this.applyDirectOutcome(event.prepared, event.outcome);
133
129
  this.terminalApplied = true;
134
130
  return;
135
131
  }
@@ -165,7 +161,6 @@ export class CursorRunFinalizer {
165
161
  private async applyDirectOutcome(
166
162
  prepared: CursorProviderTurnPrepareResult,
167
163
  outcome: CursorRunOutcome,
168
- displayOnlyTraceBlock: string | undefined,
169
164
  ): Promise<void> {
170
165
  const { stream, partial, model, context } = this.params.runnerParams;
171
166
  prepared.runtime.turnCoordinator.closeTraceBlock();
@@ -184,12 +179,10 @@ export class CursorRunFinalizer {
184
179
  outcome.kind === "finished" && hasUsableText(outcome.finalText) ? [outcome.finalText] : [],
185
180
  );
186
181
  applyCursorUsage(partial, model, context, prepared.meta.promptInputTokens, {
187
- runtime: prepared.runtimeTarget,
188
182
  turn: prepared.runtime.turnCoordinator.lastSdkTurnUsage,
189
183
  billed: prepared.runtime.billedTurnUsage,
190
184
  });
191
185
  if (prepared.meta.resumeNotice) emitDisplayOnlyTraceBlock(stream, partial, prepared.meta.resumeNotice);
192
- if (displayOnlyTraceBlock) emitDisplayOnlyTraceBlock(stream, partial, displayOnlyTraceBlock);
193
186
  stream.push({ type: "done", reason: "stop", message: partial });
194
187
  break;
195
188
  }
@@ -219,7 +212,6 @@ export class CursorRunFinalizer {
219
212
  sanitizeCursorProviderError(
220
213
  error,
221
214
  this.params.resolvedApiKey() ?? this.params.runnerParams.options?.apiKey,
222
- prepared?.runtimeTarget ?? this.params.runtimeTarget(),
223
215
  ),
224
216
  );
225
217
  }
@@ -6,7 +6,6 @@ import {
6
6
  resolveCursorSdkAbortCause,
7
7
  sanitizeCursorProviderError,
8
8
  } from "./cursor-provider-errors.js";
9
- import type { CursorRuntime } from "./cursor-config.js";
10
9
  import { hasUsableText } from "./cursor-record-utils.js";
11
10
  import {
12
11
  buildIncompleteCursorToolRunOutcome,
@@ -46,7 +45,6 @@ export interface ResolveCursorRunOutcomeParams {
46
45
  runErrorFallback?: RunError;
47
46
  resolvedApiKey?: string;
48
47
  optionsApiKey?: string;
49
- runtimeTarget: CursorRuntime;
50
48
  }
51
49
 
52
50
  function hasCursorAssistantText(
@@ -109,7 +107,6 @@ export function resolveCursorRunOutcome(params: ResolveCursorRunOutcomeParams):
109
107
  errorMessage: sanitizeCursorProviderError(
110
108
  failureDetail,
111
109
  params.resolvedApiKey ?? params.optionsApiKey,
112
- params.runtimeTarget,
113
110
  ),
114
111
  };
115
112
  }
@@ -1,13 +1,6 @@
1
1
  import type { LocalAgentStore, RunError, SDKAgent } from "@cursor/sdk";
2
2
  import { loadCursorTranscriptWebToolCallsAfterOffset } from "./cursor-agent-message-web-tools.js";
3
- import {
4
- collectCursorCloudRunReport,
5
- formatCursorCloudRunReport,
6
- type CursorCloudRunReport,
7
- } from "./cursor-cloud-reporting.js";
8
- import { recordCursorCloudLifecycleRun } from "./cursor-cloud-lifecycle.js";
9
3
  import { getCheckpointContextWindow, saveCachedContextWindow } from "./context-window-cache.js";
10
- import { scrubSensitiveText } from "./cursor-sensitive-text.js";
11
4
  import type { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
12
5
  import type { CursorSdkTurnCoordinator } from "./cursor-provider-turn-coordinator.js";
13
6
  import {
@@ -68,7 +61,6 @@ export function buildCursorRunOutcomeFromWait(params: BuildCursorRunOutcomeParam
68
61
  runErrorFallback: params.runErrorFallback,
69
62
  resolvedApiKey: params.resolvedApiKey,
70
63
  optionsApiKey: params.optionsApiKey,
71
- runtimeTarget: prepared.runtimeTarget,
72
64
  });
73
65
  }
74
66
 
@@ -99,22 +91,6 @@ async function replayCursorTranscriptWebToolCalls(
99
91
  }
100
92
  }
101
93
 
102
- function scrubCursorCloudReportingError(error: unknown, apiKey: string | undefined): Error {
103
- return new Error(scrubSensitiveText(error instanceof Error ? error.message : String(error), apiKey));
104
- }
105
-
106
- function recordCursorCloudReportingError(
107
- sdkEventDebug: CursorSdkEventDebugSink | undefined,
108
- error: unknown,
109
- apiKey: string | undefined,
110
- ): void {
111
- try {
112
- sdkEventDebug?.recordError("cloud_run_report", scrubCursorCloudReportingError(error, apiKey));
113
- } catch {
114
- // Debug reporting must never affect provider execution.
115
- }
116
- }
117
-
118
94
  export interface AwaitFinalizeCursorRunOutcomeParams {
119
95
  run: Awaited<ReturnType<SDKAgent["send"]>>;
120
96
  prepared: CursorProviderTurnPrepareResult;
@@ -134,12 +110,10 @@ export interface AwaitFinalizeCursorRunOutcomeParams {
134
110
 
135
111
  export interface FinalizedCursorRunOutcome {
136
112
  outcome: CursorRunOutcome;
137
- displayOnlyTraceBlock?: string;
138
113
  }
139
114
 
140
115
  /** Single wait/finalize path for SDK runs: wait, debug capture, transcript replay, incomplete tools, artifacts, context cache. */
141
116
  export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorRunOutcomeParams): Promise<FinalizedCursorRunOutcome> {
142
- const apiKey = params.resolvedApiKey ?? params.optionsApiKey;
143
117
  const waitResult = params.waitResult ?? (await params.run.wait());
144
118
  const outcome = buildCursorRunOutcomeFromWait({
145
119
  waitResult,
@@ -153,49 +127,17 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
153
127
  const billed = await attachCursorSdkBilledTurnUsage({
154
128
  agent: params.prepared.agent,
155
129
  agentId: params.run.agentId,
156
- runtime: params.prepared.runtimeTarget,
157
- runId: params.run.id,
158
130
  });
159
131
  params.prepared.runtime.billedTurnUsage = billed.turn;
160
132
  if (params.prepared.runtime.liveRun) {
161
133
  params.prepared.runtime.liveRun.billedTurnUsage = billed.turn;
162
134
  }
163
- let displayOnlyTraceBlock: string | undefined;
164
- if (params.prepared.runtimeTarget === "cloud" && isCursorRunFinishedSuccessfully(outcome)) {
165
- let report: CursorCloudRunReport = { agentId: params.run.agentId, runId: params.run.id, branches: [] };
166
- try {
167
- report = await collectCursorCloudRunReport({
168
- agent: params.prepared.agent,
169
- run: params.run,
170
- waitResult,
171
- apiKey,
172
- agentUsage: billed.agentUsage,
173
- });
174
- } catch (error) {
175
- recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
176
- }
177
- try {
178
- recordCursorCloudLifecycleRun(report, { apiKey });
179
- } catch (error) {
180
- recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
181
- }
182
- try {
183
- params.sdkEventDebug?.recordProviderEvent("cloud_run_report", report);
184
- } catch (error) {
185
- recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
186
- }
187
- try {
188
- displayOnlyTraceBlock = formatCursorCloudRunReport(report, { apiKey });
189
- } catch (error) {
190
- recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
191
- }
192
- }
193
135
  try {
194
136
  params.sdkEventDebug?.recordWaitResult(waitResult);
195
137
  } catch {
196
138
  // Debug reporting must never affect provider execution.
197
139
  }
198
- if (params.prepared.runtimeTarget === "local" && isCursorRunFinishedSuccessfully(outcome)) {
140
+ if (isCursorRunFinishedSuccessfully(outcome)) {
199
141
  await replayCursorTranscriptWebToolCalls(
200
142
  params.run.agentId,
201
143
  params.prepared.cwd,
@@ -211,7 +153,7 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
211
153
  } catch {
212
154
  // Debug artifact failures must never affect provider execution.
213
155
  }
214
- if (params.prepared.runtimeTarget === "local" && params.cacheContextWindow !== false) {
156
+ if (params.cacheContextWindow !== false) {
215
157
  await cacheSdkContextWindow(
216
158
  params.contextWindowAgentId ?? params.run.agentId,
217
159
  params.modelId,
@@ -219,5 +161,5 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
219
161
  params.prepared.sessionAgentLease.store,
220
162
  );
221
163
  }
222
- return { outcome, displayOnlyTraceBlock };
164
+ return { outcome };
223
165
  }
@@ -1,8 +1,8 @@
1
1
  import type { Context, SimpleStreamOptions } from "@earendil-works/pi-ai";
2
- import type { AgentModeOption, ModelSelection, SDKAgent } from "@cursor/sdk";
2
+ import type { AgentModeOption, ModelSelection } from "@cursor/sdk";
3
3
  import { configureCursorSdkHttp1 } from "./cursor-http1.js";
4
4
  import { installCursorMcpToolTimeoutOverride } from "./cursor-mcp-timeout-override.js";
5
- import { ensureCursorRipgrepPath } from "./cursor-ripgrep-path.js";
5
+ import { ensureCursorRipgrepPath, ensureCursorTreeSitterVendorDir } from "./cursor-sdk-platform-package.js";
6
6
  import { installCursorSdkOutputFilter, suppressCursorSdkOutput } from "./cursor-sdk-output-filter.js";
7
7
  import {
8
8
  acquireSessionCursorAgent,
@@ -31,33 +31,21 @@ import { resolveEffectiveCursorConfig } from "./cursor-runtime-state.js";
31
31
  import { buildCursorBridgeExcludeToolNames, type CursorResolvedSdkConfig } from "./cursor-config.js";
32
32
  import { buildCursorModelSelection } from "./model-discovery.js";
33
33
  import { getEffectiveCursorSettingSources } from "./cursor-setting-sources.js";
34
- import {
35
- formatCursorCloudPreflightError,
36
- buildCursorCloudAgentOptions,
37
- preflightCursorCloudRuntime,
38
- } from "./cursor-cloud-options.js";
39
- import { inspectCursorCloudLocalState } from "./cursor-cloud-local-state.js";
40
- import { getCursorSessionName, getCursorSessionProjectTrusted } from "./cursor-session-scope.js";
34
+ import { getCursorSessionProjectTrusted } from "./cursor-session-scope.js";
41
35
  import { resolveCursorPiToolBridgeEnabled } from "./cursor-pi-tool-bridge-env.js";
42
36
  import {
43
37
  buildCursorToolManifestText,
44
38
  resolveCursorToolManifestEnabled,
45
39
  } from "./cursor-tool-manifest.js";
46
40
  import { isCursorNativeToolDisplayRuntimeEnabled } from "./cursor-native-tool-display-state.js";
47
- import {
48
- createCursorCloudLifecyclePersistenceError,
49
- recordCursorCloudLifecycleSafely,
50
- } from "./cursor-cloud-lifecycle.js";
51
41
  import { MISSING_CURSOR_API_KEY_MESSAGE } from "./cursor-provider-errors.js";
52
42
  import { CursorSdkTurnCoordinator } from "./cursor-provider-turn-coordinator.js";
53
43
  import { resolveCursorApiKey } from "./cursor-api-key.js";
54
44
  import { loadCursorSdk } from "./cursor-sdk-runtime.js";
55
45
  import type {
56
- CloudCursorProviderTurnPrepareResult,
57
46
  CursorProviderTurnLifecycle,
58
47
  CursorProviderTurnPrepareResult,
59
48
  CursorProviderTurnRunnerParams,
60
- LocalCursorProviderTurnPrepareResult,
61
49
  } from "./cursor-provider-turn-types.js";
62
50
  import type { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
63
51
  import type { SessionCursorAgentLease } from "./cursor-session-agent.js";
@@ -78,32 +66,10 @@ interface PrepareCursorProviderTurnContext extends PrepareCursorProviderTurnPara
78
66
  fastEnabled: boolean | undefined;
79
67
  }
80
68
 
81
- function buildCursorCloudPromptContext(context: Context, handoff: "fresh" | "bootstrap" | "never"): Context {
82
- if (handoff === "bootstrap") return context;
83
- for (let index = context.messages.length - 1; index >= 0; index -= 1) {
84
- const message = context.messages[index];
85
- if (message.role === "user") return { ...context, messages: [message] };
86
- }
87
- return { ...context, messages: context.messages.slice(-1) };
88
- }
89
-
90
- const CLOUD_SEND_PLAN: CursorSessionSendPlan = { mode: "bootstrap", resetAgent: false, reason: "initial" };
91
-
92
69
  export function resolveCursorProviderTurnConfig(cwd: string) {
93
70
  return resolveEffectiveCursorConfig({ cwd, projectTrusted: getCursorSessionProjectTrusted() });
94
71
  }
95
72
 
96
- function buildCloudCursorProviderTurnLifecycle(agent: SDKAgent): CursorProviderTurnLifecycle {
97
- return {
98
- trackRunCompletion: () => {},
99
- commitSend: () => {},
100
- abandon: async () => {},
101
- dispose: async () => {
102
- await agent[Symbol.asyncDispose]?.();
103
- },
104
- };
105
- }
106
-
107
73
  function buildLocalCursorProviderTurnLifecycle(
108
74
  lease: SessionCursorAgentLease,
109
75
  scopeKey: string,
@@ -116,129 +82,9 @@ function buildLocalCursorProviderTurnLifecycle(
116
82
  };
117
83
  }
118
84
 
119
- async function prepareCursorCloudProviderTurn(
120
- prepareParams: PrepareCursorProviderTurnContext,
121
- ): Promise<CloudCursorProviderTurnPrepareResult> {
122
- const { params, cwd, resolvedApiKey, sdkEventDebug, throwIfAborted, resolvedConfig, agentMode, selection, fastEnabled } = prepareParams;
123
- const { model, context, options } = params;
124
-
125
- let restoreCursorSdkOutputFilter: (() => void) | undefined;
126
- let cloudAgentForCleanup: SDKAgent | undefined;
127
- let completed = false;
128
-
129
- try {
130
- const preflight = preflightCursorCloudRuntime({
131
- resolvedConfig,
132
- localState: resolvedConfig.cloud.allowLocalState.value
133
- ? { insideGitRepo: false }
134
- : inspectCursorCloudLocalState(cwd, {
135
- repo: resolvedConfig.cloud.repo.value,
136
- branch: resolvedConfig.cloud.branch.value,
137
- }),
138
- hasPriorContext: context.messages.length > 1,
139
- });
140
- if (!preflight.ok) throw new Error(formatCursorCloudPreflightError(preflight));
141
- if (getPendingCursorLiveRun(context) || getActiveCursorLiveRunForCurrentScope()) {
142
- throw new Error("Cursor cloud runtime cannot start while a local Cursor live run is pending; finish or abort the local run, then retry.");
143
- }
144
-
145
- const { Agent } = await loadCursorSdk();
146
- restoreCursorSdkOutputFilter = installCursorSdkOutputFilter();
147
- const promptOptions = {
148
- ...getCursorPromptOptions(model),
149
- agentMode,
150
- includePiBridgeGuidance: false,
151
- includePiAskQuestionGuidance: false,
152
- };
153
- const prompt = buildCursorPrompt(
154
- buildCursorCloudPromptContext(context, resolvedConfig.cloud.contextHandoff.value),
155
- promptOptions,
156
- );
157
- const promptInputTokens = estimateCursorPromptTokens(prompt, promptOptions);
158
- const agent = await suppressCursorSdkOutput(() =>
159
- Agent.create(buildCursorCloudAgentOptions({
160
- apiKey: resolvedApiKey,
161
- modelSelection: selection,
162
- agentMode,
163
- resolvedConfig,
164
- name: getCursorSessionName(),
165
- })),
166
- );
167
- cloudAgentForCleanup = agent;
168
- if (!recordCursorCloudLifecycleSafely({ agentId: agent.agentId }, resolvedApiKey)) {
169
- throw createCursorCloudLifecyclePersistenceError(agent.agentId, "intent", undefined, resolvedApiKey);
170
- }
171
- sdkEventDebug?.recordProviderMeta({ runtime: "cloud", cloudAgentId: agent.agentId, phase: "agent_created" });
172
- throwIfAborted();
173
-
174
- const textDeltas: string[] = [];
175
- const nativeReplayId = createCursorNativeReplayId();
176
- const turnCoordinator = new CursorSdkTurnCoordinator({
177
- stream: params.stream,
178
- partial: params.partial,
179
- cwd,
180
- resolvedApiKey,
181
- useNativeToolReplay: false,
182
- nativeReplayId,
183
- textDeltas,
184
- debugRecorder: sdkEventDebug,
185
- });
186
- sdkEventDebug?.recordProviderMeta({
187
- runtime: "cloud",
188
- cloudAgentId: agent.agentId,
189
- model: {
190
- id: model.id,
191
- provider: model.provider,
192
- api: model.api,
193
- reasoning: options?.reasoning ?? "off",
194
- fastEnabled,
195
- selection,
196
- },
197
- contextHandoff: resolvedConfig.cloud.contextHandoff.value,
198
- sendPlan: CLOUD_SEND_PLAN,
199
- promptOptions,
200
- agentMode,
201
- localForce: false,
202
- });
203
-
204
- completed = true;
205
- cloudAgentForCleanup = undefined;
206
- return {
207
- runtimeTarget: "cloud",
208
- agent,
209
- cwd,
210
- payload: {
211
- text: prompt.text,
212
- images: prompt.images.length > 0 ? prompt.images : undefined,
213
- },
214
- meta: {
215
- sendPlan: CLOUD_SEND_PLAN,
216
- prompt,
217
- bootstrap: true,
218
- promptInputTokens,
219
- useNativeToolReplay: false,
220
- bridgeEnabled: false,
221
- nativeReplayId,
222
- agentMode,
223
- modelSelection: selection,
224
- },
225
- contextWindowAgentId: agent.agentId,
226
- textDeltas,
227
- restoreCursorSdkOutputFilter,
228
- lifecycle: buildCloudCursorProviderTurnLifecycle(agent),
229
- runtime: { kind: "direct", turnCoordinator },
230
- };
231
- } finally {
232
- if (!completed) {
233
- await cloudAgentForCleanup?.[Symbol.asyncDispose]?.().catch(() => {});
234
- restoreCursorSdkOutputFilter?.();
235
- }
236
- }
237
- }
238
-
239
85
  async function prepareCursorLocalProviderTurn(
240
86
  prepareParams: PrepareCursorProviderTurnContext,
241
- ): Promise<LocalCursorProviderTurnPrepareResult> {
87
+ ): Promise<CursorProviderTurnPrepareResult> {
242
88
  const { params, cwd, resolvedApiKey, sdkEventDebug, throwIfAborted, resolvedConfig, agentMode, selection, fastEnabled } = prepareParams;
243
89
  const { model, context, options } = params;
244
90
 
@@ -249,6 +95,7 @@ async function prepareCursorLocalProviderTurn(
249
95
 
250
96
  try {
251
97
  ensureCursorRipgrepPath();
98
+ ensureCursorTreeSitterVendorDir();
252
99
  const localSafety = {
253
100
  autoReview: resolvedConfig.local.autoReview.value,
254
101
  sandboxEnabled: resolvedConfig.local.sandboxEnabled.value,
@@ -398,7 +245,6 @@ async function prepareCursorLocalProviderTurn(
398
245
 
399
246
  completed = true;
400
247
  return {
401
- runtimeTarget: "local",
402
248
  agent,
403
249
  cwd,
404
250
  payload: sendPayload,
@@ -439,21 +285,18 @@ async function prepareCursorLocalProviderTurn(
439
285
  }
440
286
  }
441
287
 
442
- /** Resolves the runtime target from the caller-supplied snapshot and dispatches to the owning branch. */
443
288
  export async function prepareCursorProviderTurn(
444
289
  prepareParams: PrepareCursorProviderTurnParams,
445
290
  ): Promise<CursorProviderTurnPrepareResult> {
446
- const { params, resolvedConfig } = prepareParams;
291
+ const { params } = prepareParams;
447
292
  const { model, options } = params;
448
293
 
449
294
  const agentMode = getCursorProviderAgentModeOrThrow();
450
- const fastEnabled = resolvedConfig.runtime.value === "cloud" ? undefined : getEffectiveFastForModelId(model.id);
295
+ const fastEnabled = getEffectiveFastForModelId(model.id);
451
296
  const selection = buildCursorModelSelection(model.id, options?.reasoning ?? "off", fastEnabled);
452
297
  const context: PrepareCursorProviderTurnContext = { ...prepareParams, agentMode, selection, fastEnabled };
453
298
 
454
- return resolvedConfig.runtime.value === "cloud"
455
- ? prepareCursorCloudProviderTurn(context)
456
- : prepareCursorLocalProviderTurn(context);
299
+ return prepareCursorLocalProviderTurn(context);
457
300
  }
458
301
 
459
302
  export function requireCursorApiKey(options: SimpleStreamOptions | undefined): string {
@@ -3,7 +3,6 @@ import { drainExistingCursorLiveRunBeforeSend } from "./cursor-provider-live-run
3
3
  import { invalidateSessionAgent } from "./cursor-session-agent.js";
4
4
  import { getCursorSessionCwd, getCursorSessionScopeKey } from "./cursor-session-scope.js";
5
5
  import { installCursorSdkProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
6
- import type { CursorRuntime } from "./cursor-config.js";
7
6
  import { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
8
7
  import { awaitFinalizeCursorRunOutcome } from "./cursor-provider-turn-finalize.js";
9
8
  import {
@@ -22,24 +21,22 @@ import type {
22
21
  CursorProviderTurnRunnerParams,
23
22
  CursorProviderTurnSendResult,
24
23
  LiveCursorProviderTurnRuntime,
25
- LocalCursorProviderTurnPrepareResult,
26
24
  } from "./cursor-provider-turn-types.js";
27
25
 
28
26
  export type { CursorProviderTurnRunnerParams } from "./cursor-provider-turn-types.js";
29
27
 
30
- type LocalLivePreparedTurn = LocalCursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime };
28
+ type LivePreparedTurn = CursorProviderTurnPrepareResult & { runtime: LiveCursorProviderTurnRuntime };
31
29
 
32
- function requireLocalLivePreparedTurn(prepared: CursorProviderTurnPrepareResult): LocalLivePreparedTurn {
33
- if (prepared.runtimeTarget !== "local" || prepared.runtime.kind !== "live") {
34
- throw new Error("Cursor live run requires a local live prepared turn");
30
+ function requireLivePreparedTurn(prepared: CursorProviderTurnPrepareResult): LivePreparedTurn {
31
+ if (prepared.runtime.kind !== "live") {
32
+ throw new Error("Cursor live run requires a live prepared turn");
35
33
  }
36
- return prepared as LocalLivePreparedTurn;
34
+ return prepared as LivePreparedTurn;
37
35
  }
38
36
 
39
37
  export class CursorProviderTurnRunner {
40
38
  private sdkEventDebug: CursorSdkEventDebugSink | undefined;
41
39
  private resolvedApiKey: string | undefined;
42
- private runtimeTarget: CursorRuntime | undefined;
43
40
 
44
41
  constructor(private readonly params: CursorProviderTurnRunnerParams) {}
45
42
 
@@ -61,7 +58,6 @@ export class CursorProviderTurnRunner {
61
58
  sdkEventDebug: () => this.sdkEventDebug,
62
59
  sdkProcessErrorGuard,
63
60
  resolvedApiKey: () => this.resolvedApiKey,
64
- runtimeTarget: () => this.runtimeTarget,
65
61
  });
66
62
 
67
63
  try {
@@ -74,25 +70,16 @@ export class CursorProviderTurnRunner {
74
70
  });
75
71
  sdkEventDebugRef.current = this.sdkEventDebug;
76
72
  this.sdkEventDebug?.recordContextSnapshot(context);
77
- // Resolved once here, before any drain await, so the drain decision and the
78
- // prepare dispatch below always act on the same config snapshot.
79
73
  const resolvedConfig = resolveCursorProviderTurnConfig(cwd);
80
- this.runtimeTarget = resolvedConfig.runtime.value;
81
- if (resolvedConfig.runtime.value === "local") {
82
- // The observed local-executor closed-pipe EPIPE is contained only from this
83
- // turn's pre-send live-run drain through run completion; for live runs the
84
- // finalizer holds the guard until run.wait() settles. A hit marks
85
- // this scope's pooled agent transport dead so the next acquire recreates it.
86
- const localScopeKey = getCursorSessionScopeKey();
87
- sdkProcessErrorGuard.containLocalTransportClosedPipe(() =>
88
- invalidateSessionAgent(localScopeKey, { deadTransport: true }),
89
- );
90
- if (
91
- (await drainExistingCursorLiveRunBeforeSend(stream, partial, model, context, options?.signal, this.sdkEventDebug)) ===
92
- "stream_ended"
93
- ) {
94
- return;
95
- }
74
+ const localScopeKey = getCursorSessionScopeKey();
75
+ sdkProcessErrorGuard.containLocalTransportClosedPipe(() =>
76
+ invalidateSessionAgent(localScopeKey, { deadTransport: true }),
77
+ );
78
+ if (
79
+ (await drainExistingCursorLiveRunBeforeSend(stream, partial, model, context, options?.signal, this.sdkEventDebug)) ===
80
+ "stream_ended"
81
+ ) {
82
+ return;
96
83
  }
97
84
  this.throwIfAborted();
98
85
 
@@ -112,12 +99,11 @@ export class CursorProviderTurnRunner {
112
99
  sdkEventDebug: this.sdkEventDebug,
113
100
  sdkProcessErrorGuard,
114
101
  throwIfAborted: () => this.throwIfAborted(),
115
- resolvedApiKey: this.resolvedApiKey,
116
102
  });
117
103
  const { send } = sendResult;
118
104
 
119
105
  if (prepared.runtime.kind === "live") {
120
- const livePrepared = requireLocalLivePreparedTurn(prepared);
106
+ const livePrepared = requireLivePreparedTurn(prepared);
121
107
  liveCompletion = runFinalizer.startLiveRunCompletion({
122
108
  send,
123
109
  prepared: livePrepared,
@@ -152,7 +138,6 @@ export class CursorProviderTurnRunner {
152
138
  kind: "direct",
153
139
  prepared,
154
140
  outcome: finalized.outcome,
155
- displayOnlyTraceBlock: finalized.displayOnlyTraceBlock,
156
141
  });
157
142
  } catch (error) {
158
143
  await runFinalizer.applyTerminalEvent({ kind: "error", prepared, error });
@@ -167,7 +152,6 @@ export class CursorProviderTurnRunner {
167
152
  sdkEventDebug: () => this.sdkEventDebug,
168
153
  sdkProcessErrorGuard: installCursorSdkProcessErrorGuard(),
169
154
  resolvedApiKey: () => this.resolvedApiKey,
170
- runtimeTarget: () => this.runtimeTarget,
171
155
  });
172
156
  await runFinalizer.applyTerminalEvent({ kind: "error", prepared: undefined, error });
173
157
  await runFinalizer.cleanup(undefined, undefined, undefined);
@@ -1,9 +1,5 @@
1
1
  import type { SendOptions } from "@cursor/sdk";
2
2
  import { countCursorAgentMessages } from "./cursor-agent-message-web-tools.js";
3
- import {
4
- createCursorCloudLifecyclePersistenceError,
5
- recordCursorCloudLifecycleSafely,
6
- } from "./cursor-cloud-lifecycle.js";
7
3
  import { CursorLiveRunAbortError } from "./cursor-live-run-coordinator.js";
8
4
  import { cursorLiveRuns } from "./cursor-provider-live-run-drain.js";
9
5
  import { consumeCursorLocalForceOverride } from "./cursor-runtime-state.js";
@@ -22,25 +18,6 @@ export interface SendCursorProviderTurnParams {
22
18
  sdkEventDebug: CursorSdkEventDebugSink | undefined;
23
19
  sdkProcessErrorGuard: ReturnType<typeof installCursorSdkProcessErrorGuard>;
24
20
  throwIfAborted: () => void;
25
- resolvedApiKey?: string;
26
- }
27
-
28
- const CLOUD_LEDGER_CANCEL_TIMEOUT_MS = 5000;
29
-
30
- async function requestBoundedCloudRunCancellation(run: Awaited<ReturnType<CursorProviderTurnPrepareResult["agent"]["send"]>>): Promise<boolean> {
31
- let timer: ReturnType<typeof setTimeout> | undefined;
32
- const timeout = new Promise<false>((resolve) => {
33
- timer = setTimeout(() => resolve(false), CLOUD_LEDGER_CANCEL_TIMEOUT_MS);
34
- timer.unref?.();
35
- });
36
- try {
37
- return await Promise.race([
38
- Promise.resolve().then(() => run.cancel()).then(() => true, () => false),
39
- timeout,
40
- ]);
41
- } finally {
42
- if (timer) clearTimeout(timer);
43
- }
44
21
  }
45
22
 
46
23
  function recordDebug(action: () => void): void {
@@ -52,7 +29,7 @@ function recordDebug(action: () => void): void {
52
29
  }
53
30
 
54
31
  export async function sendCursorProviderTurn(sendParams: SendCursorProviderTurnParams): Promise<CursorProviderTurnSendResult> {
55
- const { params, prepared, sdkEventDebug, sdkProcessErrorGuard, throwIfAborted, resolvedApiKey } = sendParams;
32
+ const { params, prepared, sdkEventDebug, sdkProcessErrorGuard, throwIfAborted } = sendParams;
56
33
  const { options } = params;
57
34
  const { agent, cwd, payload, meta, runtime } = prepared;
58
35
  const { turnCoordinator, liveRun } = runtime;
@@ -75,12 +52,10 @@ export async function sendCursorProviderTurn(sendParams: SendCursorProviderTurnP
75
52
  abortRegistration?.signal.addEventListener("abort", abortListener, { once: true });
76
53
  throwIfAborted();
77
54
  let cursorAgentMessageOffset: number | undefined;
78
- if (prepared.runtimeTarget === "local") {
79
- try {
80
- cursorAgentMessageOffset = await countCursorAgentMessages(agent.agentId, cwd, prepared.sessionAgentLease.store);
81
- } catch (error) {
82
- recordDebug(() => sdkEventDebug?.recordError("cursor_agent_message_count", error));
83
- }
55
+ try {
56
+ cursorAgentMessageOffset = await countCursorAgentMessages(agent.agentId, cwd, prepared.sessionAgentLease.store);
57
+ } catch (error) {
58
+ recordDebug(() => sdkEventDebug?.recordError("cursor_agent_message_count", error));
84
59
  }
85
60
  throwIfAborted();
86
61
  recordDebug(() => sdkEventDebug?.recordSendMeta({
@@ -111,20 +86,14 @@ export async function sendCursorProviderTurn(sendParams: SendCursorProviderTurnP
111
86
  },
112
87
  };
113
88
  throwIfAborted();
114
- if (prepared.runtimeTarget === "local" && consumeCursorLocalForceOverride(prepared.localForce)) {
89
+ if (consumeCursorLocalForceOverride(prepared.localForce)) {
115
90
  sendOptions.local = { force: true };
116
91
  }
117
92
  const runPromise = agent.send(payload, sendOptions);
118
93
  // Record at send initiation (promise created), including later reject/cancel paths.
119
- if (prepared.runtimeTarget === "local") {
120
- recordCursorSessionAgentLineage(agent.agentId);
121
- }
94
+ recordCursorSessionAgentLineage(agent.agentId);
122
95
  const run = await runPromise;
123
96
  sdkRun = run;
124
- if (prepared.runtimeTarget === "cloud" && !recordCursorCloudLifecycleSafely({ agentId: run.agentId, runId: run.id }, resolvedApiKey)) {
125
- const cancellationConfirmed = await requestBoundedCloudRunCancellation(run);
126
- throw createCursorCloudLifecyclePersistenceError(run.agentId, "run", cancellationConfirmed, resolvedApiKey);
127
- }
128
97
  recordDebug(() => sdkEventDebug?.recordRunMeta({
129
98
  runId: run.id,
130
99
  requestId: run.requestId,