pi-cursor-sdk 0.4.0 → 0.5.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 (125) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +65 -13
  3. package/dist/context-window-cache.js +0 -6
  4. package/dist/context.js +8 -0
  5. package/dist/cursor-cloud-lifecycle.js +122 -98
  6. package/dist/cursor-durable-fs.js +97 -3
  7. package/dist/cursor-fallback-models.generated.js +288 -1
  8. package/dist/cursor-fallback-warning.js +2 -2
  9. package/dist/cursor-http1.js +8 -8
  10. package/dist/cursor-live-run-coordinator.js +9 -13
  11. package/dist/cursor-native-replay-routing.js +1 -1
  12. package/dist/cursor-native-tool-display-registration.js +46 -22
  13. package/dist/cursor-native-tool-display-state.js +57 -22
  14. package/dist/cursor-native-tool-display-tools.js +5 -6
  15. package/dist/cursor-pi-tool-bridge-constants.js +23 -2
  16. package/dist/cursor-pi-tool-bridge-run.js +7 -3
  17. package/dist/cursor-pi-tool-bridge-snapshot.js +1 -1
  18. package/dist/cursor-pi-tool-bridge.js +31 -9
  19. package/dist/cursor-provider-binding.js +58 -0
  20. package/dist/cursor-provider-errors.js +28 -7
  21. package/dist/cursor-provider-lazy.js +23 -11
  22. package/dist/cursor-provider-live-run-drain.js +15 -12
  23. package/dist/cursor-provider-run-finalizer.js +19 -8
  24. package/dist/cursor-provider-turn-coordinator.js +1 -0
  25. package/dist/cursor-provider-turn-display-router.js +4 -0
  26. package/dist/cursor-provider-turn-emit.js +1 -0
  27. package/dist/cursor-provider-turn-finalize.js +29 -20
  28. package/dist/cursor-provider-turn-prepare.js +24 -11
  29. package/dist/cursor-provider-turn-runner.js +37 -11
  30. package/dist/cursor-provider-turn-send.js +22 -9
  31. package/dist/cursor-provider-turn-summary.js +89 -0
  32. package/dist/cursor-provider.js +9 -3
  33. package/dist/cursor-request-provenance.js +42 -0
  34. package/dist/cursor-ripgrep-path.js +14 -3
  35. package/dist/cursor-runtime-state.js +50 -43
  36. package/dist/cursor-sdk-billed-usage.js +54 -75
  37. package/dist/cursor-sdk-event-debug-session.js +5 -6
  38. package/dist/cursor-sdk-event-debug.js +9 -6
  39. package/dist/cursor-sdk-process-error-guard.js +8 -7
  40. package/dist/cursor-sdk-runtime.js +13 -0
  41. package/dist/cursor-session-agent-cleanup.js +2 -2
  42. package/dist/cursor-session-agent-lifecycle.js +18 -9
  43. package/dist/cursor-session-agent-lineage.js +28 -12
  44. package/dist/cursor-session-agent-resume.js +51 -35
  45. package/dist/cursor-session-agent.js +9 -9
  46. package/dist/cursor-session-compaction-prep.js +2 -7
  47. package/dist/cursor-session-scope.js +71 -39
  48. package/dist/cursor-session-settings.js +61 -0
  49. package/dist/cursor-skill-tool.js +32 -49
  50. package/dist/cursor-state.js +72 -62
  51. package/dist/cursor-usage-accounting.js +13 -70
  52. package/dist/cursor-usage-command.js +89 -0
  53. package/dist/cursor-usage-ledger.js +512 -0
  54. package/dist/index.js +11 -19
  55. package/dist/model-discovery.js +11 -19
  56. package/docs/cursor-dogfood-checklist.md +3 -3
  57. package/docs/cursor-live-smoke-checklist.md +15 -15
  58. package/docs/cursor-model-ux-spec.md +59 -18
  59. package/docs/cursor-native-tool-replay.md +5 -3
  60. package/docs/cursor-native-tool-visual-audit.md +8 -8
  61. package/docs/cursor-testing-lessons.md +47 -23
  62. package/docs/cursor-tool-surfaces.md +1 -1
  63. package/docs/platform-smoke-implementation.md +10 -6
  64. package/docs/platform-smoke.md +35 -46
  65. package/package.json +6 -6
  66. package/scripts/cloud-runtime-smoke.mjs +4 -2
  67. package/scripts/local-resume-smoke.mjs +1 -1
  68. package/scripts/platform-smoke/card-detect.mjs +2 -8
  69. package/scripts/platform-smoke/targets.mjs +8 -15
  70. package/scripts/platform-smoke/visual-evidence.mjs +7 -2
  71. package/scripts/tmux-live-smoke.sh +57 -90
  72. package/src/context-window-cache.ts +0 -6
  73. package/src/context.ts +8 -0
  74. package/src/cursor-cloud-lifecycle.ts +124 -98
  75. package/src/cursor-durable-fs.ts +65 -3
  76. package/src/cursor-fallback-models.generated.ts +288 -1
  77. package/src/cursor-fallback-warning.ts +2 -2
  78. package/src/cursor-http1.ts +8 -8
  79. package/src/cursor-live-run-coordinator.ts +12 -13
  80. package/src/cursor-native-replay-routing.ts +2 -1
  81. package/src/cursor-native-tool-display-registration.ts +48 -24
  82. package/src/cursor-native-tool-display-state.ts +65 -21
  83. package/src/cursor-native-tool-display-tools.ts +7 -4
  84. package/src/cursor-pi-tool-bridge-constants.ts +27 -2
  85. package/src/cursor-pi-tool-bridge-run.ts +11 -3
  86. package/src/cursor-pi-tool-bridge-snapshot.ts +1 -1
  87. package/src/cursor-pi-tool-bridge.ts +26 -9
  88. package/src/cursor-provider-binding.ts +62 -0
  89. package/src/cursor-provider-errors.ts +27 -7
  90. package/src/cursor-provider-lazy.ts +21 -15
  91. package/src/cursor-provider-live-run-drain.ts +20 -13
  92. package/src/cursor-provider-run-finalizer.ts +24 -15
  93. package/src/cursor-provider-turn-coordinator.ts +2 -0
  94. package/src/cursor-provider-turn-display-router.ts +5 -0
  95. package/src/cursor-provider-turn-emit.ts +3 -1
  96. package/src/cursor-provider-turn-finalize.ts +38 -23
  97. package/src/cursor-provider-turn-prepare.ts +23 -14
  98. package/src/cursor-provider-turn-runner.ts +40 -13
  99. package/src/cursor-provider-turn-send.ts +23 -15
  100. package/src/cursor-provider-turn-summary.ts +94 -0
  101. package/src/cursor-provider-turn-types.ts +37 -4
  102. package/src/cursor-provider.ts +25 -3
  103. package/src/cursor-request-provenance.ts +64 -0
  104. package/src/cursor-ripgrep-path.ts +15 -5
  105. package/src/cursor-runtime-state.ts +53 -48
  106. package/src/cursor-sdk-billed-usage.ts +54 -102
  107. package/src/cursor-sdk-event-debug-session.ts +5 -5
  108. package/src/cursor-sdk-event-debug.ts +10 -6
  109. package/src/cursor-sdk-process-error-guard.ts +7 -7
  110. package/src/cursor-sdk-runtime.ts +14 -0
  111. package/src/cursor-session-agent-cleanup.ts +2 -2
  112. package/src/cursor-session-agent-lifecycle.ts +14 -9
  113. package/src/cursor-session-agent-lineage.ts +26 -12
  114. package/src/cursor-session-agent-resume.ts +49 -36
  115. package/src/cursor-session-agent.ts +13 -10
  116. package/src/cursor-session-compaction-prep.ts +2 -7
  117. package/src/cursor-session-scope.ts +87 -39
  118. package/src/cursor-session-settings.ts +72 -0
  119. package/src/cursor-skill-tool.ts +37 -61
  120. package/src/cursor-state.ts +74 -67
  121. package/src/cursor-usage-accounting.ts +17 -82
  122. package/src/cursor-usage-command.ts +76 -0
  123. package/src/cursor-usage-ledger.ts +500 -0
  124. package/src/index.ts +14 -23
  125. package/src/model-discovery.ts +14 -22
package/src/index.ts CHANGED
@@ -1,21 +1,23 @@
1
- import type { ExtensionAPI, ProviderConfig, ProviderModelConfig } from "@earendil-works/pi-coding-agent";
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { discoverModels, type CursorModelFallbackIssue } from "./model-discovery.js";
3
3
  import { registerCursorRuntimeControls } from "./cursor-state.js";
4
4
  import { registerCursorNativeToolDisplay } from "./cursor-native-tool-display-registration.js";
5
5
  import { registerCursorPiToolBridge } from "./cursor-pi-tool-bridge.js";
6
6
  import { registerCursorQuestionTool } from "./cursor-question-tool.js";
7
7
  import { registerCursorSkillTool } from "./cursor-skill-tool.js";
8
- import { registerCursorSessionScope } from "./cursor-session-scope.js";
8
+ import { registerCursorProviderBinding } from "./cursor-provider-binding.js";
9
+ import { getCursorSessionScopeSnapshot, registerCursorSessionScope } from "./cursor-session-scope.js";
9
10
  import { registerCursorSessionAgentLifecycle } from "./cursor-session-agent-lifecycle.js";
10
11
  import { registerCursorSessionAgentLineage } from "./cursor-session-agent-lineage.js";
11
12
  import { registerCursorSessionAgentResume } from "./cursor-session-agent-resume.js";
12
- import { streamCursorLazy } from "./cursor-provider-lazy.js";
13
- import { CURSOR_API_KEY_CONFIG_VALUE, resolveCursorApiKey } from "./cursor-api-key.js";
13
+ import { resolveCursorApiKey } from "./cursor-api-key.js";
14
14
  import { registerCursorFallbackIssueWarning } from "./cursor-fallback-warning.js";
15
15
  import { registerCursorAgentsContextDedup } from "./cursor-agents-context-registration.js";
16
16
  import { registerCursorOverflowNormalization } from "./cursor-provider-overflow.js";
17
17
  import { registerCursorSdkSessionProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
18
18
  import { prepareCursorSessionForCompaction } from "./cursor-session-compaction-prep.js";
19
+ import { registerCursorUsageLedger } from "./cursor-usage-ledger.js";
20
+ import { registerCursorUsageCommand } from "./cursor-usage-command.js";
19
21
 
20
22
  type CursorExtensionApi =
21
23
  & Pick<ExtensionAPI, "registerProvider" | "registerCommand" | "on">
@@ -31,31 +33,20 @@ type CursorExtensionApi =
31
33
  & Parameters<typeof registerCursorFallbackIssueWarning>[0]
32
34
  & Parameters<typeof registerCursorAgentsContextDedup>[0]
33
35
  & Parameters<typeof registerCursorOverflowNormalization>[0]
34
- & Parameters<typeof registerCursorSdkSessionProcessErrorGuard>[0];
35
-
36
- function createCursorProviderConfig(models: ProviderModelConfig[]): ProviderConfig {
37
- return {
38
- name: "Cursor",
39
- baseUrl: "https://cursor.com",
40
- apiKey: CURSOR_API_KEY_CONFIG_VALUE,
41
- api: "cursor-sdk",
42
- models,
43
- streamSimple: streamCursorLazy,
44
- };
45
- }
46
-
47
- function registerCursorProvider(pi: Pick<ExtensionAPI, "registerProvider">, models: ProviderModelConfig[]): void {
48
- pi.registerProvider("cursor", createCursorProviderConfig(models));
49
- }
36
+ & Parameters<typeof registerCursorSdkSessionProcessErrorGuard>[0]
37
+ & Parameters<typeof registerCursorUsageLedger>[0];
50
38
 
51
39
  export default async function (pi: CursorExtensionApi) {
52
40
  // Session cwd must register before other session_start listeners that depend on it.
53
41
  registerCursorSessionScope(pi);
42
+ registerCursorUsageLedger(pi);
43
+ registerCursorUsageCommand(pi);
44
+ const registerCursorProvider = registerCursorProviderBinding(pi);
54
45
  registerCursorSessionAgentLineage(pi);
55
46
  registerCursorSessionAgentLifecycle(pi);
56
47
  registerCursorSessionAgentResume(pi);
57
48
  pi.on("session_before_compact", async () => {
58
- await prepareCursorSessionForCompaction();
49
+ await prepareCursorSessionForCompaction(getCursorSessionScopeSnapshot(pi).scopeKey);
59
50
  });
60
51
  registerCursorRuntimeControls(pi);
61
52
  registerCursorNativeToolDisplay(pi);
@@ -87,7 +78,7 @@ export default async function (pi: CursorExtensionApi) {
87
78
  refreshFallbackIssue = issue;
88
79
  },
89
80
  });
90
- registerCursorProvider(pi, refreshedModels);
81
+ registerCursorProvider(refreshedModels);
91
82
  if (!ctx.hasUI) return;
92
83
  if (refreshFallbackIssue) {
93
84
  ctx.ui.notify(`Cursor model catalog refresh did not use a live catalog: ${refreshFallbackIssue.message}`, "warning");
@@ -97,7 +88,7 @@ export default async function (pi: CursorExtensionApi) {
97
88
  },
98
89
  });
99
90
 
100
- registerCursorProvider(pi, models);
91
+ registerCursorProvider(models);
101
92
  // Register last so session_shutdown cleanup remains protected until other Cursor handlers finish.
102
93
  registerCursorSdkSessionProcessErrorGuard(pi);
103
94
  }
@@ -4,13 +4,13 @@ import type {
4
4
  ModelParameterValue,
5
5
  ModelSelection,
6
6
  } from "@cursor/sdk";
7
- import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
7
+ import type { ProviderModelConfig as PiProviderModelConfig } from "@earendil-works/pi-coding-agent";
8
8
  import type { ModelThinkingLevel, ThinkingLevelMap } from "@earendil-works/pi-ai";
9
9
  import { getCursorModelSelectionIdentities } from "../shared/cursor-model-selection-identities.mjs";
10
10
  import { loadContextWindowCache } from "./context-window-cache.js";
11
11
  import { loadCursorSdk } from "./cursor-sdk-runtime.js";
12
12
  import { resolveCursorApiKey, resolveCursorRuntimeApiKey } from "./cursor-api-key.js";
13
- import { scrubSensitiveText } from "./cursor-sensitive-text.js";
13
+ import { sanitizeCursorProviderError } from "./cursor-provider-errors.js";
14
14
  import {
15
15
  fingerprintApiKey,
16
16
  loadAnyCachedModelCatalog,
@@ -18,6 +18,8 @@ import {
18
18
  saveModelListCache,
19
19
  } from "./model-list-cache.js";
20
20
 
21
+ type ProviderModelConfig = Extract<PiProviderModelConfig, { reasoning: boolean }>;
22
+
21
23
  const FALLBACK_CONTEXT_WINDOW = 128000;
22
24
  const FALLBACK_MAX_TOKENS = 16384;
23
25
  const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
@@ -65,6 +67,7 @@ export interface CursorModelMetadata {
65
67
  reasoning: boolean;
66
68
  effort: boolean;
67
69
  thinking: boolean;
70
+ reasoning_effort: boolean;
68
71
  fast: boolean;
69
72
  };
70
73
  }
@@ -114,7 +117,7 @@ function getThinkingLevelMap(item: ModelListItem): ThinkingLevelMap | undefined
114
117
  const reasoningParameter = getParameter(item, "reasoning");
115
118
  const effortParameter = getParameter(item, "effort");
116
119
  const thinkingParameter = getParameter(item, "thinking");
117
- const valueParameter = effortParameter ?? reasoningParameter ?? thinkingParameter;
120
+ const valueParameter = effortParameter ?? reasoningParameter ?? thinkingParameter ?? getParameter(item, "reasoning_effort");
118
121
  if (!valueParameter) return undefined;
119
122
 
120
123
  if (valueParameter.id === "thinking" && hasBooleanValues(valueParameter)) {
@@ -235,6 +238,7 @@ function toMetadata(
235
238
  reasoning: getParameter(item, "reasoning") !== undefined,
236
239
  effort: getParameter(item, "effort") !== undefined,
237
240
  thinking: getParameter(item, "thinking") !== undefined,
241
+ reasoning_effort: getParameter(item, "reasoning_effort") !== undefined,
238
242
  fast: getParameter(item, "fast") !== undefined,
239
243
  },
240
244
  };
@@ -280,15 +284,6 @@ export function getCursorModelMetadata(modelId: string): CursorModelMetadata | u
280
284
  return metadataByPiModelId.get(modelId);
281
285
  }
282
286
 
283
- export function getCursorModelMetadataEntries(): CursorModelMetadata[] {
284
- return [...metadataByPiModelId.values()].map((metadata) => ({
285
- ...metadata,
286
- defaultParams: cloneParams(metadata.defaultParams),
287
- ...(metadata.thinkingLevelMap ? { thinkingLevelMap: { ...metadata.thinkingLevelMap } } : {}),
288
- parameterIds: { ...metadata.parameterIds },
289
- }));
290
- }
291
-
292
287
  function setParam(params: ModelParameterValue[], id: string, value: string): void {
293
288
  const existing = params.find((param) => param.id === id);
294
289
  if (existing) {
@@ -336,6 +331,8 @@ function applyThinkingLevel(
336
331
 
337
332
  if (metadata.parameterIds.thinking) {
338
333
  setParam(params, "thinking", mapped);
334
+ } else if (metadata.parameterIds.reasoning_effort) {
335
+ setParam(params, "reasoning_effort", mapped);
339
336
  }
340
337
  }
341
338
 
@@ -357,11 +354,6 @@ export function buildCursorModelSelection(
357
354
  return params.length > 0 ? { id: metadata.selectionModelId, params } : { id: metadata.selectionModelId };
358
355
  }
359
356
 
360
- function sanitizeDiscoveryError(error: unknown, apiKey: string): string | undefined {
361
- const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
362
- return scrubSensitiveText(message, apiKey).trim() || undefined;
363
- }
364
-
365
357
  async function useFallbackModels(options: DiscoverModelsOptions, issue: CursorModelFallbackIssue): Promise<ProviderModelConfig[]> {
366
358
  options.onFallback?.(issue);
367
359
  const { FALLBACK_MODEL_ITEMS } = await import("./cursor-fallback-models.generated.js");
@@ -398,7 +390,7 @@ export async function discoverModels(options: DiscoverModelsOptions = {}): Promi
398
390
  message: `Cursor model discovery returned no models. Using fallback Cursor models; verify ${AUTH_SETUP_HINT}. ${CATALOG_REFRESH_HINT}`,
399
391
  });
400
392
  } catch (error) {
401
- const errorMessage = sanitizeDiscoveryError(error, apiKey);
393
+ const errorMessage = sanitizeCursorProviderError(error, apiKey);
402
394
  // Prefer a previously cached catalog over the generic bundled fallback when
403
395
  // a live refresh fails (e.g. transient network/auth errors), but keep the
404
396
  // provenance visible so refresh commands do not claim a live refresh worked.
@@ -406,15 +398,15 @@ export async function discoverModels(options: DiscoverModelsOptions = {}): Promi
406
398
  if (cachedCatalog && cachedCatalog.models.length > 0) {
407
399
  options.onFallback?.({
408
400
  reason: "cached-after-error",
409
- message: `Cursor model discovery failed; using cached Cursor model catalog from ${new Date(cachedCatalog.fetchedAt).toISOString()}.${errorMessage ? ` ${errorMessage}` : ""}`,
410
- ...(errorMessage ? { errorMessage } : {}),
401
+ message: `Cursor model discovery failed; using cached Cursor model catalog from ${new Date(cachedCatalog.fetchedAt).toISOString()}. ${errorMessage}`,
402
+ errorMessage,
411
403
  });
412
404
  return registerModelItems(cachedCatalog.models);
413
405
  }
414
406
  return useFallbackModels(options, {
415
407
  reason: "discovery-failed",
416
- message: `Cursor model discovery failed${errorMessage ? `: ${errorMessage}` : ""}. Using fallback Cursor models; verify ${AUTH_SETUP_HINT}. ${CATALOG_REFRESH_HINT}`,
417
- ...(errorMessage ? { errorMessage } : {}),
408
+ message: `Cursor model discovery failed: ${errorMessage} Using fallback Cursor models; run /cursor-refresh-models to retry discovery.`,
409
+ errorMessage,
418
410
  });
419
411
  }
420
412
  }