pi-cursor-sdk 0.2.0 → 0.3.7

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 (177) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +55 -51
  3. package/dist/bundled-context-windows.js +39 -0
  4. package/dist/context-window-cache.js +92 -0
  5. package/dist/context.js +353 -0
  6. package/dist/cursor-active-tools.js +3 -0
  7. package/dist/cursor-agent-message-web-tools.js +165 -0
  8. package/dist/cursor-agents-context-registration.js +17 -0
  9. package/dist/cursor-agents-context.js +127 -0
  10. package/dist/cursor-api-key.js +34 -0
  11. package/dist/cursor-bridge-contract.js +27 -0
  12. package/dist/cursor-cloud-lifecycle.js +650 -0
  13. package/dist/cursor-cloud-local-state.js +460 -0
  14. package/dist/cursor-cloud-options.js +145 -0
  15. package/dist/cursor-cloud-reporting.js +222 -0
  16. package/dist/cursor-compact-tool-summary.js +75 -0
  17. package/dist/cursor-config.js +613 -0
  18. package/dist/cursor-context-tools.js +6 -0
  19. package/dist/cursor-display-only-trace.js +11 -0
  20. package/dist/cursor-display-text.js +18 -0
  21. package/dist/cursor-durable-fs.js +53 -0
  22. package/dist/cursor-edit-diff.js +13 -0
  23. package/dist/cursor-env-boolean.js +19 -0
  24. package/dist/cursor-fallback-models.generated.js +7760 -0
  25. package/dist/cursor-fallback-warning.js +15 -0
  26. package/dist/cursor-http1.js +45 -0
  27. package/dist/cursor-incomplete-tool-visibility.js +83 -0
  28. package/dist/cursor-live-run-accounting.js +55 -0
  29. package/dist/cursor-live-run-coordinator.js +409 -0
  30. package/dist/cursor-mcp-timeout-override.js +116 -0
  31. package/dist/cursor-model-lifecycle.js +32 -0
  32. package/dist/cursor-model.js +5 -0
  33. package/dist/cursor-native-replay-routing.js +35 -0
  34. package/dist/cursor-native-replay-trace.js +28 -0
  35. package/dist/cursor-native-tool-display-registration.js +102 -0
  36. package/dist/cursor-native-tool-display-replay.js +428 -0
  37. package/dist/cursor-native-tool-display-state.js +70 -0
  38. package/dist/cursor-native-tool-display-tools.js +123 -0
  39. package/dist/cursor-native-tool-names.js +11 -0
  40. package/dist/cursor-partial-content-emitter.js +130 -0
  41. package/dist/cursor-pi-context.js +30 -0
  42. package/dist/cursor-pi-tool-bridge-abort.js +114 -0
  43. package/dist/cursor-pi-tool-bridge-constants.js +6 -0
  44. package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
  45. package/dist/cursor-pi-tool-bridge-env.js +18 -0
  46. package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
  47. package/dist/cursor-pi-tool-bridge-run.js +355 -0
  48. package/dist/cursor-pi-tool-bridge-server.js +163 -0
  49. package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
  50. package/dist/cursor-pi-tool-bridge-types.js +1 -0
  51. package/dist/cursor-pi-tool-bridge.js +123 -0
  52. package/dist/cursor-provider-errors.js +311 -0
  53. package/dist/cursor-provider-lazy.js +39 -0
  54. package/dist/cursor-provider-live-run-drain.js +420 -0
  55. package/dist/cursor-provider-overflow.js +90 -0
  56. package/dist/cursor-provider-run-finalizer.js +176 -0
  57. package/dist/cursor-provider-run-outcome.js +76 -0
  58. package/dist/cursor-provider-turn-coordinator.js +293 -0
  59. package/dist/cursor-provider-turn-display-router.js +158 -0
  60. package/dist/cursor-provider-turn-emit.js +41 -0
  61. package/dist/cursor-provider-turn-finalize.js +154 -0
  62. package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
  63. package/dist/cursor-provider-turn-prepare.js +379 -0
  64. package/dist/cursor-provider-turn-runner.js +146 -0
  65. package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
  66. package/dist/cursor-provider-turn-send.js +138 -0
  67. package/dist/cursor-provider-turn-shell-output.js +117 -0
  68. package/dist/cursor-provider-turn-tool-ledger.js +99 -0
  69. package/dist/cursor-provider-turn-types.js +1 -0
  70. package/dist/cursor-provider.js +72 -0
  71. package/dist/cursor-question-tool.js +194 -0
  72. package/dist/cursor-record-utils.js +61 -0
  73. package/dist/cursor-replay-activity-builders.js +114 -0
  74. package/dist/cursor-replay-source-names.js +27 -0
  75. package/dist/cursor-replay-summary-args.js +105 -0
  76. package/dist/cursor-replay-tool-details.js +167 -0
  77. package/dist/cursor-ripgrep-path.js +27 -0
  78. package/dist/cursor-run-final-text.js +63 -0
  79. package/dist/cursor-runtime-state.js +380 -0
  80. package/dist/cursor-sdk-billed-usage.js +86 -0
  81. package/dist/cursor-sdk-event-debug-constants.js +33 -0
  82. package/dist/cursor-sdk-event-debug-session.js +107 -0
  83. package/dist/cursor-sdk-event-debug.js +461 -0
  84. package/dist/cursor-sdk-output-filter.js +1 -0
  85. package/dist/cursor-sdk-process-error-guard.js +221 -0
  86. package/dist/cursor-sdk-runtime.js +3 -0
  87. package/dist/cursor-sensitive-text.js +23 -0
  88. package/dist/cursor-session-agent-cleanup.js +311 -0
  89. package/dist/cursor-session-agent-lifecycle.js +32 -0
  90. package/dist/cursor-session-agent-lineage.js +103 -0
  91. package/dist/cursor-session-agent-resume.js +417 -0
  92. package/dist/cursor-session-agent.js +507 -0
  93. package/dist/cursor-session-compaction-prep.js +21 -0
  94. package/dist/cursor-session-scope.js +113 -0
  95. package/dist/cursor-session-send-policy.js +18 -0
  96. package/dist/cursor-session-store.js +105 -0
  97. package/dist/cursor-session-turn-queue.js +50 -0
  98. package/dist/cursor-setting-sources.js +15 -0
  99. package/dist/cursor-skill-tool.js +230 -0
  100. package/dist/cursor-state.js +519 -0
  101. package/dist/cursor-task-presentation.js +59 -0
  102. package/dist/cursor-tool-lifecycle.js +94 -0
  103. package/dist/cursor-tool-manifest.js +34 -0
  104. package/dist/cursor-tool-presentation-registry.js +305 -0
  105. package/dist/cursor-tool-result-display-readers.js +158 -0
  106. package/dist/cursor-tool-transcript.js +32 -0
  107. package/dist/cursor-tool-visibility.js +28 -0
  108. package/dist/cursor-transcript-tool-formatters.js +618 -0
  109. package/dist/cursor-transcript-tool-specs.js +284 -0
  110. package/dist/cursor-transcript-utils.js +170 -0
  111. package/dist/cursor-usage-accounting.js +166 -0
  112. package/dist/cursor-web-tool-activity.js +23 -0
  113. package/dist/cursor-web-tool-args.js +12 -0
  114. package/dist/index.js +82 -0
  115. package/dist/model-discovery.js +305 -0
  116. package/dist/model-list-cache.js +156 -0
  117. package/docs/cursor-dogfood-checklist.md +2 -1
  118. package/docs/cursor-live-smoke-checklist.md +13 -12
  119. package/docs/cursor-model-ux-spec.md +27 -6
  120. package/docs/cursor-native-tool-replay.md +13 -13
  121. package/docs/cursor-native-tool-visual-audit.md +6 -3
  122. package/docs/cursor-testing-lessons.md +14 -8
  123. package/docs/cursor-tool-surfaces.md +5 -5
  124. package/docs/platform-smoke.md +3 -3
  125. package/package.json +19 -7
  126. package/platform-smoke.config.mjs +1 -1
  127. package/scripts/build.mjs +126 -0
  128. package/scripts/cloud-runtime-smoke.mjs +3 -1
  129. package/scripts/debug-provider-events.mjs +3 -1
  130. package/scripts/debug-sdk-events.mjs +1 -1
  131. package/scripts/isolated-cursor-smoke.sh +5 -4
  132. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
  133. package/scripts/lib/cursor-visual-render.mjs +1 -1
  134. package/scripts/lib/ensure-built.mjs +16 -0
  135. package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
  136. package/scripts/local-resume-smoke.mjs +3 -1
  137. package/scripts/platform-smoke/card-detect.mjs +1 -1
  138. package/scripts/platform-smoke/live-suite-runner.mjs +1 -1
  139. package/scripts/platform-smoke/render-ansi.mjs +1 -1
  140. package/scripts/platform-smoke/targets.mjs +2 -2
  141. package/scripts/prepare.mjs +102 -0
  142. package/scripts/steering-rpc-smoke.mjs +4 -2
  143. package/scripts/tmux-live-smoke.sh +11 -11
  144. package/scripts/visual-tui-smoke-self-test.mjs +4 -1
  145. package/scripts/visual-tui-smoke.mjs +51 -7
  146. package/src/bundled-context-windows.ts +4 -1
  147. package/src/context.ts +27 -4
  148. package/src/cursor-agents-context-registration.ts +2 -2
  149. package/src/cursor-agents-context.ts +24 -10
  150. package/src/cursor-api-key.ts +5 -4
  151. package/src/cursor-cloud-reporting.ts +23 -2
  152. package/src/cursor-context-tools.ts +3 -1
  153. package/src/cursor-fallback-models.generated.ts +592 -204
  154. package/src/cursor-live-run-coordinator.ts +11 -6
  155. package/src/cursor-native-tool-display-registration.ts +10 -11
  156. package/src/cursor-partial-content-emitter.ts +13 -0
  157. package/src/cursor-pi-context.ts +44 -0
  158. package/src/cursor-provider-errors.ts +1 -1
  159. package/src/cursor-provider-lazy.ts +5 -4
  160. package/src/cursor-provider-live-run-drain.ts +14 -9
  161. package/src/cursor-provider-run-finalizer.ts +1 -0
  162. package/src/cursor-provider-turn-coordinator.ts +15 -0
  163. package/src/cursor-provider-turn-emit.ts +6 -0
  164. package/src/cursor-provider-turn-finalize.ts +12 -0
  165. package/src/cursor-provider-turn-prepare.ts +10 -5
  166. package/src/cursor-provider-turn-types.ts +2 -0
  167. package/src/cursor-sdk-billed-usage.ts +107 -0
  168. package/src/cursor-sdk-process-error-guard.ts +6 -4
  169. package/src/cursor-session-agent-lifecycle.ts +8 -9
  170. package/src/cursor-session-agent-resume.ts +23 -0
  171. package/src/cursor-session-compaction-prep.ts +4 -0
  172. package/src/cursor-skill-tool.ts +1 -1
  173. package/src/cursor-tool-manifest.ts +1 -1
  174. package/src/cursor-usage-accounting.ts +70 -9
  175. package/src/index.ts +1 -1
  176. package/tsconfig.build.json +8 -0
  177. package/tsconfig.json +16 -0
package/src/context.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { getCursorConversationMessages, resolveCursorPiContext } from "./cursor-pi-context.js";
2
3
  import type { Context, Message, ToolCall } from "@earendil-works/pi-ai";
3
4
  import { convertToLlm } from "@earendil-works/pi-coding-agent";
4
5
  import type { AgentModeOption, SDKImage } from "@cursor/sdk";
@@ -85,7 +86,7 @@ function getCursorBootstrapTailSections(
85
86
  }
86
87
 
87
88
  function normalizePiContextMessages(messages: Context["messages"]): Message[] {
88
- return convertToLlm(messages as Parameters<typeof convertToLlm>[0]);
89
+ return convertToLlm(getCursorConversationMessages({ messages }) as Parameters<typeof convertToLlm>[0]);
89
90
  }
90
91
 
91
92
  function isTextBlock(block: { type: string }): block is { type: "text"; text: string } {
@@ -137,6 +138,15 @@ function formatToolCall(toolCall: ToolCall): string {
137
138
 
138
139
  function sanitizeSystemPromptForCursor(systemPrompt: string): string {
139
140
  let sanitized = systemPrompt;
141
+ // Transcript-era Pi wraps its built-in tool catalog/rules in XML sections.
142
+ sanitized = sanitized.replace(
143
+ /<tools>\n[\s\S]*?\n\nIn addition to the tools above, you may have access to other custom tools depending on the project\.\n<\/tools>/g,
144
+ "Pi tool catalog omitted: Cursor can call only Cursor SDK tools exposed in this run.",
145
+ );
146
+ sanitized = sanitized.replace(
147
+ /<rules>\n[\s\S]*?\n<\/rules>\n\n(?=<docs>\nPi documentation )/g,
148
+ "<rules>\n- Be concise in your responses.\n- Show file paths clearly when working with files.\n</rules>\n\n",
149
+ );
140
150
  sanitized = sanitized.replace(
141
151
  /Available tools:\n[\s\S]*?\n\nIn addition to the tools above, you may have access to other custom tools depending on the project\.\n\n/g,
142
152
  "Pi tool catalog omitted: Cursor can call only Cursor SDK tools exposed in this run.\n\n",
@@ -279,12 +289,24 @@ function serializeMessageForFingerprint(message: Message, index: number): string
279
289
  return hashCursorContextValue(
280
290
  `toolResult:${message.timestamp ?? index}:${message.toolCallId}:${message.toolName}:${JSON.stringify(message.content)}:${message.isError === true}`,
281
291
  );
292
+ default:
293
+ // System messages are handled by serializeRawPiMessageForFingerprint.
294
+ throw new Error("Unsupported Pi message role in Cursor context fingerprint.");
282
295
  }
283
296
  }
284
297
 
285
298
  function serializeRawPiMessageForFingerprint(message: Context["messages"][number], index: number): string {
286
299
  const role = (message as { role?: string }).role;
287
300
  switch (role) {
301
+ case "system": {
302
+ const entry = message as {
303
+ content: unknown; sections?: unknown; toolsAdded?: unknown; toolsRemoved?: unknown;
304
+ };
305
+ return hashCursorContextValue(JSON.stringify({
306
+ role, content: entry.content, sections: entry.sections,
307
+ toolsAdded: entry.toolsAdded, toolsRemoved: entry.toolsRemoved,
308
+ }));
309
+ }
288
310
  case "branchSummary": {
289
311
  const entry = message as { summary?: string; fromId?: string; timestamp?: number };
290
312
  return hashCursorContextValue(
@@ -337,7 +359,7 @@ function parseCursorContextFingerprint(fingerprint: string): CursorContextFinger
337
359
 
338
360
  export function computeCursorContextFingerprint(context: Context): string {
339
361
  const payload: CursorContextFingerprintPayload = {
340
- systemHash: hashCursorContextValue(context.systemPrompt ?? ""),
362
+ systemHash: hashCursorContextValue(JSON.stringify(resolveCursorPiContext(context))),
341
363
  messageHashes: context.messages.map((message, index) => serializeRawPiMessageForFingerprint(message, index)),
342
364
  };
343
365
  return JSON.stringify(payload);
@@ -412,8 +434,9 @@ export function buildCursorPrompt(context: Context, options: CursorPromptOptions
412
434
  sectionsBeforeMessages.push(options.toolManifest);
413
435
  }
414
436
 
415
- if (context.systemPrompt) {
416
- sectionsBeforeMessages.push(`System instructions from pi:\n${sanitizeSystemPromptForCursor(context.systemPrompt)}`);
437
+ const { systemPrompt } = resolveCursorPiContext(context);
438
+ if (systemPrompt) {
439
+ sectionsBeforeMessages.push(`System instructions from pi:\n${sanitizeSystemPromptForCursor(systemPrompt)}`);
417
440
  }
418
441
 
419
442
  const messages = normalizePiContextMessages(context.messages);
@@ -1,14 +1,14 @@
1
1
  import { isCursorModel } from "./cursor-model.js";
2
2
  import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
3
3
  import { resolveEffectiveCursorConfigForContext } from "./cursor-runtime-state.js";
4
+ import { resolveCursorFacingSystemPrompt } from "./cursor-agents-context.js";
4
5
 
5
6
  export type CursorAgentsContextExtensionApi = CursorModelLifecycleExtensionApi;
6
7
 
7
8
  export function registerCursorAgentsContextDedup(pi: CursorAgentsContextExtensionApi): void {
8
9
  registerCursorModelLifecycle(pi, {
9
- beforeAgentStart: async (event, ctx) => {
10
+ beforeAgentStart: (event, ctx) => {
10
11
  if (!isCursorModel(ctx.model)) return undefined;
11
- const { resolveCursorFacingSystemPrompt } = await import("./cursor-agents-context.js");
12
12
  const runtime = resolveEffectiveCursorConfigForContext(ctx).runtime.value;
13
13
  const resolved = resolveCursorFacingSystemPrompt(
14
14
  event.systemPrompt,
@@ -12,8 +12,6 @@ import {
12
12
  } from "./cursor-setting-sources.js";
13
13
  import type { SettingSource } from "@cursor/sdk";
14
14
  import type { CursorRuntime } from "./cursor-config.js";
15
- export { registerCursorAgentsContextDedup, type CursorAgentsContextExtensionApi } from "./cursor-agents-context-registration.js";
16
-
17
15
  export const CURSOR_PRESERVE_PI_AGENTS_MD_ENV = "PI_CURSOR_PRESERVE_PI_AGENTS_MD";
18
16
 
19
17
  /** Opening tag prefix pi `buildSystemPrompt()` uses for each context file (path attribute only). */
@@ -116,9 +114,21 @@ export function serializePiProjectInstructionsBlock(file: PiAgentsContextFile):
116
114
  return `${PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX}${file.path}">\n${file.content}\n${PI_PROJECT_INSTRUCTIONS_CLOSE}\n\n`;
117
115
  }
118
116
 
119
- /** Exact pi `buildSystemPrompt()` serialization for the full project context section. */
120
- export function serializePiProjectContextSection(contextFiles: readonly PiAgentsContextFile[]): string {
117
+ /** The two supported Pi project-context serializations; legacy includes outer spacing. */
118
+ export function serializePiProjectContextSection(
119
+ contextFiles: readonly PiAgentsContextFile[],
120
+ format: "legacy" | "transcript" = "legacy",
121
+ ): string {
121
122
  if (contextFiles.length === 0) return "";
123
+ if (format === "transcript") {
124
+ return [
125
+ "<project_context>",
126
+ "Project-specific instructions and guidelines:",
127
+ "",
128
+ contextFiles.map((file) => serializePiProjectInstructionsBlock(file).trimEnd()).join("\n\n"),
129
+ "</project_context>",
130
+ ].join("\n");
131
+ }
122
132
  return `${PI_PROJECT_CONTEXT_OPEN}${contextFiles.map(serializePiProjectInstructionsBlock).join("")}${PI_PROJECT_CONTEXT_CLOSE}`;
123
133
  }
124
134
 
@@ -140,12 +150,16 @@ export function removePiAgentsContextFromSystemPrompt(
140
150
  }
141
151
  if (!removedAny) return systemPrompt;
142
152
 
143
- const originalSection = serializePiProjectContextSection(contextFiles);
144
- const start = systemPrompt.indexOf(originalSection);
145
- if (start < 0) return systemPrompt;
146
-
147
- const replacementSection = serializePiProjectContextSection(retainedContextFiles);
148
- return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
153
+ // Match only the exact known files in either supported serialization; never
154
+ // strip arbitrary user-authored XML or neighboring custom sections.
155
+ for (const format of ["legacy", "transcript"] as const) {
156
+ const originalSection = serializePiProjectContextSection(contextFiles, format);
157
+ const start = systemPrompt.indexOf(originalSection);
158
+ if (start < 0) continue;
159
+ const replacementSection = serializePiProjectContextSection(retainedContextFiles, format);
160
+ return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
161
+ }
162
+ return systemPrompt;
149
163
  }
150
164
 
151
165
  export function resolveCursorFacingSystemPrompt(
@@ -1,3 +1,5 @@
1
+ import { readStoredCredential } from "@earendil-works/pi-coding-agent";
2
+
1
3
  export const CURSOR_API_KEY_ENV_VAR = "CURSOR_API_KEY";
2
4
  const CURSOR_PROVIDER_ID = "cursor";
3
5
 
@@ -21,9 +23,8 @@ export function resolveCursorApiKey(apiKey?: string): string | undefined {
21
23
  return trimmed;
22
24
  }
23
25
 
24
- async function getStoredCursorApiKey(): Promise<string | undefined> {
26
+ function getStoredCursorApiKey(): string | undefined {
25
27
  try {
26
- const { readStoredCredential } = await import("@earendil-works/pi-coding-agent");
27
28
  const credential = readStoredCredential(CURSOR_PROVIDER_ID);
28
29
  return resolveCursorApiKey(credential?.type === "api_key" ? credential.key : undefined);
29
30
  } catch {
@@ -31,6 +32,6 @@ async function getStoredCursorApiKey(): Promise<string | undefined> {
31
32
  }
32
33
  }
33
34
 
34
- export async function resolveCursorRuntimeApiKey(): Promise<string | undefined> {
35
- return (await getStoredCursorApiKey()) ?? resolveCursorApiKey(process.env.CURSOR_API_KEY);
35
+ export function resolveCursorRuntimeApiKey(): Promise<string | undefined> {
36
+ return Promise.resolve(getStoredCursorApiKey() ?? resolveCursorApiKey(process.env.CURSOR_API_KEY));
36
37
  }
@@ -170,17 +170,38 @@ export async function fetchCursorCloudRawUsage(
170
170
  }
171
171
  }
172
172
 
173
+ function mapCursorSdkAgentUsageToCloudReport(value: unknown, runId?: string): CursorCloudUsageReport | undefined {
174
+ const record = asRecord(value);
175
+ const runs = (getArray(record, "runs") ?? []).map(asRecord);
176
+ const matchingRun = runId ? runs.find((run) => getString(run, "runId") === runId) : undefined;
177
+ return normalizeUsage({
178
+ totalUsage: getRecord(record, "usage"),
179
+ runUsage: getRecord(matchingRun, "usage"),
180
+ });
181
+ }
182
+
173
183
  export async function collectCursorCloudRunReport(options: {
174
184
  agent: SDKAgent;
175
185
  run: Run;
176
186
  waitResult: RunResult;
177
187
  apiKey: string | undefined;
188
+ agentUsage?: unknown;
178
189
  }): Promise<CursorCloudRunReport> {
179
190
  const listArtifacts = options.agent.listArtifacts;
180
- const [artifactResult, usage] = await Promise.all([
191
+ const sdkUsage =
192
+ options.agentUsage !== undefined
193
+ ? mapCursorSdkAgentUsageToCloudReport(options.agentUsage, options.run.id)
194
+ : typeof options.agent.getUsage === "function"
195
+ ? mapCursorSdkAgentUsageToCloudReport(
196
+ await withTimeout(Promise.resolve(options.agent.getUsage({ runId: options.run.id }))),
197
+ options.run.id,
198
+ )
199
+ : undefined;
200
+ const [artifactResult, restUsage] = await Promise.all([
181
201
  typeof listArtifacts === "function" ? withTimeout(listArtifacts.call(options.agent)) : undefined,
182
- fetchCursorCloudRawUsage({ agentId: options.run.agentId, runId: options.run.id, apiKey: options.apiKey }),
202
+ sdkUsage ? undefined : fetchCursorCloudRawUsage({ agentId: options.run.agentId, runId: options.run.id, apiKey: options.apiKey }),
183
203
  ]);
204
+ const usage = sdkUsage ?? restUsage;
184
205
  const waitBranches = getArray(getRecord(asRecord(options.waitResult), "git"), "branches");
185
206
  const runBranches = getArray(getRecord(asRecord(options.run), "git"), "branches");
186
207
  return {
@@ -1,6 +1,8 @@
1
1
  import type { Context } from "@earendil-works/pi-ai";
2
+ import { resolveCursorPiContext } from "./cursor-pi-context.js";
2
3
 
3
4
  /** Tool names from the provider context snapshot at stream start (not live pi.getActiveTools()). */
4
5
  export function getActiveContextToolNames(context: Context): ReadonlySet<string> | undefined {
5
- return context.tools ? new Set(context.tools.map((tool) => tool.name)) : undefined;
6
+ const { tools } = resolveCursorPiContext(context);
7
+ return tools === undefined ? undefined : new Set(tools.map((tool) => tool.name));
6
8
  }