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/dist/index.js CHANGED
@@ -4,38 +4,30 @@ import { registerCursorNativeToolDisplay } from "./cursor-native-tool-display-re
4
4
  import { registerCursorPiToolBridge } from "./cursor-pi-tool-bridge.js";
5
5
  import { registerCursorQuestionTool } from "./cursor-question-tool.js";
6
6
  import { registerCursorSkillTool } from "./cursor-skill-tool.js";
7
- import { registerCursorSessionScope } from "./cursor-session-scope.js";
7
+ import { registerCursorProviderBinding } from "./cursor-provider-binding.js";
8
+ import { getCursorSessionScopeSnapshot, registerCursorSessionScope } from "./cursor-session-scope.js";
8
9
  import { registerCursorSessionAgentLifecycle } from "./cursor-session-agent-lifecycle.js";
9
10
  import { registerCursorSessionAgentLineage } from "./cursor-session-agent-lineage.js";
10
11
  import { registerCursorSessionAgentResume } from "./cursor-session-agent-resume.js";
11
- import { streamCursorLazy } from "./cursor-provider-lazy.js";
12
- import { CURSOR_API_KEY_CONFIG_VALUE, resolveCursorApiKey } from "./cursor-api-key.js";
12
+ import { resolveCursorApiKey } from "./cursor-api-key.js";
13
13
  import { registerCursorFallbackIssueWarning } from "./cursor-fallback-warning.js";
14
14
  import { registerCursorAgentsContextDedup } from "./cursor-agents-context-registration.js";
15
15
  import { registerCursorOverflowNormalization } from "./cursor-provider-overflow.js";
16
16
  import { registerCursorSdkSessionProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
17
17
  import { prepareCursorSessionForCompaction } from "./cursor-session-compaction-prep.js";
18
- function createCursorProviderConfig(models) {
19
- return {
20
- name: "Cursor",
21
- baseUrl: "https://cursor.com",
22
- apiKey: CURSOR_API_KEY_CONFIG_VALUE,
23
- api: "cursor-sdk",
24
- models,
25
- streamSimple: streamCursorLazy,
26
- };
27
- }
28
- function registerCursorProvider(pi, models) {
29
- pi.registerProvider("cursor", createCursorProviderConfig(models));
30
- }
18
+ import { registerCursorUsageLedger } from "./cursor-usage-ledger.js";
19
+ import { registerCursorUsageCommand } from "./cursor-usage-command.js";
31
20
  export default async function (pi) {
32
21
  // Session cwd must register before other session_start listeners that depend on it.
33
22
  registerCursorSessionScope(pi);
23
+ registerCursorUsageLedger(pi);
24
+ registerCursorUsageCommand(pi);
25
+ const registerCursorProvider = registerCursorProviderBinding(pi);
34
26
  registerCursorSessionAgentLineage(pi);
35
27
  registerCursorSessionAgentLifecycle(pi);
36
28
  registerCursorSessionAgentResume(pi);
37
29
  pi.on("session_before_compact", async () => {
38
- await prepareCursorSessionForCompaction();
30
+ await prepareCursorSessionForCompaction(getCursorSessionScopeSnapshot(pi).scopeKey);
39
31
  });
40
32
  registerCursorRuntimeControls(pi);
41
33
  registerCursorNativeToolDisplay(pi);
@@ -65,7 +57,7 @@ export default async function (pi) {
65
57
  refreshFallbackIssue = issue;
66
58
  },
67
59
  });
68
- registerCursorProvider(pi, refreshedModels);
60
+ registerCursorProvider(refreshedModels);
69
61
  if (!ctx.hasUI)
70
62
  return;
71
63
  if (refreshFallbackIssue) {
@@ -76,7 +68,7 @@ export default async function (pi) {
76
68
  }
77
69
  },
78
70
  });
79
- registerCursorProvider(pi, models);
71
+ registerCursorProvider(models);
80
72
  // Register last so session_shutdown cleanup remains protected until other Cursor handlers finish.
81
73
  registerCursorSdkSessionProcessErrorGuard(pi);
82
74
  }
@@ -2,7 +2,7 @@ import { getCursorModelSelectionIdentities } from "../shared/cursor-model-select
2
2
  import { loadContextWindowCache } from "./context-window-cache.js";
3
3
  import { loadCursorSdk } from "./cursor-sdk-runtime.js";
4
4
  import { resolveCursorApiKey, resolveCursorRuntimeApiKey } from "./cursor-api-key.js";
5
- import { scrubSensitiveText } from "./cursor-sensitive-text.js";
5
+ import { sanitizeCursorProviderError } from "./cursor-provider-errors.js";
6
6
  import { fingerprintApiKey, loadAnyCachedModelCatalog, loadFreshCachedModels, saveModelListCache, } from "./model-list-cache.js";
7
7
  const FALLBACK_CONTEXT_WINDOW = 128000;
8
8
  const FALLBACK_MAX_TOKENS = 16384;
@@ -46,7 +46,7 @@ function getThinkingLevelMap(item) {
46
46
  const reasoningParameter = getParameter(item, "reasoning");
47
47
  const effortParameter = getParameter(item, "effort");
48
48
  const thinkingParameter = getParameter(item, "thinking");
49
- const valueParameter = effortParameter ?? reasoningParameter ?? thinkingParameter;
49
+ const valueParameter = effortParameter ?? reasoningParameter ?? thinkingParameter ?? getParameter(item, "reasoning_effort");
50
50
  if (!valueParameter)
51
51
  return undefined;
52
52
  if (valueParameter.id === "thinking" && hasBooleanValues(valueParameter)) {
@@ -147,6 +147,7 @@ function toMetadata(item, piModelId, selectionModelId, defaultParams, context, c
147
147
  reasoning: getParameter(item, "reasoning") !== undefined,
148
148
  effort: getParameter(item, "effort") !== undefined,
149
149
  thinking: getParameter(item, "thinking") !== undefined,
150
+ reasoning_effort: getParameter(item, "reasoning_effort") !== undefined,
150
151
  fast: getParameter(item, "fast") !== undefined,
151
152
  },
152
153
  };
@@ -179,14 +180,6 @@ function registerModelItems(items) {
179
180
  export function getCursorModelMetadata(modelId) {
180
181
  return metadataByPiModelId.get(modelId);
181
182
  }
182
- export function getCursorModelMetadataEntries() {
183
- return [...metadataByPiModelId.values()].map((metadata) => ({
184
- ...metadata,
185
- defaultParams: cloneParams(metadata.defaultParams),
186
- ...(metadata.thinkingLevelMap ? { thinkingLevelMap: { ...metadata.thinkingLevelMap } } : {}),
187
- parameterIds: { ...metadata.parameterIds },
188
- }));
189
- }
190
183
  function setParam(params, id, value) {
191
184
  const existing = params.find((param) => param.id === id);
192
185
  if (existing) {
@@ -229,6 +222,9 @@ function applyThinkingLevel(metadata, params, level) {
229
222
  if (metadata.parameterIds.thinking) {
230
223
  setParam(params, "thinking", mapped);
231
224
  }
225
+ else if (metadata.parameterIds.reasoning_effort) {
226
+ setParam(params, "reasoning_effort", mapped);
227
+ }
232
228
  }
233
229
  export function buildCursorModelSelection(modelId, thinkingLevel, fastEnabled) {
234
230
  const metadata = getCursorModelMetadata(modelId);
@@ -241,10 +237,6 @@ export function buildCursorModelSelection(modelId, thinkingLevel, fastEnabled) {
241
237
  }
242
238
  return params.length > 0 ? { id: metadata.selectionModelId, params } : { id: metadata.selectionModelId };
243
239
  }
244
- function sanitizeDiscoveryError(error, apiKey) {
245
- const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
246
- return scrubSensitiveText(message, apiKey).trim() || undefined;
247
- }
248
240
  async function useFallbackModels(options, issue) {
249
241
  options.onFallback?.(issue);
250
242
  const { FALLBACK_MODEL_ITEMS } = await import("./cursor-fallback-models.generated.js");
@@ -278,7 +270,7 @@ export async function discoverModels(options = {}) {
278
270
  });
279
271
  }
280
272
  catch (error) {
281
- const errorMessage = sanitizeDiscoveryError(error, apiKey);
273
+ const errorMessage = sanitizeCursorProviderError(error, apiKey);
282
274
  // Prefer a previously cached catalog over the generic bundled fallback when
283
275
  // a live refresh fails (e.g. transient network/auth errors), but keep the
284
276
  // provenance visible so refresh commands do not claim a live refresh worked.
@@ -286,15 +278,15 @@ export async function discoverModels(options = {}) {
286
278
  if (cachedCatalog && cachedCatalog.models.length > 0) {
287
279
  options.onFallback?.({
288
280
  reason: "cached-after-error",
289
- message: `Cursor model discovery failed; using cached Cursor model catalog from ${new Date(cachedCatalog.fetchedAt).toISOString()}.${errorMessage ? ` ${errorMessage}` : ""}`,
290
- ...(errorMessage ? { errorMessage } : {}),
281
+ message: `Cursor model discovery failed; using cached Cursor model catalog from ${new Date(cachedCatalog.fetchedAt).toISOString()}. ${errorMessage}`,
282
+ errorMessage,
291
283
  });
292
284
  return registerModelItems(cachedCatalog.models);
293
285
  }
294
286
  return useFallbackModels(options, {
295
287
  reason: "discovery-failed",
296
- message: `Cursor model discovery failed${errorMessage ? `: ${errorMessage}` : ""}. Using fallback Cursor models; verify ${AUTH_SETUP_HINT}. ${CATALOG_REFRESH_HINT}`,
297
- ...(errorMessage ? { errorMessage } : {}),
288
+ message: `Cursor model discovery failed: ${errorMessage} Using fallback Cursor models; run /cursor-refresh-models to retry discovery.`,
289
+ errorMessage,
298
290
  });
299
291
  }
300
292
  }
@@ -1,6 +1,6 @@
1
1
  # Cursor dogfood checklist
2
2
 
3
- Short maintainer checklist for **minimal-surface** validation after prompt, bridge, replay, or manifest changes. This is the fast path from pi-cursor-composer dogfood sessions—not a substitute for the required [platform smoke gate](./platform-smoke.md).
3
+ Short maintainer menu for **minimal-surface** validation after prompt, bridge, replay, or manifest changes. Start with offline/faux checks and reuse exact-input retained evidence. Only changed behavior needing new real-service proof warrants a selected exercise on one representative environment; docs/metadata-only changes need no paid runs. The [platform smoke matrix](./platform-smoke.md) is optional, not a routine ship step. No full paid campaign replay or automatic paid retries. No paid Cloud testing for generic PRs/releases; only explicitly Cursor Cloud-focused PRs/issues may select necessary focused Cloud proof. Automated Cursor PR reviews continue unchanged.
4
4
 
5
5
  ## Minimal environment
6
6
 
@@ -33,7 +33,7 @@ Inspect the session JSONL under the temp `--session-dir`:
33
33
  | Pattern | Meaning |
34
34
  | --- | --- |
35
35
  | `cursor-replay-*` | Display-only replay of Cursor SDK activity—not callable |
36
- | `cursor-pi-bridge-run-*` | Live pi execution via bridge |
36
+ | `cursor-pi-bridge-run-*` (run) / `cursor-pi-bridge-<32 hex>-t<counter>` (tool) | Live pi execution via bridge |
37
37
  | Callable tools | Cursor SDK host + MCP `listTools` + exposed `pi__*` only |
38
38
 
39
39
  Common mistake: treating `cursor-replay-*` IDs or pi transcript tool labels as tools to invoke.
@@ -60,6 +60,6 @@ Canonical visual evidence: `npm run smoke:visual` (see [Cursor native tool visua
60
60
  ## Related docs
61
61
 
62
62
  - [Cursor tool surfaces in pi](./cursor-tool-surfaces.md) — three namespaces and discoverability
63
- - [Platform smoke gate](./platform-smoke.md) — required cross-platform release gate
63
+ - [Platform smoke](./platform-smoke.md) — focused selection and optional comprehensive matrix
64
64
  - [Cursor live smoke checklist](./cursor-live-smoke-checklist.md) — inner-loop/manual debug checks
65
65
  - [Cursor testing lessons](./cursor-testing-lessons.md) — auth, JSONL scans, plan-mode traps
@@ -1,10 +1,10 @@
1
1
  # Cursor Live Smoke Checklist
2
2
 
3
- > **Platform Smoke:** The required local cross-platform release gate is `npm run smoke:platform:all`; it runs doctor first. Cloud-runtime changes also require `npm run smoke:cloud`. See [docs/platform-smoke.md](./platform-smoke.md) for the full contract. The manual checks below remain useful inner-loop/debug tools but are not the required release gate.
3
+ > **Cost-conscious verification:** Offline/faux checks first; reuse exact-input retained evidence. Use only the smallest meaningful changed-behavior live check on one representative environment when real-service proof is necessary. Docs/metadata-only changes need no paid runs. The full `smoke:platform:all` matrix is optional. No paid Cloud testing for generic PRs/releases; only explicitly Cursor Cloud-focused PRs/issues may select necessary focused Cloud proof. Automated Cursor PR reviews continue unchanged. See [docs/platform-smoke.md](./platform-smoke.md).
4
4
 
5
5
  ## Purpose
6
6
 
7
- Use this manual checklist during development and debugging of Cursor provider/runtime changes. Unit tests and mocks are necessary, but they are not enough for this extension. See [Cursor testing lessons](./cursor-testing-lessons.md) for auth/isolated-harness pitfalls and the plan-mode replay regression that motivated recent hardening. For release readiness, run the local platform gate in [docs/platform-smoke.md](./platform-smoke.md), plus `npm run smoke:cloud` for cloud-runtime changes; this checklist is inner-loop evidence only.
7
+ Use this checklist as a menu, not a mandatory campaign. Select only behavior that changed and needs new real-service evidence after offline/faux checks and retained-proof reuse. Do not run host matrices merely for matrix coverage or automatically retry paid failures. See [Cursor testing lessons](./cursor-testing-lessons.md) for isolated-harness and replay pitfalls. Selected checks keep their distinct assertions, persisted evidence, visual proof, and cleanup requirements; do not claim unobserved coverage.
8
8
 
9
9
  ## Inner-loop rule
10
10
 
@@ -13,8 +13,8 @@ Use this manual checklist during development and debugging of Cursor provider/ru
13
13
  - Use the local extension under test: `pi --approve -e . --cursor-no-fast --model cursor/grok-4.6`.
14
14
  - Use a temporary `--session-dir` for every run.
15
15
  - Do not paste or commit Cursor API keys, raw session contents with secrets, endpoint URLs, or local private paths.
16
- - If an inner-loop check fails, stop and fix or use [docs/platform-smoke.md](./platform-smoke.md) as the release-blocking source of truth. Do not treat this checklist as a narrower replacement for the platform gate.
17
- - Do not narrow the smoke scope to the apparent code diff. Treat provider reality, TUI behavior, bridge behavior, replay behavior, diagnostics safety, abort/cancel cleanup, usage accounting, packaging, and cleanup as in scope for every Cursor provider/runtime release.
16
+ - If a selected check fails, retain evidence and diagnose offline before choosing a repair or a necessary follow-up call. No automatic paid retries.
17
+ - Scope new live calls to changed behavior that needs real-service proof; retain valid proof for unchanged behavior. Do not run every checklist section or the full matrix as a routine commit/release step.
18
18
  - A check is passed only when the visible TUI/output, stderr diagnostics, and persisted JSONL agree with the expected behavior.
19
19
 
20
20
  ## Prerequisites
@@ -65,13 +65,13 @@ node scripts/validate-smoke-jsonl.mjs --replay-errors-only "$SMOKE_DIR/session-s
65
65
 
66
66
  The replay scan flags only error `toolResult` / error assistant messages with `Tool grep/cursor/find/ls not found`, not successful reads of docs that mention those strings. See [Cursor testing lessons](./cursor-testing-lessons.md#what-counts-as-a-replay-failure).
67
67
 
68
- `npm run smoke:live` is a helper only; it polls the section 3 TUI for answer/footer evidence and then cleans up the tmux session, but it does not replace the canonical rendered-PNG visual review in section 4. Run the relevant helper `--self-test` (`smoke:live`, `smoke:visual`, `smoke:steering`, or `smoke:isolated`) when changing sealed PATH or env wrappers. Release readiness requires the platform smoke gate. Run focused manual checks below when debugging detailed visual TUI behavior, bridge, standalone native replay, abort/cancel, packaging, cleanup, or any touched runtime surface before rerunning the platform gate.
68
+ `npm run smoke:live` is a helper only; it polls the section 3 TUI for answer/footer evidence and then cleans up the tmux session, but it does not replace the canonical rendered-PNG visual review in section 4. Run the relevant helper `--self-test` (`smoke:live`, `smoke:visual`, `smoke:steering`, or `smoke:isolated`) when changing sealed PATH or env wrappers. For changed behavior needing new live evidence, select the relevant manual check or existing single-suite/single-target platform run, not both by default. The comprehensive matrix is optional.
69
69
 
70
70
  Pass criteria:
71
71
 
72
72
  - `node --version` reports Node 24+.
73
73
  - `pi --version` reports official Pi 0.87.1 or the selected official-latest/current-`fitchmultz/pi` compatibility target.
74
- - `npm ls` shows exact `@cursor/sdk@1.0.32`; local `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` 0.87.1; and the bundled bridge runtime closure `@modelcontextprotocol/server@2.1.0`, `@modelcontextprotocol/hono@2.0.1`, `hono@4.13.9`, and `@hono/node-server@2.1.1`.
74
+ - `npm ls` shows exact `@cursor/sdk@1.0.32`; development `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` 0.99.1 and host TypeBox 1.3.27; and the bundled bridge runtime closure `@modelcontextprotocol/server@2.1.0`, `@modelcontextprotocol/hono@2.0.1`, `hono@4.13.9`, and `@hono/node-server@2.1.1`.
75
75
  - `cursor/grok-4.6` appears in the model list.
76
76
  - No Cursor key or auth token is printed.
77
77
  - If neither `~/.pi/agent/auth.json` cursor auth nor `CURSOR_API_KEY` is available, stop and report the live smoke as blocked.
@@ -136,7 +136,7 @@ Pass criteria:
136
136
 
137
137
  ## 4. Focused visual card/color rendering check
138
138
 
139
- This is the canonical inner-loop visual debug path for Cursor provider/runtime changes. It requires offscreen TUI visual inspection, not only JSONL or code review. Use Node 24+, official Pi 0.87.1 or another current compatibility target, exact `@cursor/sdk@1.0.32`, a fresh temporary session dir, Cursor SDK `plan` mode, native replay enabled, and the checked-in visual runner. The runner resolves `pi` by directly walking the parent `PATH`, uses `process.execPath` for Node, and prepends that Node directory for both prereq checks and tmux launches so `#!/usr/bin/env node` shims use the validated Node. The default matrix is native replay only: native replay registration is forced on, settings sources are `none`, the pi bridge is off, overlapping built-in pi tools are not exposed, and inherited Cursor SDK event-debug artifact env is cleared. With `--event-debug`, debug capture writes to a deterministic directory under `VISUAL_DIR`.
139
+ This is a visual debug menu for changed card/color behavior requiring new live evidence. Select only the relevant category below, or reuse a batched existing platform suite; do not execute the entire list by default. It requires offscreen TUI visual inspection, not only JSONL or code review. Use Node 24+, official Pi 0.87.1 or another current compatibility target, exact `@cursor/sdk@1.0.32`, a fresh temporary session dir, Cursor SDK `plan` mode, native replay enabled, and the checked-in visual runner. The runner resolves `pi` by directly walking the parent `PATH`, uses `process.execPath` for Node, and prepends that Node directory for both prereq checks and tmux launches so `#!/usr/bin/env node` shims use the validated Node. The default matrix is native replay only: native replay registration is forced on, settings sources are `none`, the pi bridge is off, overlapping built-in pi tools are not exposed, and inherited Cursor SDK event-debug artifact env is cleared. With `--event-debug`, debug capture writes to a deterministic directory under `VISUAL_DIR`.
140
140
 
141
141
  ```bash
142
142
  VISUAL_DIR="$(mktemp -d /tmp/pi-cursor-sdk-1016-visual.XXXXXX)"
@@ -185,7 +185,7 @@ npm run smoke:visual -- "${VISUAL_ARGS[@]}" \
185
185
  --prompt 'Stay in Cursor plan mode. If Cursor exposes plan, todo, task, or mode activity for this request, use that capability to outline a tiny unit test without editing files. Otherwise answer with a concise numbered plan. Do not use shell or file mutation tools.'
186
186
  ```
187
187
 
188
- By default, `npm run smoke:visual` writes `.ansi`, `.txt`, `.html`, `.png`, and `.jsonl.path` artifacts. If Playwright Chromium is unavailable in an agent-harness run, rerun with `--no-screenshot`, open the generated `.html` with `agent_browser`, save a PNG screenshot, and record that PNG path beside the runner artifacts. To visually audit bridge behavior or ambient Cursor settings, opt in with `--bridge`, `--bridge --expose-builtin-tools`, or `--setting-sources <value>` and label that evidence separately; do not count those opt-in runs as default native replay matrix proof.
188
+ By default, `npm run smoke:visual` writes `.ansi`, `.txt`, `.html`, `.png`, and `.jsonl.path` artifacts. Check browser availability before a paid run. If PNG rendering fails but ANSI/HTML evidence was retained, render that retained evidence with the canonical browser/xterm path and save a PNG; do not repeat the model call merely to produce a screenshot. To visually audit bridge behavior or ambient Cursor settings, opt in with `--bridge`, `--bridge --expose-builtin-tools`, or `--setting-sources <value>` and label that evidence separately; do not count those opt-in runs as default native replay matrix proof.
189
189
 
190
190
  Expected proof for each category is defined in [Cursor Native Tool Visual Audit Workflow](./cursor-native-tool-visual-audit.md). Do not mark a category passed because the prompt was sent. A category passes only when the PNG shows the expected card and the JSONL shows the expected completed `toolCall` / `toolResult` pair with the expected `isError` state.
191
191
 
@@ -193,7 +193,7 @@ Pass criteria:
193
193
 
194
194
  - PNG screenshots exist for every claimed card category, not only text/JSONL logs.
195
195
  - JSONL paths exist for every claimed card category.
196
- - Required cutover categories have matching PNG + JSONL proof from the default native replay matrix: read, grep/search, find/glob, list, shell success, write, edit/diff, and true read failure.
196
+ - Each selected changed category has matching PNG + JSONL proof; retained exact-input proof covers unchanged categories. Do not claim unobserved categories.
197
197
  - Native-looking read/search/find/list/shell/write/edit cards use intended pi card styling.
198
198
  - Shell success is not red/error-styled; stdout is readable.
199
199
  - Edit/diff previews show red/green added/removed colors and readable paths.
@@ -271,7 +271,7 @@ Allowed fields:
271
271
 
272
272
  - event name
273
273
  - run-safe correlation IDs that are not endpoint path components
274
- - bridge/pi tool call IDs derived from the run-safe ID
274
+ - bridge run IDs remain `cursor-pi-bridge-run-*`; provider-facing bridge/pi tool call IDs encode the same run UUID as 32 hex characters, use the `cursor-pi-bridge-<32 hex>-t<counter>` shape, and stay within the 64-character limit
275
275
  - hashed Cursor MCP call correlation IDs of the form `cursor-mcp-call-<8 hex chars>`
276
276
  - exposed pi/MCP tool name pairs
277
277
  - pending/queued/cancelled counts
@@ -316,7 +316,7 @@ Pass criteria:
316
316
 
317
317
  ## 9. Long-running bridge and abort/cancel
318
318
 
319
- Use this focused check when debugging abort cleanup. The platform smoke gate is the release-blocking source of truth for every Cursor provider/runtime release.
319
+ Select this check only when changed abort cleanup needs new real-service evidence; otherwise reuse valid retained proof. Keep process, bridge, and persisted-session cleanup assertions intact.
320
320
 
321
321
  Use a harmless long-running command and interrupt it after the bridge request is queued:
322
322
 
@@ -353,8 +353,8 @@ Script-enforced pass criteria:
353
353
 
354
354
  Additional manual usage checks for provider/accounting changes:
355
355
 
356
- - Tool-heavy runs should show nonzero output for visible assistant/tool-call activity.
357
- - Split runs should count consumed tool-result input once on the following assistant turn.
356
+ - Each assistant message's disjoint input/cache/output components should sum to `totalTokens` and describe one coherent current context, not cumulative billed spend.
357
+ - In split runs, earlier tool results can remain in later current-context estimates. Fresh, attributable LOCAL SDK usage takes precedence; late raw and billed facts remain in the separate ledger without rewriting emitted messages. See [context, compaction, and Cursor usage](../README.md#context-compaction-and-cursor-usage).
358
358
 
359
359
  ## 11. Standard local gates
360
360
 
@@ -385,7 +385,7 @@ Pass criteria:
385
385
 
386
386
  ## Coverage gaps this checklist makes explicit
387
387
 
388
- Everything in this section is in scope when using this checklist for Cursor provider/runtime debugging. Release readiness still comes from the platform smoke gate:
388
+ Use this list to choose meaningful changed-behavior coverage, not to trigger a full paid replay. Prefer offline contracts and valid retained evidence:
389
389
 
390
390
  - Long-running bridged tool abort/cancel cleanup.
391
391
  - Native replay cards beyond read, especially shell/edit/write cards, when those renderers change.
@@ -395,4 +395,4 @@ Everything in this section is in scope when using this checklist for Cursor prov
395
395
  - Ambient Cursor setting-source behavior when startup filtering or local Cursor settings handling changes.
396
396
  - Model discovery aliases/context variants when model-discovery code or Cursor SDK versions change.
397
397
 
398
- If any surface has no adequate platform or focused live check, add that coverage before release instead of assuming mocks cover reality.
398
+ If changed behavior needs real-service proof and neither retained evidence nor an existing focused check covers it, report the specific gap and choose the smallest meaningful check. Do not assume mocks prove service behavior or make unrelated optional lanes a release requirement.