@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.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.
Files changed (91) hide show
  1. package/CHANGELOG.md +22 -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-extension-factory-guard.js +31 -0
  7. package/dist/cursor-pi-tool-bridge-server.js +3 -0
  8. package/dist/cursor-pi-tool-bridge.js +5 -0
  9. package/dist/cursor-provider-errors.js +3 -58
  10. package/dist/cursor-provider-live-run-drain.js +0 -3
  11. package/dist/cursor-provider-run-finalizer.js +4 -7
  12. package/dist/cursor-provider-run-outcome.js +1 -1
  13. package/dist/cursor-provider-turn-finalize.js +3 -55
  14. package/dist/cursor-provider-turn-prepare.js +8 -144
  15. package/dist/cursor-provider-turn-runner.js +9 -23
  16. package/dist/cursor-provider-turn-send.js +8 -35
  17. package/dist/cursor-runtime-state.js +6 -268
  18. package/dist/cursor-sdk-billed-usage.js +3 -18
  19. package/dist/cursor-sdk-platform-package.js +88 -0
  20. package/dist/cursor-session-agent.js +18 -14
  21. package/dist/cursor-skill-tool.js +12 -22
  22. package/dist/cursor-state.js +5 -8
  23. package/dist/cursor-usage-accounting.js +1 -1
  24. package/dist/index.js +65 -49
  25. package/docs/cursor-dogfood-checklist.md +4 -4
  26. package/docs/cursor-live-smoke-checklist.md +24 -24
  27. package/docs/cursor-model-ux-spec.md +27 -30
  28. package/docs/cursor-native-tool-replay.md +4 -4
  29. package/docs/cursor-native-tool-visual-audit.md +10 -10
  30. package/docs/cursor-testing-lessons.md +38 -16
  31. package/docs/cursor-tool-surfaces.md +2 -4
  32. package/docs/platform-smoke-implementation.md +5 -5
  33. package/docs/platform-smoke.md +28 -73
  34. package/node_modules/cross-spawn/node_modules/which/CHANGELOG.md +166 -0
  35. package/package.json +3 -17
  36. package/platform-smoke.config.mjs +2 -1
  37. package/scripts/lib/cursor-visual-render.mjs +12 -2
  38. package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
  39. package/scripts/platform-smoke/card-detect.mjs +1 -1
  40. package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
  41. package/scripts/platform-smoke/scenarios.mjs +1 -1
  42. package/scripts/platform-smoke/targets.mjs +14 -5
  43. package/scripts/visual-tui-smoke-self-test.mjs +9 -33
  44. package/scripts/visual-tui-smoke.mjs +54 -11
  45. package/src/cursor-agents-context-registration.ts +0 -5
  46. package/src/cursor-agents-context.ts +1 -3
  47. package/src/cursor-config.ts +8 -379
  48. package/src/cursor-extension-factory-guard.ts +57 -0
  49. package/src/cursor-pi-tool-bridge-server.ts +4 -0
  50. package/src/cursor-pi-tool-bridge.ts +5 -0
  51. package/src/cursor-provider-errors.ts +2 -62
  52. package/src/cursor-provider-live-run-drain.ts +0 -3
  53. package/src/cursor-provider-run-finalizer.ts +4 -12
  54. package/src/cursor-provider-run-outcome.ts +0 -3
  55. package/src/cursor-provider-turn-finalize.ts +3 -61
  56. package/src/cursor-provider-turn-prepare.ts +8 -165
  57. package/src/cursor-provider-turn-runner.ts +15 -31
  58. package/src/cursor-provider-turn-send.ts +7 -38
  59. package/src/cursor-provider-turn-types.ts +9 -30
  60. package/src/cursor-runtime-state.ts +6 -345
  61. package/src/cursor-sdk-billed-usage.ts +3 -24
  62. package/src/cursor-sdk-platform-package.ts +106 -0
  63. package/src/cursor-session-agent.ts +16 -12
  64. package/src/cursor-skill-tool.ts +10 -26
  65. package/src/cursor-state.ts +5 -10
  66. package/src/cursor-usage-accounting.ts +1 -3
  67. package/src/index.ts +70 -49
  68. package/dist/cursor-cloud-lifecycle.js +0 -650
  69. package/dist/cursor-cloud-local-state.js +0 -460
  70. package/dist/cursor-cloud-options.js +0 -145
  71. package/dist/cursor-cloud-reporting.js +0 -222
  72. package/dist/cursor-ripgrep-path.js +0 -27
  73. package/scripts/cloud-runtime-smoke.d.mts +0 -42
  74. package/scripts/cloud-runtime-smoke.mjs +0 -623
  75. package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
  76. package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
  77. package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
  78. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
  79. package/scripts/lib/cloud-smoke-github.d.mts +0 -78
  80. package/scripts/lib/cloud-smoke-github.mjs +0 -331
  81. package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
  82. package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
  83. package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
  84. package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
  85. package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
  86. package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
  87. package/src/cursor-cloud-lifecycle.ts +0 -733
  88. package/src/cursor-cloud-local-state.ts +0 -536
  89. package/src/cursor-cloud-options.ts +0 -182
  90. package/src/cursor-cloud-reporting.ts +0 -267
  91. package/src/cursor-ripgrep-path.ts +0 -32
@@ -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,
@@ -48,13 +48,7 @@ interface CursorProviderTurnRuntimeBase {
48
48
  billedTurnUsage?: CursorSdkTurnUsage;
49
49
  }
50
50
 
51
- /**
52
- * Runtime-agnostic lifecycle operations for a prepared turn.
53
- *
54
- * Local implementations delegate to the session agent lease; cloud
55
- * implementations no-op the local-only operations (commitSend,
56
- * trackRunCompletion, abandon) and dispose the cloud agent instead.
57
- */
51
+ /** Lifecycle operations for a prepared local turn, delegated to the session agent lease. */
58
52
  export interface CursorProviderTurnLifecycle {
59
53
  trackRunCompletion(completion: Promise<unknown>): void;
60
54
  commitSend(context: Context, bootstrapped: boolean): void;
@@ -74,7 +68,13 @@ export interface LiveCursorProviderTurnRuntime extends CursorProviderTurnRuntime
74
68
 
75
69
  export type CursorProviderTurnRuntime = DirectCursorProviderTurnRuntime | LiveCursorProviderTurnRuntime;
76
70
 
77
- interface CursorProviderTurnPrepareResultBase {
71
+ /**
72
+ * Single owned model for a prepared local provider turn.
73
+ *
74
+ * Send, finalize, and cleanup phases receive this immutable object instead of
75
+ * keeping parallel liveRun/turnCoordinator/resource bags in sync by convention.
76
+ */
77
+ export interface CursorProviderTurnPrepareResult {
78
78
  agent: SDKAgent;
79
79
  cwd: string;
80
80
  payload: CursorProviderTurnSendPayload;
@@ -83,33 +83,12 @@ interface CursorProviderTurnPrepareResultBase {
83
83
  textDeltas: string[];
84
84
  restoreCursorSdkOutputFilter: () => void;
85
85
  lifecycle: CursorProviderTurnLifecycle;
86
- }
87
-
88
- export interface LocalCursorProviderTurnPrepareResult extends CursorProviderTurnPrepareResultBase {
89
- runtimeTarget: "local";
90
- runtime: CursorProviderTurnRuntime;
91
86
  sessionAgentScopeKey: string;
92
87
  sessionAgentLease: SessionCursorAgentLease;
93
88
  localForce: CursorResolvedSetting<boolean>;
89
+ runtime: CursorProviderTurnRuntime;
94
90
  }
95
91
 
96
- export interface CloudCursorProviderTurnPrepareResult extends CursorProviderTurnPrepareResultBase {
97
- runtimeTarget: "cloud";
98
- runtime: DirectCursorProviderTurnRuntime;
99
- sessionAgentScopeKey?: undefined;
100
- sessionAgentLease?: undefined;
101
- }
102
-
103
- /**
104
- * Single owned model for a prepared provider turn.
105
- *
106
- * Send, finalize, and cleanup phases receive this immutable object instead of
107
- * keeping parallel liveRun/turnCoordinator/resource bags in sync by convention.
108
- */
109
- export type CursorProviderTurnPrepareResult =
110
- | LocalCursorProviderTurnPrepareResult
111
- | CloudCursorProviderTurnPrepareResult;
112
-
113
92
  export interface CursorProviderTurnSend {
114
93
  run: Awaited<ReturnType<SDKAgent["send"]>>;
115
94
  cursorAgentMessageOffset: number | undefined;