pi-cursor-sdk 0.1.39 → 0.1.41

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 (47) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +13 -12
  3. package/docs/cursor-dogfood-checklist.md +7 -1
  4. package/docs/cursor-live-smoke-checklist.md +13 -13
  5. package/docs/cursor-model-ux-spec.md +8 -8
  6. package/docs/cursor-native-tool-replay.md +4 -4
  7. package/docs/cursor-native-tool-visual-audit.md +5 -5
  8. package/docs/cursor-testing-lessons.md +5 -5
  9. package/docs/cursor-tool-surfaces.md +4 -0
  10. package/docs/platform-smoke.md +22 -7
  11. package/package.json +8 -5
  12. package/platform-smoke.config.mjs +5 -0
  13. package/scripts/debug-provider-events.mjs +1 -0
  14. package/scripts/isolated-cursor-smoke.sh +7 -7
  15. package/scripts/lib/cursor-visual-manifest.d.mts +3 -0
  16. package/scripts/lib/cursor-visual-manifest.mjs +82 -0
  17. package/scripts/platform-smoke/artifacts.mjs +225 -2
  18. package/scripts/platform-smoke/card-detect.mjs +1 -1
  19. package/scripts/platform-smoke/doctor.mjs +53 -8
  20. package/scripts/platform-smoke/live-suite-runner.mjs +7 -6
  21. package/scripts/platform-smoke/platform-build-windows.ps1 +2 -2
  22. package/scripts/platform-smoke/scenarios.mjs +1 -1
  23. package/scripts/platform-smoke/targets.mjs +2 -2
  24. package/scripts/platform-smoke.mjs +75 -6
  25. package/scripts/steering-rpc-smoke.mjs +1 -1
  26. package/scripts/tmux-live-smoke.sh +1 -1
  27. package/scripts/visual-tui-smoke-self-test.mjs +229 -0
  28. package/scripts/visual-tui-smoke.mjs +46 -179
  29. package/shared/cursor-setting-sources.d.mts +1 -0
  30. package/shared/cursor-setting-sources.mjs +2 -1
  31. package/src/context.ts +25 -10
  32. package/src/cursor-active-tools.ts +7 -0
  33. package/src/cursor-native-tool-display-registration.ts +31 -21
  34. package/src/cursor-native-tool-display-state.ts +13 -4
  35. package/src/cursor-pi-tool-bridge-run.ts +6 -3
  36. package/src/cursor-pi-tool-bridge-types.ts +2 -2
  37. package/src/cursor-provider-errors.ts +2 -1
  38. package/src/cursor-provider-live-run-drain.ts +1 -1
  39. package/src/cursor-provider-turn-prepare.ts +1 -1
  40. package/src/cursor-provider-turn-send.ts +2 -0
  41. package/src/cursor-question-tool.ts +2 -1
  42. package/src/cursor-sdk-event-debug.ts +3 -1
  43. package/src/cursor-setting-sources.ts +2 -0
  44. package/src/cursor-skill-tool.ts +2 -1
  45. package/src/cursor-state.ts +2 -1
  46. package/src/cursor-tool-manifest.ts +2 -1
  47. package/src/cursor-usage-accounting.ts +5 -4
@@ -1,6 +1,7 @@
1
1
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { Text } from "@earendil-works/pi-tui";
3
3
  import { Type } from "typebox";
4
+ import { arePiToolsDisabled } from "./cursor-active-tools.js";
4
5
  import { isCursorModel } from "./cursor-model.js";
5
6
  import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
6
7
  import { resolveCursorPiToolBridgeEnabled } from "./cursor-pi-tool-bridge-env.js";
@@ -175,7 +176,7 @@ async function askOneQuestion(question: CursorQuestion, ctx: { ui: ExtensionCont
175
176
 
176
177
  function syncCursorQuestionToolForModel(pi: Pick<ExtensionAPI, "getActiveTools" | "setActiveTools">, model: ExtensionContext["model"]): void {
177
178
  const activeToolNames = new Set(pi.getActiveTools());
178
- const shouldBeActive = isCursorModel(model) && resolveCursorPiToolBridgeEnabled();
179
+ const shouldBeActive = !arePiToolsDisabled(pi) && isCursorModel(model) && resolveCursorPiToolBridgeEnabled();
179
180
  const alreadyActive = activeToolNames.has(CURSOR_ASK_QUESTION_TOOL_NAME);
180
181
  if (shouldBeActive === alreadyActive) return;
181
182
  if (shouldBeActive) {
@@ -78,12 +78,14 @@ export interface CursorSdkEventDebugSendMeta {
78
78
 
79
79
  export interface CursorSdkEventDebugRunMeta {
80
80
  runId: string;
81
+ requestId?: string;
81
82
  agentId: string;
82
83
  status: string;
83
84
  }
84
85
 
85
86
  interface CursorSdkRunLike {
86
87
  id: string;
88
+ requestId?: string;
87
89
  agentId?: string;
88
90
  status?: string;
89
91
  stream?: () => AsyncIterable<unknown>;
@@ -373,7 +375,7 @@ export class CursorSdkEventDebugSink {
373
375
  attachRunStream(run: unknown): void {
374
376
  const sdkRun = run as CursorSdkRunLike;
375
377
  if (typeof sdkRun.stream !== "function") {
376
- this.recordProviderEvent("run_stream_unavailable", { runId: sdkRun.id });
378
+ this.recordProviderEvent("run_stream_unavailable", { runId: sdkRun.id, requestId: sdkRun.requestId });
377
379
  return;
378
380
  }
379
381
  this.streamCapturePromise = (async () => {
@@ -2,10 +2,12 @@ import type { SettingSource } from "@cursor/sdk";
2
2
  /** Provider-facing wrapper; canonical parsing lives in shared/cursor-setting-sources.mjs. */
3
3
  import {
4
4
  CURSOR_SETTING_SOURCES_ENV as CURSOR_SETTING_SOURCES_ENV_JS,
5
+ DEFAULT_CURSOR_SETTING_SOURCES as DEFAULT_CURSOR_SETTING_SOURCES_JS,
5
6
  resolveCursorSettingSources as resolveCursorSettingSourcesJs,
6
7
  } from "../shared/cursor-setting-sources.mjs";
7
8
 
8
9
  export const CURSOR_SETTING_SOURCES_ENV = CURSOR_SETTING_SOURCES_ENV_JS;
10
+ export const DEFAULT_CURSOR_SETTING_SOURCES = DEFAULT_CURSOR_SETTING_SOURCES_JS as readonly SettingSource[];
9
11
 
10
12
  export function resolveCursorSettingSources(raw?: string): SettingSource[] | undefined {
11
13
  return resolveCursorSettingSourcesJs(raw) as SettingSource[] | undefined;
@@ -8,6 +8,7 @@ import type {
8
8
  Skill,
9
9
  } from "@earendil-works/pi-coding-agent";
10
10
  import { Type } from "typebox";
11
+ import { arePiToolsDisabled } from "./cursor-active-tools.js";
11
12
  import { isCursorModel } from "./cursor-model.js";
12
13
  import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
13
14
  import { resolveCursorPiToolBridgeEnabled } from "./cursor-pi-tool-bridge-env.js";
@@ -62,7 +63,7 @@ function shouldExposeSkillTool(model: ExtensionContext["model"]): boolean {
62
63
 
63
64
  function syncCursorSkillToolForModel(pi: Pick<ExtensionAPI, "getActiveTools" | "setActiveTools">, model: ExtensionContext["model"]): void {
64
65
  const activeToolNames = new Set(pi.getActiveTools());
65
- const shouldBeActive = shouldExposeSkillTool(model);
66
+ const shouldBeActive = !arePiToolsDisabled(pi) && shouldExposeSkillTool(model);
66
67
  const alreadyActive = activeToolNames.has(CURSOR_ACTIVATE_SKILL_TOOL_NAME);
67
68
  if (shouldBeActive === alreadyActive) return;
68
69
  if (shouldBeActive) {
@@ -15,6 +15,7 @@ import {
15
15
  } from "./cursor-pi-tool-bridge-snapshot.js";
16
16
  import {
17
17
  CURSOR_SETTING_SOURCES_ENV,
18
+ DEFAULT_CURSOR_SETTING_SOURCES,
18
19
  resolveCursorSettingSources,
19
20
  } from "./cursor-setting-sources.js";
20
21
  import { isCursorModel } from "./cursor-model.js";
@@ -298,7 +299,7 @@ function notifyInvalidCursorModeIfCursorActive(ctx: Pick<ExtensionContext, "hasU
298
299
  function formatEffectiveCursorSettingSourcesLabel(raw: string | undefined = process.env[CURSOR_SETTING_SOURCES_ENV]): string {
299
300
  const effective = resolveCursorSettingSources(raw);
300
301
  const effectiveLabel = effective === undefined ? "none" : effective.join(",");
301
- const rawLabel = raw?.trim() ? raw.trim() : "(unset → all)";
302
+ const rawLabel = raw?.trim() ? raw.trim() : `(unset → ${DEFAULT_CURSOR_SETTING_SOURCES.join(",")})`;
302
303
  return `${rawLabel} (effective: ${effectiveLabel})`;
303
304
  }
304
305
 
@@ -4,7 +4,7 @@ import type { CursorPiToolBridgeSnapshot } from "./cursor-pi-tool-bridge-types.j
4
4
  export const CURSOR_TOOL_MANIFEST_ENV = "PI_CURSOR_TOOL_MANIFEST";
5
5
 
6
6
  /**
7
- * Representative @cursor/sdk@1.0.17 local-agent ToolType values; actual exposure can vary by run.
7
+ * Representative @cursor/sdk@1.0.18 local-agent ToolType values; actual exposure can vary by run.
8
8
  * See docs/cursor-native-tool-replay.md#sdk-tooltype-replay-matrix.
9
9
  */
10
10
  export const CURSOR_HOST_TOOL_MANIFEST_SUMMARY =
@@ -26,6 +26,7 @@ export function buildCursorToolManifestText(options: {
26
26
  "Callable tool surfaces this run:",
27
27
  `- Cursor SDK host tools (callable; not listed in MCP listTools): ${CURSOR_HOST_TOOL_MANIFEST_SUMMARY}.`,
28
28
  "- Configured Cursor MCP servers: discovered at runtime via MCP listTools (depends on Cursor settings and PI_CURSOR_SETTING_SOURCES).",
29
+ "- Pi CLI tool toggles such as --no-tools affect pi tools and bridge exposure only; they do not disable Cursor SDK host tools or configured Cursor MCP.",
29
30
  ];
30
31
  const bridgeTools = options.bridgeSnapshot?.tools ?? [];
31
32
  if (!piBridgeEnabled) {
@@ -56,10 +56,11 @@ export function estimateCursorContextTotalTokens(partial: AssistantMessage, mode
56
56
  return estimateCursorContextTokens(withAssistantMessage(context, partial), getCursorPromptOptions(model));
57
57
  }
58
58
 
59
- export function applyCursorApproximateUsage(partial: AssistantMessage, model: Model<Api>, context: Context, sessionInputTokens: number): void {
60
- partial.usage.input = sessionInputTokens;
61
- partial.usage.output = estimateCursorAssistantSessionOutputTokens(partial);
59
+ export function applyCursorApproximateUsage(partial: AssistantMessage, _model: Model<Api>, _context: Context, sessionInputTokens: number): void {
60
+ const outputTokens = estimateCursorAssistantSessionOutputTokens(partial);
61
+ partial.usage.input = Math.max(0, sessionInputTokens);
62
+ partial.usage.output = outputTokens;
62
63
  partial.usage.cacheRead = 0;
63
64
  partial.usage.cacheWrite = 0;
64
- partial.usage.totalTokens = estimateCursorContextTotalTokens(partial, model, context);
65
+ partial.usage.totalTokens = partial.usage.input + partial.usage.output + partial.usage.cacheRead + partial.usage.cacheWrite;
65
66
  }