@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.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 (79) hide show
  1. package/CHANGELOG.md +16 -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-provider-errors.js +3 -58
  7. package/dist/cursor-provider-live-run-drain.js +0 -3
  8. package/dist/cursor-provider-run-finalizer.js +4 -7
  9. package/dist/cursor-provider-run-outcome.js +1 -1
  10. package/dist/cursor-provider-turn-finalize.js +3 -55
  11. package/dist/cursor-provider-turn-prepare.js +8 -144
  12. package/dist/cursor-provider-turn-runner.js +9 -23
  13. package/dist/cursor-provider-turn-send.js +8 -35
  14. package/dist/cursor-runtime-state.js +6 -268
  15. package/dist/cursor-sdk-billed-usage.js +3 -18
  16. package/dist/cursor-sdk-platform-package.js +88 -0
  17. package/dist/cursor-session-agent.js +18 -14
  18. package/dist/cursor-skill-tool.js +12 -22
  19. package/dist/cursor-state.js +5 -8
  20. package/dist/cursor-usage-accounting.js +1 -1
  21. package/docs/cursor-dogfood-checklist.md +4 -4
  22. package/docs/cursor-live-smoke-checklist.md +23 -23
  23. package/docs/cursor-model-ux-spec.md +27 -30
  24. package/docs/cursor-native-tool-replay.md +4 -4
  25. package/docs/cursor-native-tool-visual-audit.md +7 -7
  26. package/docs/cursor-testing-lessons.md +23 -16
  27. package/docs/cursor-tool-surfaces.md +2 -4
  28. package/docs/platform-smoke-implementation.md +5 -5
  29. package/docs/platform-smoke.md +27 -72
  30. package/package.json +3 -17
  31. package/platform-smoke.config.mjs +2 -1
  32. package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
  33. package/scripts/platform-smoke/card-detect.mjs +1 -1
  34. package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
  35. package/scripts/platform-smoke/scenarios.mjs +1 -1
  36. package/scripts/platform-smoke/targets.mjs +14 -5
  37. package/src/cursor-agents-context-registration.ts +0 -5
  38. package/src/cursor-agents-context.ts +1 -3
  39. package/src/cursor-config.ts +8 -379
  40. package/src/cursor-provider-errors.ts +2 -62
  41. package/src/cursor-provider-live-run-drain.ts +0 -3
  42. package/src/cursor-provider-run-finalizer.ts +4 -12
  43. package/src/cursor-provider-run-outcome.ts +0 -3
  44. package/src/cursor-provider-turn-finalize.ts +3 -61
  45. package/src/cursor-provider-turn-prepare.ts +8 -165
  46. package/src/cursor-provider-turn-runner.ts +15 -31
  47. package/src/cursor-provider-turn-send.ts +7 -38
  48. package/src/cursor-provider-turn-types.ts +9 -30
  49. package/src/cursor-runtime-state.ts +6 -345
  50. package/src/cursor-sdk-billed-usage.ts +3 -24
  51. package/src/cursor-sdk-platform-package.ts +106 -0
  52. package/src/cursor-session-agent.ts +16 -12
  53. package/src/cursor-skill-tool.ts +10 -26
  54. package/src/cursor-state.ts +5 -10
  55. package/src/cursor-usage-accounting.ts +1 -3
  56. package/dist/cursor-cloud-lifecycle.js +0 -650
  57. package/dist/cursor-cloud-local-state.js +0 -460
  58. package/dist/cursor-cloud-options.js +0 -145
  59. package/dist/cursor-cloud-reporting.js +0 -222
  60. package/dist/cursor-ripgrep-path.js +0 -27
  61. package/scripts/cloud-runtime-smoke.d.mts +0 -42
  62. package/scripts/cloud-runtime-smoke.mjs +0 -623
  63. package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
  64. package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
  65. package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
  66. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
  67. package/scripts/lib/cloud-smoke-github.d.mts +0 -78
  68. package/scripts/lib/cloud-smoke-github.mjs +0 -331
  69. package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
  70. package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
  71. package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
  72. package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
  73. package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
  74. package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
  75. package/src/cursor-cloud-lifecycle.ts +0 -733
  76. package/src/cursor-cloud-local-state.ts +0 -536
  77. package/src/cursor-cloud-options.ts +0 -182
  78. package/src/cursor-cloud-reporting.ts +0 -267
  79. package/src/cursor-ripgrep-path.ts +0 -32
@@ -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 checklist for **minimal-surface** validation after prompt, bridge, replay, or manifest changes. This is the fast path from pi-cursor-composer dogfood sessions. It complements the current fork release evidence bar; the cross-platform matrix in [platform smoke](./platform-smoke.md) is deferred under issue #2.
4
4
 
5
5
  ## Minimal environment
6
6
 
@@ -55,11 +55,11 @@ After a Cursor **edit** tool call, confirm the activity card:
55
55
  - `details.diffString` present on the replay record
56
56
  - Collapsed diff preview with colored add/remove lines in the TUI
57
57
 
58
- Canonical visual evidence: `npm run smoke:visual` (see [Cursor native tool visual audit](./cursor-native-tool-visual-audit.md)).
58
+ Canonical visual evidence: `npm run smoke:visual -- --label release-check --prompt 'Read ./package.json and reply with its package name.'` (see [Cursor native tool visual audit](./cursor-native-tool-visual-audit.md)).
59
59
 
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
64
- - [Cursor live smoke checklist](./cursor-live-smoke-checklist.md) — inner-loop/manual debug checks
63
+ - [Deferred platform smoke matrix](./platform-smoke.md) — future cross-platform release gate tracked in issue #2
64
+ - [Cursor live smoke checklist](./cursor-live-smoke-checklist.md) — live release evidence and focused checks
65
65
  - [Cursor testing lessons](./cursor-testing-lessons.md) — auth, JSONL scans, plan-mode traps
@@ -1,20 +1,20 @@
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
+ > **Release evidence:** This checklist is part of the current fork release evidence bar. The Crabbox-backed cross-platform matrix is deferred under [issue #2](https://github.com/emmaneugene/pi-cursor-sdk/issues/2). See [docs/platform-smoke.md](./platform-smoke.md) for the retained future matrix.
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 for live provider/runtime evidence. 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 current fork evidence bar: a live print-mode Cursor run and `npm run smoke:visual`.
8
8
 
9
9
  ## Inner-loop rule
10
10
 
11
- - Build first: `npm run build` after any `src/` edit — the pi manifest loads compiled `dist/`, so unbuilt runs validate stale code. (the cloud/steering/local-resume/provider-debug launchers rebuild automatically even when run directly with `node scripts/...`; `smoke:live`/`smoke:visual`/`smoke:isolated` build via their npm scripts; direct `pi -e .` invocations do not build.)
11
+ - Build first: `npm run build` after any `src/` edit — the pi manifest loads compiled `dist/`, so unbuilt runs validate stale code. (the steering/local-resume/provider-debug launchers rebuild automatically even when run directly with `node scripts/...`; `smoke:live`/`smoke:visual`/`smoke:isolated` build via their npm scripts; direct `pi -e .` invocations do not build.)
12
12
  - Run from a clean working tree except for the intended branch diff.
13
- - Use the local extension under test: `pi --approve -e . --cursor-no-fast --model cursor/grok-4.6`.
13
+ - Use the local extension under test: `pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6`. `-ne` keeps a host `pi install` of this package from colliding with `-e .`.
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 live check fails, stop and fix it. Do not treat the deferred platform matrix as a current release blocker.
17
+ - Match focused live checks to the changed surface. Provider reality, TUI behavior, bridge behavior, replay behavior, diagnostics safety, abort/cancel cleanup, usage accounting, packaging, and cleanup each need targeted evidence when the change touches them.
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
@@ -24,7 +24,7 @@ export SMOKE_DIR="/tmp/pi-cursor-sdk-live-smoke-$(date +%Y%m%dT%H%M%S)"
24
24
  mkdir -p "$SMOKE_DIR"
25
25
  pi --version
26
26
  npm ls @cursor/sdk @earendil-works/pi-coding-agent @earendil-works/pi-ai @earendil-works/pi-tui
27
- pi --approve -e . --list-models cursor
27
+ pi -ne --approve -e . --list-models cursor
28
28
  ```
29
29
 
30
30
  Live pi runs resolve provider auth from **`~/.pi/agent/auth.json`**, not only shell env. Isolated smoke copies that file into a clean temporary `HOME`. Ensure `auth.json` includes a `cursor` provider entry, or export `CURSOR_API_KEY` as a fallback.
@@ -64,12 +64,12 @@ node scripts/validate-smoke-jsonl.mjs --replay-errors-only "$SMOKE_DIR/session-s
64
64
 
65
65
  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).
66
66
 
67
- `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.
67
+ `npm run smoke:live` polls the section 3 TUI for answer/footer evidence and then cleans up the tmux session. 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 both a live print-mode run and the visual smoke evidence. Run focused manual checks below when debugging detailed visual TUI behavior, bridge, standalone native replay, abort/cancel, packaging, cleanup, or any touched runtime surface.
68
68
 
69
69
  Pass criteria:
70
70
 
71
71
  - `pi --version` reports Pi 0.84.0 for this cutover baseline.
72
- - `npm ls` shows `@cursor/sdk@1.0.27` and local `@earendil-works/*@0.84.0` packages.
72
+ - `npm ls` shows `@cursor/sdk@1.0.30` and local `@earendil-works/*@0.84.0` packages.
73
73
  - `cursor/grok-4.6` appears in the model list.
74
74
  - No Cursor key or auth token is printed.
75
75
  - If neither `~/.pi/agent/auth.json` cursor auth nor `CURSOR_API_KEY` is available, stop and report the live smoke as blocked.
@@ -78,7 +78,7 @@ Pass criteria:
78
78
 
79
79
  ```bash
80
80
  PI_CURSOR_SETTING_SOURCES=none \
81
- pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
81
+ pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
82
82
  --session-dir "$SMOKE_DIR/basic" \
83
83
  --no-tools \
84
84
  -p 'Live smoke. Reply exactly: PI_CURSOR_SMOKE_OK' \
@@ -96,7 +96,7 @@ Pass criteria:
96
96
  ## 2. Default setting-source startup noise check
97
97
 
98
98
  ```bash
99
- pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
99
+ pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
100
100
  --session-dir "$SMOKE_DIR/default-settings" \
101
101
  --no-tools \
102
102
  -p 'Default settings smoke. Include PRODUCT=42 in the final answer.' \
@@ -118,14 +118,14 @@ Run a real interactive session under tmux:
118
118
  ```bash
119
119
  SESSION="pi-cursor-sdk-smoke-$(date +%s)"
120
120
  tmux new-session -d -s "$SESSION" -x 120 -y 40 -- zsh -lc \
121
- "cd '$PWD' && PI_CURSOR_SETTING_SOURCES=none pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 --session-dir '$SMOKE_DIR/tui' --session-id cursor-sdk-1016-tui --no-tools 'TUI smoke. Compute 19 + 23. Reply only with SUM=<number>.'"
121
+ "cd '$PWD' && PI_CURSOR_SETTING_SOURCES=none pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6 --session-dir '$SMOKE_DIR/tui' --session-id cursor-sdk-1016-tui --no-tools 'TUI smoke. Compute 19 + 23. Reply only with SUM=<number>.'"
122
122
  ```
123
123
 
124
124
  Observe with `tmux capture-pane -pt "$SESSION"` or attach manually.
125
125
 
126
126
  Pass criteria:
127
127
 
128
- - Footer shows `(cursor) composer-2-5`. With `--cursor-no-fast`, Cursor fast mode is off and the Cursor extension status should show `cursor:local · fast:off`; ignore unrelated status text from other extensions.
128
+ - Footer shows `(cursor) grok-4.6`. With `--cursor-no-fast`, Cursor fast mode is off and the Cursor extension status should show `cursor · fast:off`; ignore unrelated status text from other extensions.
129
129
  - The run uses Pi 0.84.0 `--session-id` successfully.
130
130
  - Assistant answer appears correctly.
131
131
  - `/session` shows one user and one assistant message for the simple run.
@@ -134,7 +134,7 @@ Pass criteria:
134
134
 
135
135
  ## 4. Focused visual card/color rendering check
136
136
 
137
- 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 Pi 0.84.0, `@cursor/sdk@1.0.27`, 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`.
137
+ This is the canonical visual evidence path for Cursor provider/runtime changes. It requires offscreen TUI visual inspection, not only JSONL or code review. Use Pi 0.84.0, `@cursor/sdk@1.0.30`, 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`.
138
138
 
139
139
  ```bash
140
140
  VISUAL_DIR="$(mktemp -d /tmp/pi-cursor-sdk-1016-visual.XXXXXX)"
@@ -191,7 +191,7 @@ Pass criteria:
191
191
 
192
192
  - PNG screenshots exist for every claimed card category, not only text/JSONL logs.
193
193
  - JSONL paths exist for every claimed card category.
194
- - 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.
194
+ - Required categories have matching PNG + JSONL proof from the default native replay matrix: read, grep/search, find/glob, shell success, write, edit/diff, and true read failure. The list category remains optional because Cursor does not reliably route it through native `ls`.
195
195
  - Native-looking read/search/find/list/shell/write/edit cards use intended pi card styling.
196
196
  - Shell success is not red/error-styled; stdout is readable.
197
197
  - Edit/diff previews show red/green added/removed colors and readable paths.
@@ -205,7 +205,7 @@ Pass criteria:
205
205
 
206
206
  ```bash
207
207
  PI_CURSOR_SETTING_SOURCES=none \
208
- pi --approve -e . --cursor-no-fast --cursor-mode plan --model cursor/grok-4.6 \
208
+ pi -ne --approve -e . --cursor-no-fast --cursor-mode plan --model cursor/grok-4.6 \
209
209
  --session-dir "$SMOKE_DIR/cursor-mode-plan" \
210
210
  --session-id cursor-sdk-1016-plan \
211
211
  --no-tools \
@@ -227,7 +227,7 @@ Pass criteria:
227
227
  PI_CURSOR_SETTING_SOURCES=none \
228
228
  PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1 \
229
229
  PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1 \
230
- pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
230
+ pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
231
231
  --session-dir "$SMOKE_DIR/bridge" \
232
232
  -p 'Bridge smoke. Do exactly two tool calls before answering: first call pi__read on ./package.json; second call pi__read on ./definitely-missing-pi-cursor-sdk-smoke-file.txt. Then answer: OK_NAME=<package name>; MISSING_RESULT=<error or success>. Do not use shell.' \
233
233
  > "$SMOKE_DIR/bridge.stdout.txt" \
@@ -236,7 +236,7 @@ pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
236
236
 
237
237
  Pass criteria:
238
238
 
239
- - stdout includes `OK_NAME=pi-cursor-sdk`.
239
+ - stdout includes `OK_NAME=@emmaneugene/pi-cursor-sdk`.
240
240
  - Diagnostics include `run_created`, `tools_exposed`, two `request_queued`, two `request_resolved`, and `run_disposed`.
241
241
  - The missing-file request has `isError: true`.
242
242
  - Persisted JSONL contains real pi tool calls named `read`, matching `toolResult` messages, and final assistant output.
@@ -248,7 +248,7 @@ Pass criteria:
248
248
  PI_CURSOR_SETTING_SOURCES=none \
249
249
  PI_CURSOR_PI_TOOL_BRIDGE=0 \
250
250
  PI_CURSOR_NATIVE_TOOL_DISPLAY=1 \
251
- pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
251
+ pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
252
252
  --session-dir "$SMOKE_DIR/native-replay" \
253
253
  -p 'Native replay smoke. Use your Cursor file-reading capability to read ./README.md, then answer README_SEEN=yes if it contains pi-cursor-sdk.' \
254
254
  > "$SMOKE_DIR/native-replay.stdout.txt" \
@@ -314,7 +314,7 @@ Pass criteria:
314
314
 
315
315
  ## 9. Long-running bridge and abort/cancel
316
316
 
317
- 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.
317
+ Use this focused check when debugging abort cleanup. The current fork release evidence bar is documented at the top of this checklist; the platform matrix is deferred under issue #2.
318
318
 
319
319
  Use a harmless long-running command and interrupt it after the bridge request is queued:
320
320
 
@@ -322,7 +322,7 @@ Use a harmless long-running command and interrupt it after the bridge request is
322
322
  PI_CURSOR_SETTING_SOURCES=none \
323
323
  PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1 \
324
324
  PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1 \
325
- pi --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
325
+ pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6 \
326
326
  --session-dir "$SMOKE_DIR/abort" \
327
327
  -p 'Abort smoke. Call pi__bash with command: sleep 30 && echo SHOULD_NOT_PRINT. Do not answer until the tool completes.'
328
328
  ```
@@ -383,7 +383,7 @@ Pass criteria:
383
383
 
384
384
  ## Coverage gaps this checklist makes explicit
385
385
 
386
- 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:
386
+ Everything in this section is in scope when using this checklist for Cursor provider/runtime debugging. The current fork release evidence bar is the full unit/typecheck suite, package dry run, a live print-mode run, and visual smoke. Add focused checks below when a change touches one of these surfaces:
387
387
 
388
388
  - Long-running bridged tool abort/cancel cleanup.
389
389
  - Native replay cards beyond read, especially shell/edit/write cards, when those renderers change.
@@ -393,4 +393,4 @@ Everything in this section is in scope when using this checklist for Cursor prov
393
393
  - Ambient Cursor setting-source behavior when startup filtering or local Cursor settings handling changes.
394
394
  - Model discovery aliases/context variants when model-discovery code or Cursor SDK versions change.
395
395
 
396
- If any surface has no adequate platform or focused live check, add that coverage before release instead of assuming mocks cover reality.
396
+ If any changed surface has no adequate focused live check, add that coverage before release instead of assuming mocks cover reality.
@@ -16,10 +16,8 @@ Current implementation notes:
16
16
  - Installed `@cursor/sdk` user messages accept images, and Cursor models are treated as image-capable; registered input metadata is `text` plus `image`.
17
17
  - Image payload forwarding sends images only from the latest user message. If the latest user turn is plain text after an earlier image turn, the transcript keeps an `[image omitted from transcript]` placeholder but no image bytes are sent to Cursor. The prompt explicitly tells Cursor that prior image bytes are unavailable and to ask the user to reattach or describe a prior image when needed. Carrying images forward across turns remains a future product decision because it affects token cost, privacy, stale visual context, and expected multimodal follow-up behavior.
18
18
  - Exact `@cursor/sdk@1.0.30` is a package dependency of this extension; users should not need a global SDK install. Pi 0.84.0 is the minimum supported and current validation baseline, while optional published Pi core peer dependencies use `"*"` ranges per current Pi package guidance.
19
- - After each finished SDK run, the provider calls `agent.getUsage()` (no `runId` on local agents; `runId` only for cloud `run-*` IDs) and maps billed spend into pi `usage` spend fields. Occupancy `totalTokens` uses only in-window local turn-ended occupancy below the latest compaction `tokensBefore`; billed rows never become occupancy, so footer/auto-compact stay aligned with the post-compact Cursor prompt.
20
- - Startup discovery does not duplicate Pi CLI parsing: it uses stored `~/.pi/agent/auth.json` API-key auth from `/login`, then `CURSOR_API_KEY`, otherwise it registers the bundled fallback catalog. Provider turns keep Pi's resolved `options.apiKey`. `/cursor-refresh-models` and `/cursor-cloud` mutations resolve provider `cursor` through the command context's Pi ModelRegistry, then normalize placeholders through `CURSOR_API_KEY`. The extension config file stores only non-secret Cursor-only state such as fast defaults and the user-level local HTTP transport preference.
21
- - Cursor Cloud repository overrides accept only HTTPS repository URLs without userinfo, query parameters, or fragments. Invalid values fail during preflight before `Agent.create()`, messages never echo the supplied URL, and shared provider/maintainer scrubbing removes URL/SCP-style userinfo defensively.
22
- - Cursor Cloud requires a persisted pi session. Immediately after remote `Agent.create()` returns, before debug work or abort checks, the provider appends a branch-local pi lifecycle entry, fsyncs the existing Pi session JSONL anchor through a read-write descriptor, and then fsyncs a newline-framed sidecar keyed by the stable pi session ID (POSIX mode `0600`; Windows inherits the user session directory ACL) in the session directory. Journal creation is exclusive, and existing append/read opens reject symlinks and require matching regular-file descriptor/path identity before using the descriptor. Existing session files use the exact lifecycle entry ID as anchor; fileless first turns use an orphan marker that a same-session-ID restart durably claims onto exactly one matching or replacement branch, surviving the timestamped path change and later JSONL creation without granting sibling access; returned run IDs are fsynced before abort/wait handling, readers skip malformed/truncated lines independently, and branch-only history events are reduced after deduplicated sidecar history, and tombstones are tracked before records exist. A durable sidecar result remains authoritative if its optional Pi mirror append fails; if the sidecar result itself fails, the prior durable intent remains pending and blocks retry rather than claiming success. `--no-session` and durable-ledger failures fail closed before send, while post-send ledger failure requests bounded cancellation. `/cursor-cloud` always validates the embedded session ID, accepts only null anchors while truly fileless, and reconciles each orphan to one branch before listing or mutation. Successive record events merge run/branch metadata monotonically even when mirrored sources arrive out of order. Archive/delete require resolved Cursor auth, fsync a durable intent before the SDK call, and fsync a durable success result afterward; unresolved intent blocks repeat mutation and requires dashboard inspection.
19
+ - After each finished SDK run, the provider calls `agent.getUsage()` and maps billed spend into pi `usage` spend fields. Occupancy `totalTokens` uses only in-window local turn-ended occupancy below the latest compaction `tokensBefore`; billed rows never become occupancy, so footer/auto-compact stay aligned with the post-compact Cursor prompt.
20
+ - Startup discovery does not duplicate Pi CLI parsing: it uses stored `~/.pi/agent/auth.json` API-key auth from `/login`, then `CURSOR_API_KEY`, otherwise it registers the bundled fallback catalog. Provider turns keep Pi's resolved `options.apiKey`. `/cursor-refresh-models` resolves provider `cursor` through the command context's Pi ModelRegistry, then normalizes placeholders through `CURSOR_API_KEY`. The extension config file stores only non-secret Cursor-only state such as fast defaults and the user-level local HTTP transport preference.
23
21
  - Local agents pass `settingSources: ["all"]` by default so Cursor MCP servers, plugin tools, project/user settings, and related Cursor-native capabilities are available. Users can narrow loading with a comma-separated list such as `PI_CURSOR_SETTING_SOURCES=project,user,plugins`, or disable ambient setting sources with `PI_CURSOR_SETTING_SOURCES=none`. `/cursor-refresh-config` calls the current pooled SDK agent's `agent.reload()` to refresh filesystem Cursor config without recreating the agent. The provider suppresses direct Cursor SDK bootstrap stdout/stderr/console noise (including late first-send workspace loading such as hook compatibility warnings) so it does not pollute pi's TUI.
24
22
  - On `cursor/*` models, pi-cursor-sdk removes only pi-generated `<project_instructions>` blocks that overlap the effective Cursor `settingSources`: `user` for `~/.pi/agent/AGENTS.md`; `project` for discovered repo/parent `AGENTS.md` and `CLAUDE.md` (verified Cursor behavior: local agents load project `AGENTS.md` and `CLAUDE.md`). `~/.pi/agent/CLAUDE.md` is not removed (Cursor user layer uses `~/.claude/CLAUDE.md`). Blocks are removed by exact pi serialization match from structured `contextFiles` via the `before_agent_start` hook, not in `buildCursorPrompt` sanitization. Suppression is skipped with `-nc`, `PI_CURSOR_SETTING_SOURCES=none`, narrowed sources such as `plugins` that omit the matching layer, or `PI_CURSOR_PRESERVE_PI_AGENTS_MD=1`. Switching away from a Cursor model restores pi's full context block on the next user message.
25
23
  - Cursor SDK models are treated as thinking-capable even when pi reports `thinking=no`; that pi column only means the SDK did not expose a pi-controllable thinking parameter for that model.
@@ -27,24 +25,24 @@ Current implementation notes:
27
25
  - Local Cursor agents get two tool surfaces. First, Cursor keeps the Cursor SDK local-agent tool surface plus configured Cursor settings, plugins, and Cursor MCP servers. Second, pi-cursor-sdk exposes active pi tools through a default-on, tokenized loopback MCP bridge when bridgeable tools exist.
28
26
  - `buildCursorPiToolBridgeSnapshot()` is the runtime capability source for pi bridge tools. It snapshots `pi.getActiveTools()` and `pi.getAllTools()`, carries pi 0.77+ per-tool `promptGuidelines` into bridge MCP descriptions, filters internal replay names, hides overlapping built-in pi tools (`read`, `bash`, `write`, `edit`, `grep`, `find`, `ls`) unless `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1`, and creates collision-safe MCP names such as `pi__sem_reindex`. Cursor discovers the current run's exposed bridge tools through MCP `listTools`. Bootstrap prompts include a compact callable-surface manifest from `buildCursorToolManifestText()` by default (`PI_CURSOR_TOOL_MANIFEST=1`); disable with `PI_CURSOR_TOOL_MANIFEST=0`. There is no per-turn visible tool list, status manifest, or footer manifest. User-facing summary: [Cursor tool surfaces in pi](./cursor-tool-surfaces.md).
29
27
  - Prompt text is the primary provider/bridge contract. Bootstrap prompts carry a short boundary block plus the callable-surface manifest by default (`PI_CURSOR_TOOL_MANIFEST=1`). MCP `listTools` descriptions use a one-line pointer to the bootstrap prompt instead of repeating the full contract (`buildCursorPiBridgeMcpToolDescription()`). Cursor must call the exposed `pi__*` MCP name, not the real pi tool name shown in pi history or transcripts. When exposed, `pi__mcp` takes preference over Cursor-configured MCP for MCP work and `pi__subagent` takes preference over Cursor-native subagents for delegation; the Cursor-native surfaces remain fallbacks when the matching pi bridge tool is absent or unavailable. Pi emits and executes the real pi tool name. Maintainer debug: `/cursor-tools` prints bridge/manifest enablement, effective `PI_CURSOR_SETTING_SOURCES`, and the current callable-surface snapshot.
30
- - The provider also registers `cursor_ask_question` for Cursor models when the bridge and default-on `PI_CURSOR_ASK_QUESTION` control are enabled. While the tool awaits pi UI input it emits package event `pi-cursor-sdk:ask-question:blocked` with `{ active: true }` and clears `{ active: false }` in `finally`; the tool runs with `executionMode: "sequential"` so parallel sibling calls cannot overlap dialogs. Cursor sees it as `pi__cursor_ask_question`, and pi executes it through the normal tool path so interactive users can choose options from pi UI. `PI_CURSOR_ASK_QUESTION=0` removes only this tool while preserving the rest of the bridge. In non-UI modes it reports that UI is unavailable so Cursor can state a default assumption instead. When pi has visible Agent Skills loaded, the provider rewrites the skill catalog for Cursor and registers `cursor_activate_skill` as `pi__cursor_activate_skill`; pi executes it through the normal tool path so Cursor can load the full `SKILL.md` and skill resource list for the current pi-loaded skill source of truth. `PI_CURSOR_PI_TOOL_BRIDGE=0` disables the local bridge, including question and skill activation bridging. Cloud Cursor agents remain out of scope for the bridge.
28
+ - The provider also registers `cursor_ask_question` for Cursor models when the bridge and default-on `PI_CURSOR_ASK_QUESTION` control are enabled. While the tool awaits pi UI input it emits package event `pi-cursor-sdk:ask-question:blocked` with `{ active: true }` and clears `{ active: false }` in `finally`; the tool runs with `executionMode: "sequential"` so parallel sibling calls cannot overlap dialogs. Cursor sees it as `pi__cursor_ask_question`, and pi executes it through the normal tool path so interactive users can choose options from pi UI. `PI_CURSOR_ASK_QUESTION=0` removes only this tool while preserving the rest of the bridge. In non-UI modes it reports that UI is unavailable so Cursor can state a default assumption instead. When pi has visible Agent Skills loaded, the provider rewrites the skill catalog for Cursor and registers `cursor_activate_skill` as `pi__cursor_activate_skill`; pi executes it through the normal tool path so Cursor can load the full `SKILL.md` and skill resource list for the current pi-loaded skill source of truth. `PI_CURSOR_PI_TOOL_BRIDGE=0` disables the local bridge, including question and skill activation bridging.
31
29
  - The bridge queues MCP calls, emits provider `toolcall_*` events, waits for matching pi `toolResult` messages by `toolCallId`, resolves the result back into the same live Cursor SDK run without creating a new `Agent`, and never calls tool `execute()` handlers directly. The same-run resume invariant holds unless the run was disposed, aborted, or cancelled.
32
30
  - Cursor SDK MCP tool calls use a guarded timeout override because installed `@cursor/sdk` 1.0.30 still has a 60-second MCP request default with no public per-server timeout option. The extension extends the verified Cursor SDK MCP `callTool` timeout path to 3600 seconds by default and shortens the verified first-send MCP initialize/listTools timeout paths to 10 seconds by default so unavailable configured MCP servers do not block the first reply for a full minute; unknown MCP protocol timeout stacks keep the SDK default. Users can override tool-call timeouts with `PI_CURSOR_MCP_TOOL_TIMEOUT_MS` or `PI_CURSOR_MCP_TOOL_TIMEOUT_SECONDS`, and initialize/listTools timeouts with `PI_CURSOR_MCP_CONNECT_TIMEOUT_MS` or `PI_CURSOR_MCP_CONNECT_TIMEOUT_SECONDS`. Bridged `CallTool` waits also have a local fail-closed deadline that defaults to and cannot exceed the effective MCP tool timeout; `PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS` can lower it, expiry or MCP cancellation aborts active pi execution when available, and expired bridge events are dropped before pi tool emission.
33
- - Cursor SDK local safety controls are off by default. `--cursor-auto-review` / `PI_CURSOR_AUTO_REVIEW` and `--cursor-sandbox` / `PI_CURSOR_SANDBOX` pass only explicit enabled values into `Agent.create({ local })`; user or trusted project config can set `local.autoReview` and `local.sandboxOptions.enabled`; project config is active only when Pi's project-trust flow reached the extension and approved the project or the run used explicit `--approve`, and project saves require the same immutable trust provenance rather than creating Pi trust resources automatically. Pi 0.84.0 loads `pi install -l` project-local extensions after the trust event, so those installs require `--approve` on every run that reads or writes `.pi/cursor-sdk.json`. Explicit runtime, fast-default, and HTTP transport saves preserve unrecognized config fields, reject malformed or non-object JSON without rewriting it, and use one lock-protected read-modify-write path; fast saves mutate only the selected model key. Because Pi can mutate its in-memory session branch before a journal append throws, a completed global save is authoritative and the command reports the partial journal failure instead of attempting an ambiguous rollback; the new global value stays authoritative over stale branch entries until a later successful save or session restart.
34
- - Local HTTP/1.1/SSE compatibility is strictly opt-in through `PI_CURSOR_HTTP_1_1`, `/cursor-http on|off|toggle`, or user `cursor-sdk.json` `local.useHttp1ForAgent`. Precedence is session, environment, user, then the built-in unset default; project config is excluded. Unset makes no `Cursor.configure()` call. Explicit values configure the installed SDK before local `Agent.create()`, extension-owned explicit state is cleared with the SDK's documented `null` reset when returning to unset and during session shutdown before module reload, and default/HTTP2/HTTP1 choices split pooled local agents. Pi's supported CLI/TUI/print/RPC lifecycle has one active session runtime per process; concurrent independent `AgentSession` embedding in one process is outside this transport toggle's contract because the installed SDK setting and executor cache are module-global. The footer adds `http1` only for enabled local runtime; cloud creation and status remain untouched.
31
+ - Cursor SDK local safety controls are off by default. `--cursor-auto-review` / `PI_CURSOR_AUTO_REVIEW` and `--cursor-sandbox` / `PI_CURSOR_SANDBOX` pass only explicit enabled values into `Agent.create({ local })`; user or trusted project config can set `local.autoReview` and `local.sandboxOptions.enabled`; project config is active only when Pi's project-trust flow reached the extension and approved the project or the run used explicit `--approve`, and project saves require the same immutable trust provenance rather than creating Pi trust resources automatically. Pi 0.84.0 loads `pi install -l` project-local extensions after the trust event, so those installs require `--approve` on every run that reads or writes `.pi/cursor-sdk.json`. Fast-default and HTTP transport saves preserve unrecognized config fields, reject malformed or non-object JSON without rewriting it, and use one lock-protected read-modify-write path; fast saves mutate only the selected model key. Because Pi can mutate its in-memory session branch before a journal append throws, a completed global save is authoritative and the command reports the partial journal failure instead of attempting an ambiguous rollback; the new global value stays authoritative over stale branch entries until a later successful save or session restart.
32
+ - Local HTTP/1.1/SSE compatibility is strictly opt-in through `PI_CURSOR_HTTP_1_1`, `/cursor-http on|off|toggle`, or user `cursor-sdk.json` `local.useHttp1ForAgent`. Precedence is session, environment, user, then the built-in unset default; project config is excluded. Unset makes no `Cursor.configure()` call. Explicit values configure the installed SDK before local `Agent.create()`, extension-owned explicit state is cleared with the SDK's documented `null` reset when returning to unset and during session shutdown before module reload, and default/HTTP2/HTTP1 choices split pooled local agents. Pi's supported CLI/TUI/print/RPC lifecycle has one active session runtime per process; concurrent independent `AgentSession` embedding in one process is outside this transport toggle's contract because the installed SDK setting and executor cache are module-global. The footer adds `http1` only when HTTP/1.1 transport is enabled.
35
33
  - Bridge diagnostics are opt-in only: `PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1` writes typed, allowlisted, scrubbed single-line JSONL records to `process.stderr` with prefix `[pi-cursor-sdk:bridge]`. Diagnostics are scrubbed operational logs, not anonymous telemetry. They intentionally include tool names, safe correlation IDs, run lifecycle, exposed pi↔MCP name pairs, queued requests, result resolution, rejection, cancellation, and pending counts. Correlation IDs are generated independently from the tokenized endpoint path, and Cursor MCP call IDs are hashed before serialization. Diagnostics must not include endpoint paths/URLs/path components/tokens, API keys, bearer tokens, cookies, session credentials, raw args/results, stdout/stderr payloads, file contents, Cursor settings output, or local private session paths in tracked docs, and they must not call pi UI status, notification, or footer APIs. If tool names themselves are unacceptable for a release target, bridge debug diagnostics are not safe for shared logs under the current contract.
36
34
  - This repo does not provide a generic desktop-automation, browser-driver, or CDP recipe. Provider docs should describe pi-cursor-sdk's Cursor provider/bridge contract only.
37
35
  - Cursor internal tool activity is recorded from SDK events and scrubbed. Maintainer reference for `@cursor/sdk@1.0.30` `ToolType` values, runtime alias normalization, and intentional mapping/fallback rules: [Cursor native tool replay — SDK ToolType replay matrix](./cursor-native-tool-replay.md#sdk-tooltype-replay-matrix) (official SDK docs: https://cursor.com/docs/sdk/typescript). In TUI sessions and structured JSON/RPC modes, supported completed `read`, `bash`, `grep`, `find`, `ls`, `edit`, `write`, diagnostics, delete, todo/plan, task, image generation, MCP, semantic search, and screen recording activity is replayed through pi's native tool-call rendering path with recorded Cursor results, so users and JSON/RPC consumers can see native-looking cards/events without rerunning Cursor's reads/shell commands/file edits. Cursor `glob` activity is replayed through native `find` cards. Cursor write activity is replayed through native-looking `write` cards, and Cursor StrReplace/edit activity uses native-looking `edit` only when recorded arguments truthfully satisfy pi's `edit` schema; path-only Cursor edit and notebook edit replay falls back to neutral Cursor activity before pi validation. Diagnostics, delete, todos/plans, task/subagent, image, and MCP activity use neutral Cursor activity cards with pi's default success/error shell. Cursor SDK `task` activity is labeled **Cursor subagent** by default because it represents Cursor-spawned child-agent work; the card summary includes description plus subagent kind/model/short ID when Cursor reports them, and `PI_CURSOR_TASK_PRESENTATION=task` restores the older **Cursor task** wording for comparison. This is visibility over Cursor SDK task events, not a native pi subagent session: pi shows start/final output plus any `conversationSteps` tool-call summaries Cursor returns, but cannot show a live nested read/shell/MCP trail when the SDK only returns final subagent text. Neutral Cursor activity calls include `activityTitle` and, when available, `activitySummary` so partial/collapsed cards preserve identity such as `Cursor plan`, `Cursor todos`, `Cursor subagent`, `Cursor MCP`, or `Cursor edit`. For long-running or externally meaningful Cursor tools (`task`, `shell`, `mcp`, `generateImage`, `recordScreen`, `semSearch`, web search/fetch, plan/todo), the provider may surface one low-noise deferred in-progress thinking line such as `Cursor MCP: external_search` from bounded, scrubbed SDK args; fast local tools (`read`, `grep`, `glob`, and similar) skip lifecycle lines when completion follows immediately, and pi bridge MCP calls are excluded because pi already shows real pi tool execution ([lifecycle visibility](./cursor-native-tool-replay.md#low-noise-tool-lifecycle-visibility)). Replay-only tools display recorded Cursor results, normalize workspace-local paths/diff headers for display, use pi diff colors for edit previews and path-inferred syntax highlighting for write previews, and fail closed if called without a recorded result. Native replay wrappers are registered only for tool names not already owned by another extension; conflicting tools use the bounded scrubbed transcript fallback. Cursor workflow tools such as mode/task/todo/plan activity are not pi workflow controls; reported todo/plan events are displayed as Cursor activity only. Plan/todo replay cards can be followed by Cursor's final plan text, selected from `run.wait().result` when Cursor provides one and trimmed against already-emitted text. Started Cursor SDK tool calls that never receive a completion event are surfaced with bounded user-visible labels/traces (neutral activity cards when native replay routing allows, otherwise the same inactive or transcript trace fallbacks used for completed replay) instead of being silently discarded when the run failed, was aborted, or produced no assistant text; after a successful text-producing run, missing-completion starts remain maintainer-debug-only for all tools: installed `@cursor/sdk` 1.0.30 emits `tool-call-started` with no completion delta, step, or conversation entry when a permission policy or hook denies a call, and offers no way to distinguish such denials from lost completions, so suppression is the deliberate choice over false error cards. Explicit failures remain visible when Cursor reports them through completed tool calls or step results. Pi bridge MCP starts remain excluded from duplicate incomplete Cursor cards because pi already shows real pi tool execution. `PI_CURSOR_NATIVE_TOOL_DISPLAY=0` disables native replay, and `PI_CURSOR_REGISTER_NATIVE_TOOLS=0` is a registration-only opt-out that keeps the transcript fallback without shadowing pi tool names. When bridge or native replay cards are emitted, the provider mirrors Codex's turn shape as Cursor SDK activity arrives: assistant `toolUse`, pi `toolResult`s, live post-tool Cursor thinking/text, any later tool batches as further `toolUse` turns, then Cursor's final assistant answer. For shell replay, completed `stdout` / `stderr` are primary; unambiguous `shell-output-delta` data is also shown as bounded live progress while one shell call is active and used as display-only fallback for empty successful shell completions, while overlapping shell calls drop ambiguous deltas instead of guessing. Print mode keeps bounded scrubbed transcript output instead, preserving `pi -p` assistant text output. Cursor text deltas stream live when no live-run turn split is active.
38
36
  - Cursor native replay uses one neutral replay tool name, `cursor`, plus native-compatible card names when renderer-compatible (`read`, `bash`, `grep`, `find`, `ls`, `edit`, `write`). Neutral replay identity lives in `activityTitle`, `activitySummary`, and typed replay details, not in extra registered tool names. Bridge MCP names such as `pi__sem_reindex` are MCP-only; pi session output uses real pi tool names.
39
- - Local Cursor SDK usage events are used when the SDK reports them before the corresponding pi turn is emitted and the reported counts fit the selected pi model window. For each safe local SDK-attributed assistant turn, `usage.input`, `usage.output`, `usage.cacheRead`, and `usage.cacheWrite` come from the latest per-turn raw `turn-ended.usage` (not SDK `toTokenUsage`): observed local runtime keeps `inputTokens` as the full prompt with cache fields as a partition, even though published SDK `TokenUsage.totalTokens` sums all four fields. Pi maps that raw local shape to disjoint components (`input = inputTokens - cacheReadTokens - cacheWriteTokens`) and `usage.totalTokens = inputTokens + outputTokens` for occupancy/compaction only when that total is below the latest compaction `tokensBefore`; otherwise occupancy uses the post-compaction estimate floor. Cloud billed `getUsage()` rows map to spend fields only and never become occupancy. Approximate fallback never reports less occupancy than the last compatible same-model in-window assistant measurement in context. Cumulative `RunResult.usage` is never used for per-message occupancy. If the local SDK reports no usage in time, or reports full-agent-context-sized usage outside the selected model window, the provider falls back to local `input/output` activity estimates while setting `usage.totalTokens` to the current replayable context estimate so footer/compaction context does not collapse after split tool turns; after a split live-run turn times out waiting for SDK usage, later SDK usage for that live run is ignored rather than risk applying stale usage to the wrong pi turn. Cursor SDK cost is unavailable, so cost remains absent/zero. `src/cursor-usage-accounting.ts` owns this policy.
37
+ - Local Cursor SDK usage events are used when the SDK reports them before the corresponding pi turn is emitted and the reported counts fit the selected pi model window. For each safe local SDK-attributed assistant turn, `usage.input`, `usage.output`, `usage.cacheRead`, and `usage.cacheWrite` come from the latest per-turn raw `turn-ended.usage` (not SDK `toTokenUsage`): observed local runtime keeps `inputTokens` as the full prompt with cache fields as a partition, even though published SDK `TokenUsage.totalTokens` sums all four fields. Pi maps that raw local shape to disjoint components (`input = inputTokens - cacheReadTokens - cacheWriteTokens`) and `usage.totalTokens = inputTokens + outputTokens` for occupancy/compaction only when that total is below the latest compaction `tokensBefore`; otherwise occupancy uses the post-compaction estimate floor. Approximate fallback never reports less occupancy than the last compatible same-model in-window assistant measurement in context. Cumulative `RunResult.usage` is never used for per-message occupancy. If the local SDK reports no usage in time, or reports full-agent-context-sized usage outside the selected model window, the provider falls back to local `input/output` activity estimates while setting `usage.totalTokens` to the current replayable context estimate so footer/compaction context does not collapse after split tool turns; after a split live-run turn times out waiting for SDK usage, later SDK usage for that live run is ignored rather than risk applying stale usage to the wrong pi turn. Cursor SDK cost is unavailable, so cost remains absent/zero. `src/cursor-usage-accounting.ts` owns this policy.
40
38
  - Audit observation, 2026-05-19, superseded by the 2026-05-21 replay pass and #68 incomplete visibility, then narrowed by the 2026-05-26 fast-local suppression: a missing-file read with Composer 2.5 emitted `tool-call-started` for Cursor `read`, then streamed final text `Error: File not found`, but did not emit `tool-call-completed` or an `onStep` `toolCall` error result. Leftover started calls from failed, aborted, or no-text runs are surfaced at run completion through the same native replay routing as completed tools (activity cards when allowed, otherwise inactive/transcript traces), while all missing-completion starts are debug-only after a successful text-producing run (widened 2026-09-04 after a `beforeShellExecution` deny-hook reproduction against `@cursor/sdk` 1.0.30 showed a denied shell call emits no completion delta, step, or conversation entry; the same suppression is applied to all tools as a product choice). Cursor-reported completed/step errors remain visible.
41
39
  - Maintainer visual verification for replay-card changes should follow [Cursor Native Tool Visual Audit Workflow](./cursor-native-tool-visual-audit.md): offscreen PTY-driven pi run, xterm.js/Playwright screenshot rendering, and JSONL inspection before accepting commits or PRs.
42
- - Cursor provider/runtime releases must pass the local [Platform Smoke Gate](./platform-smoke.md): `npm run smoke:platform:all`. Cloud-runtime changes must also pass `npm run smoke:cloud`. Use [Cursor Live Smoke Checklist](./cursor-live-smoke-checklist.md) only for focused inner-loop/debug runs with real `pi --approve -e . --cursor-no-fast --model cursor/grok-4.6` invocations, manual observation, temporary session dirs, diagnostics scans, and persisted JSONL inspection. See [Cursor testing lessons](./cursor-testing-lessons.md) for auth.json seeding, isolated smoke harnesses, and replay JSONL scans.
40
+ - Current fork release evidence for Cursor provider/runtime changes is the full unit/typecheck suite, package dry run, a live print-mode Cursor run, and visual smoke. The Crabbox-backed platform matrix is deferred under [issue #2](https://github.com/emmaneugene/pi-cursor-sdk/issues/2). Use [Cursor Live Smoke Checklist](./cursor-live-smoke-checklist.md) for live verification with real `pi -ne --approve -e . --cursor-no-fast --model cursor/grok-4.6` invocations, temporary session dirs, diagnostics scans, and persisted JSONL inspection. See [Cursor testing lessons](./cursor-testing-lessons.md) for auth.json seeding, isolated smoke harnesses, and replay JSONL scans.
43
41
  - For models without a catalog `context` parameter, context windows are not hardcoded. The extension ships a bundled SDK-derived default/non-Max cache generated from `createAgentPlatform().checkpointStore.loadLatest(agentId).tokenDetails.maxTokens`. Successful runs can update a local override cache, but model discovery does not probe models at startup.
44
42
  - Max Mode context windows are distinct from default/non-Max context windows. `@cursor/sdk` 1.0.30 documentation says the SDK may enable Max Mode automatically when a selected model requires it, but the public local-agent `ModelSelection` path still does not expose a manual Max Mode selector. Do not advertise Max Mode context windows unless the SDK catalog exposes an exact parameter/variant or the SDK public API adds a Max Mode selector that the extension actually sends.
45
43
  - The installed `@cursor/sdk` exposes latest-style `ModelListItem.aliases`. The extension registers only unambiguous aliases as pi model IDs (with the same context suffixes when applicable) and sends the alias back in `ModelSelection.id`. Cursor-only fast preferences are keyed by the selected SDK model ID/alias, with read fallback for older preferences keyed by the underlying catalog `id`. Aliases shared by multiple base models, such as generic family aliases, are skipped because the pi row metadata would otherwise imply one base model while Cursor may resolve the alias to another.
46
44
  - Local restart resume treats user entries already present at `session_start` or selected by tree navigation as crash-ambiguous: an older SDK handle cannot span them because the prior process may already have submitted that prompt. A user entry appended after startup in the current process may span the last completed handle for the normal next send.
47
- - Persisted pi sessions use a session-scoped Cursor SDK SQLite store at `<getDefaultSdkStateRoot(cwd)>/pi-sessions/<session-hash>/`; create/resume, transcript reads, checkpoint lookup, and exact-ID cleanup all receive that same store. Fileless acquisitions use unique OS-temporary stores that are removed on graceful disposal; invalidation starts a fresh agent instead of reopening a disposed temporary store. Resume entries version the store identity. Legacy entries still resume against the SDK default workspace store, then move to the per-session store after fallback or agent replacement. Removing a persisted pi session does not automatically remove its store directory; only a verified session-derived `pi-sessions/<session-hash>` root may be removed after no pi process uses it. The shared SDK default workspace root recorded by legacy entries must never be removed as session cleanup. Cloud agents are unchanged.
45
+ - Persisted pi sessions use a session-scoped Cursor SDK SQLite store at `<getDefaultSdkStateRoot(cwd)>/pi-sessions/<session-hash>/`; create/resume, transcript reads, checkpoint lookup, and exact-ID cleanup all receive that same store. Fileless acquisitions use unique OS-temporary stores that are removed on graceful disposal; invalidation starts a fresh agent instead of reopening a disposed temporary store. Resume entries version the store identity. Legacy entries still resume against the SDK default workspace store, then move to the per-session store after fallback or agent replacement. Removing a persisted pi session does not automatically remove its store directory; only a verified session-derived `pi-sessions/<session-hash>` root may be removed after no pi process uses it. The shared SDK default workspace root recorded by legacy entries must never be removed as session cleanup.
48
46
  - Session-scoped Cursor SDK agent pooling reuses one live `@cursor/sdk` agent across compatible follow-up turns within the same pi session scope. Independently, each distinct local agent whose `Agent.send()` is initiated is best-effort recorded once per native pi session as a non-resumable `cursor-sdk-agent-lineage` custom entry (including failed/cancelled sends and when local resume is disabled). Cloned/forked sessions record lineage under their own pi session ID; donor entries do not suppress the new session. `planCursorSessionSend()` in `src/cursor-session-send-policy.ts` decides whether the next turn sends a full bootstrap prompt or an incremental follow-up, whether the SDK agent must be recreated, and why. `computeCursorContextFingerprint()` and `shouldBootstrapCursorContext()` remain the context-only bootstrap signal. The pool recreates the agent when context diverges, when branch or compaction summaries appear after `/tree` navigation or compaction, after 20 completed incremental sends, when the API key identity changes, after send errors, after five minutes without a successful send (`CURSOR_LOCAL_AGENT_IDLE_MS`; `Agent.create`, not `Agent.resume`), on `session_shutdown`, and when `session_before_tree` / `session_tree` invalidate the active branch. Incremental sends omit the full Cursor SDK tool boundary block because the session agent retains prior bootstrap context, but every send ends with a short tool tail guard placed after the latest user request (including an explicit shell `cd` hint). True incremental sends also omit invariant Pi system instructions; system-prompt changes are part of the context fingerprint and force a full context-divergence bootstrap that includes the updated system section.
49
47
  - Pi steering/follow-up delivery can arrive while a split live Cursor SDK run is still active. The provider resolves pending live runs by scanning trailing `toolResult` messages while skipping trailing `user` messages, tracks the active live run per session scope, and resumes the in-flight run instead of calling `Agent.send()` again. When the context ends with steering user text after tool results, the provider releases the prior live run and chains an incremental `Agent.send()` for the latest user message in the same provider turn; if the prior run emits more text or tool requests after steering arrives, that stale activity is cancelled instead of surfacing another old-run tool turn and losing the new user input. A pre-send guard waits for or resumes any still-active scoped live run before starting a fresh send so `@cursor/sdk` `AgentBusyError` (`already has active run`) does not surface to pi users. Pooled session agents mark busy as soon as live/direct `run.wait()` tracking starts (`trackRunCompletion` on the session lease), and `acquireSessionCursorAgent()` awaits that busy state before returning a lease so send planning, transcript offsets, and later `Agent.send()` do not race the prior turn's SDK run completion (for example pi auto-compaction summarization). `session_before_compact` calls `prepareCursorSessionForCompaction()` to release scoped live-run drain state and reset the pooled agent before summarization streams. Tracked completions and send commits are scoped to the pooled agent `instanceId` so disposal/replacement drops stale tracking and ignores late commits from disposed agents.
50
48
 
@@ -388,7 +386,7 @@ Rules:
388
386
  - Toggle unsuffixed models with `/cursor-fast`; do not persist a new default while a virtual fast alias is selected.
389
387
  - Store per-session and global per-base-model preferences for unsuffixed models.
390
388
  - When calling `Agent.create()` or `agent.send()`, include the selected `fast` value in Cursor model params.
391
- - Show fast-capable local models as `cursor:local · fast:on` or `cursor:local · fast:off` through `ctx.ui.setStatus()` while a Cursor model is active; cloud runtime shows `cursor:cloud · fast:n/a`.
389
+ - Show fast-capable models as `cursor · fast:on` or `cursor · fast:off` through `ctx.ui.setStatus()` while a Cursor model is active.
392
390
  - Keep `--cursor-fast` and `--cursor-no-fast` as explicit process-level force flags.
393
391
 
394
392
  Reason:
@@ -399,9 +397,9 @@ Reason:
399
397
  Status examples:
400
398
 
401
399
  ```text
402
- cursor:local · fast:off
403
- cursor:local · fast:on
404
- cursor:local · fast:on · http1
400
+ cursor · fast:off
401
+ cursor · fast:on
402
+ cursor · fast:on · http1
405
403
  ```
406
404
 
407
405
  ## Cursor SDK Mode Behavior
@@ -429,10 +427,9 @@ Rules:
429
427
  Status examples:
430
428
 
431
429
  ```text
432
- cursor:local · fast:n/a · plan
433
- cursor:local · fast:off · plan
434
- cursor:local · fast:on · plan
435
- cursor:cloud · fast:n/a · plan
430
+ cursor · fast:n/a · plan
431
+ cursor · fast:off · plan
432
+ cursor · fast:on · plan
436
433
  ```
437
434
 
438
435
  ## Footer Behavior
@@ -441,7 +438,7 @@ Hard requirement:
441
438
 
442
439
  - Leave pi's default footer intact.
443
440
  - Do not use `ctx.ui.setFooter()` for the first pass.
444
- - Use `ctx.ui.setStatus()` only while a Cursor model is active, showing Cursor-only state that pi cannot show natively, such as `cursor:local`, `cursor:cloud`, local `fast:on|off|n/a`, enabled local `http1`, and non-default Cursor SDK `plan` mode.
441
+ - Use `ctx.ui.setStatus()` only while a Cursor model is active, showing Cursor-only state that pi cannot show natively, such as `cursor`, `fast:on|off|n/a`, enabled `http1`, and non-default Cursor SDK `plan` mode.
445
442
  - Non-cursor models must have no Cursor status.
446
443
 
447
444
  Reason:
@@ -455,13 +452,13 @@ Expected native footer behavior:
455
452
  - provider/model is shown by pi from the selected `cursor` model,
456
453
  - thinking level is shown by pi when `reasoning` is true,
457
454
  - context usage is computed from `contextWindow`,
458
- - extension status adds only Cursor-only text such as `cursor:local · fast:n/a`, `cursor:local · fast:off`, `cursor:local · fast:on · http1`, `cursor:local · fast:on · plan`, or `cursor:cloud · fast:n/a`.
455
+ - extension status adds only Cursor-only text such as `cursor · fast:n/a`, `cursor · fast:off`, `cursor · fast:on · http1`, or `cursor · fast:on · plan`.
459
456
 
460
457
  `ctx.ui.setStatus()` adds an extension status line in the default footer. It does not patch the built-in model segment. The native shape is closer to:
461
458
 
462
459
  ```text
463
460
  ... (cursor) gpt-5.5@1m • medium
464
- cursor:local · fast:off · plan
461
+ cursor · fast:off · plan
465
462
  ```
466
463
 
467
464
  not:
@@ -569,7 +566,7 @@ pi --model cursor/gpt-5.5@1m --cursor-fast -p "Say ok only"
569
566
 
570
567
  ## Discovered Model Capability Examples
571
568
 
572
- These examples document the capability shapes the extension handles, not an exhaustive live catalog. The exact Cursor catalog changes over time; use `pi --approve -e . --list-models cursor` or `Cursor.models.list()` for the current model surface. When the SDK reports aliases, only unambiguous aliases are registered; shared generic aliases are skipped.
569
+ These examples document the capability shapes the extension handles, not an exhaustive live catalog. The exact Cursor catalog changes over time; use `pi -ne --approve -e . --list-models cursor` or `Cursor.models.list()` for the current model surface. When the SDK reports aliases, only unambiguous aliases are registered; shared generic aliases are skipped.
573
570
 
574
571
  | Example model shape | Cursor controls | Pi representation |
575
572
  |---|---|---|
@@ -594,14 +591,14 @@ Initial Cursor default for Composer 2.5:
594
591
  pi model: cursor/composer-2-5
595
592
  Cursor params: fast=true
596
593
  pi thinking: off
597
- Cursor status: cursor:local · fast:on
594
+ Cursor status: cursor · fast:on
598
595
  ```
599
596
 
600
597
  Toggle fast:
601
598
 
602
599
  ```text
603
600
  Cursor params: fast=false
604
- Cursor status: cursor:local · fast:off
601
+ Cursor status: cursor · fast:off
605
602
  ```
606
603
 
607
604
  `shift+tab`: no-op because the model is not reasoning-capable.
@@ -614,7 +611,7 @@ Initial Cursor default:
614
611
  pi model: cursor/gpt-5.5@1m
615
612
  Cursor params: context=1m; reasoning=medium; fast=false
616
613
  pi thinking: medium
617
- Cursor status: cursor:local · fast:off
614
+ Cursor status: cursor · fast:off
618
615
  ```
619
616
 
620
617
  After selecting the 272k variant:
@@ -629,7 +626,7 @@ After fast toggle:
629
626
 
630
627
  ```text
631
628
  Cursor params: context=272k; reasoning=medium; fast=true
632
- Cursor status: cursor:local · fast:on
629
+ Cursor status: cursor · fast:on
633
630
  ```
634
631
 
635
632
  After `shift+tab` to xhigh:
@@ -647,7 +644,7 @@ Initial Cursor default:
647
644
  pi model: cursor/gpt-5.3-codex
648
645
  Cursor params: reasoning=high; fast=true
649
646
  pi thinking: high
650
- Cursor status: cursor:local · fast:on
647
+ Cursor status: cursor · fast:on
651
648
  ```
652
649
 
653
650
  After `shift+tab` to low:
@@ -742,9 +739,9 @@ Before calling done:
742
739
  - launch interactive with Cursor
743
740
  - verify default pi footer remains unchanged
744
741
  - verify Cursor status appears only for Cursor models
745
- - verify Cursor fast-capable local models show `cursor:local · fast:on` or `cursor:local · fast:off`
746
- - required `cursor-http1-live` platform lane proves an enabled local HTTP/1.1/SSE turn completes and shows `http1`; unit/default live lanes prove local-disabled and cloud statuses omit it
747
- - verify Cursor `plan` status appears only in non-default mode and combines with status as `cursor:local · fast:n/a · plan`, `cursor:local · fast:on · plan`, `cursor:local · fast:off · plan`, or `cursor:cloud · fast:n/a · plan`
742
+ - verify Cursor fast-capable models show `cursor · fast:on` or `cursor · fast:off`
743
+ - when HTTP/1.1 transport code changes, a focused live check proves an enabled HTTP/1.1/SSE turn completes and shows `http1`; unit/default live lanes prove disabled statuses omit it
744
+ - verify Cursor `plan` status appears only in non-default mode and combines with status as `cursor · fast:n/a · plan`, `cursor · fast:on · plan`, or `cursor · fast:off · plan`
748
745
  - verify non-cursor footer/status unchanged
749
746
  - verify `shift+tab` uses pi native thinking
750
747
  - verify context changes through native model selection
@@ -39,7 +39,7 @@ PI_CURSOR_MCP_CONNECT_TIMEOUT_MS=5000 pi --model cursor/grok-4.6
39
39
  PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1 pi --model cursor/grok-4.6
40
40
  ```
41
41
 
42
- `PI_CURSOR_ASK_QUESTION=0` disables only `cursor_ask_question` / `pi__cursor_ask_question`, leaving the rest of the pi bridge available; it is enabled by default. `PI_CURSOR_PI_TOOL_BRIDGE=0` disables the bridge, including `pi__cursor_ask_question`. `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1` opts in to exposing overlapping pi tool names that Cursor already has native equivalents for (`read`, `bash`, `write`, `edit`, `grep`, `find`, and `ls`). By default those names are hidden even when pi's Cursor replay wrapper has registered them as extension tools; non-overlapping active built-ins remain bridgeable by default. The installed Cursor SDK uses a 60-second MCP protocol default; pi-cursor-sdk overrides that seam by default with 3600 seconds for MCP `callTool` requests and 10 seconds for verified initialize/listTools requests on first send. Bridged calls also have a local fail-closed deadline capped by the effective MCP tool timeout; lower it with `PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS` to reject stale pending state and abort active pi execution sooner. Unknown MCP protocol timeout stacks keep the SDK default. `PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1` emits typed, allowlisted, scrubbed single-line JSONL bridge diagnostics to `process.stderr` with prefix `[pi-cursor-sdk:bridge]`; it is off by default, uses run-safe IDs that are not reused in endpoint paths, and does not print endpoint URLs/path components/tokens, raw args/results, file contents, or secrets. Cursor-native tools, Cursor settings, plugins, and configured Cursor MCP servers still come from the Cursor SDK local agent path. Cloud Cursor agents are out of scope for this bridge.
42
+ `PI_CURSOR_ASK_QUESTION=0` disables only `cursor_ask_question` / `pi__cursor_ask_question`, leaving the rest of the pi bridge available; it is enabled by default. `PI_CURSOR_PI_TOOL_BRIDGE=0` disables the bridge, including `pi__cursor_ask_question`. `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1` opts in to exposing overlapping pi tool names that Cursor already has native equivalents for (`read`, `bash`, `write`, `edit`, `grep`, `find`, and `ls`). By default those names are hidden even when pi's Cursor replay wrapper has registered them as extension tools; non-overlapping active built-ins remain bridgeable by default. The installed Cursor SDK uses a 60-second MCP protocol default; pi-cursor-sdk overrides that seam by default with 3600 seconds for MCP `callTool` requests and 10 seconds for verified initialize/listTools requests on first send. Bridged calls also have a local fail-closed deadline capped by the effective MCP tool timeout; lower it with `PI_CURSOR_PI_BRIDGE_CALL_TIMEOUT_MS` to reject stale pending state and abort active pi execution sooner. Unknown MCP protocol timeout stacks keep the SDK default. `PI_CURSOR_PI_TOOL_BRIDGE_DEBUG=1` emits typed, allowlisted, scrubbed single-line JSONL bridge diagnostics to `process.stderr` with prefix `[pi-cursor-sdk:bridge]`; it is off by default, uses run-safe IDs that are not reused in endpoint paths, and does not print endpoint URLs/path components/tokens, raw args/results, file contents, or secrets. Cursor-native tools, Cursor settings, plugins, and configured Cursor MCP servers still come from the Cursor SDK local agent path.
43
43
 
44
44
  ## What gets replayed
45
45
 
@@ -64,13 +64,13 @@ When Cursor reports completed tool activity, the extension can display recorded
64
64
 
65
65
  Cursor `glob` activity is displayed through native `find` cards.
66
66
 
67
- For the full `@cursor/sdk@1.0.27` `ToolType` set, disposition matrix, and runtime alias normalization, see [SDK ToolType replay matrix](#sdk-tooltype-replay-matrix) below. Official SDK reference: https://cursor.com/docs/sdk/typescript
67
+ For the full `@cursor/sdk@1.0.30` `ToolType` set, disposition matrix, and runtime alias normalization, see [SDK ToolType replay matrix](#sdk-tooltype-replay-matrix) below. Official SDK reference: https://cursor.com/docs/sdk/typescript
68
68
 
69
69
  Edit and write activity replays through pi-facing `edit` and `write` cards only when replay arguments truthfully satisfy the matching pi schema, but still uses recorded Cursor results only. The adapter passes through truthful Cursor paths, content when Cursor reported it, and recorded diff/details; it does not pretend Cursor's editing schema is pi's schema and it fails closed if a recorded replay result is missing. Cursor `StrReplace` with recorded replacement text displays as native-looking `edit`; path-only Cursor `edit` and notebook edit activity fall back to neutral Cursor activity so pi does not reject the replay before recorded-result handling. Cursor `write` displays as native-looking `write`. Diagnostics, delete, todos/plans, task/subagent, image, MCP, semantic search, screen recording, and web search/fetch activity use neutral Cursor activity cards with pi's default success/error tool shell. Cursor SDK `task` activity is labeled **Cursor subagent** by default because it represents Cursor-spawned child-agent work; `PI_CURSOR_TASK_PRESENTATION=task` keeps the older **Cursor task** wording for comparison. MCP completions whose `toolName` is `WebSearch` / `web_search` / `WebFetch` / similar are labeled **Cursor web search** or **Cursor web fetch** instead of generic **Cursor MCP**. Neutral Cursor activity cards carry display metadata such as `activityTitle` and `activitySummary`, so partial/collapsed cards can say `Cursor plan`, `Cursor todos`, `Cursor subagent`, `Cursor MCP`, `Cursor semantic search`, `Cursor screen recording`, `Cursor web search`, `Cursor web fetch`, or `Cursor edit` instead of only `Cursor activity`. These replay tools only display recorded Cursor results; they never mutate files or execute tool work directly. Replay paths are normalized to workspace-relative paths when possible. Most collapsed replay cards include bounded previews for diffs and text details so small edits, todos, task output, and MCP results are visible without expanding; web search/fetch activity stays summary-only while collapsed because those cards often arrive after final text and can otherwise bury the answer. Ctrl+O expansion shows the recorded details. Edit previews omit raw unified diff headers and show compact numbered changed/context lines using pi's native diff added/removed/context colors, and write previews use syntax highlighting when pi can infer a language from the path. Image generation replay cards show the saved image path in the collapsed summary and render the image inline when pi terminal image display is enabled and the generated file is still readable.
70
70
 
71
71
  ## SDK ToolType replay matrix
72
72
 
73
- Source of truth for SDK tool names: `@cursor/sdk@1.0.27` conversation `ToolType` values and https://cursor.com/docs/sdk/typescript
73
+ Source of truth for SDK tool names: `@cursor/sdk@1.0.30` conversation `ToolType` values and https://cursor.com/docs/sdk/typescript
74
74
 
75
75
  Implementation owners: `src/cursor-tool-presentation-registry.ts` (canonical names, labels, visibility, replay policy, bridge exclusions for internal replay wrappers, alias normalization, and display-spec key completeness), `src/cursor-transcript-tool-specs.ts` (registry-keyed display implementations for transcript formatting and pi display builders), `src/cursor-native-tool-display-replay.ts` (replay card rendering derived from registry replay metadata), and `src/cursor-web-tool-activity.ts` (MCP/web alias remapping before display lookup).
76
76
 
@@ -184,7 +184,7 @@ Lifecycle rules:
184
184
 
185
185
  As Cursor SDK tool completions arrive, the extension mirrors native Codex ordering by ending a tool-use turn, letting pi render the recorded tool results, then continuing with live post-tool Cursor thinking/text, later Cursor tool batches, or Cursor's final answer as the next assistant turn. For plan-mode runs, neutral Cursor plan/todo cards can therefore appear before the final Cursor plan text.
186
186
 
187
- Bridged pi tool calls follow the same visible pi `toolUse` turn shape, but they are real pi tool executions rather than replayed Cursor results. Local usage accounting uses per-turn raw Cursor SDK `turn-ended.usage` when available before the corresponding pi turn is emitted, including cache read/write fields; observed local full-prompt/partition semantics map into disjoint pi input/cache components and set `usage.totalTokens = inputTokens + outputTokens` for occupancy (distinct from published SDK `toTokenUsage` additive totals). If the local SDK reports no usage in time, the provider falls back to local `input/output` activity estimates with `usage.totalTokens` set to the current replayable context estimate, then ignores later usage for that live run rather than risk applying stale usage to the wrong pi turn. Cloud raw usage remains display-only and uses approximate pi message accounting until its field semantics are independently captured.
187
+ Bridged pi tool calls follow the same visible pi `toolUse` turn shape, but they are real pi tool executions rather than replayed Cursor results. Local usage accounting uses per-turn raw Cursor SDK `turn-ended.usage` when available before the corresponding pi turn is emitted, including cache read/write fields; observed local full-prompt/partition semantics map into disjoint pi input/cache components and set `usage.totalTokens = inputTokens + outputTokens` for occupancy (distinct from published SDK `toTokenUsage` additive totals). If the local SDK reports no usage in time, the provider falls back to local `input/output` activity estimates with `usage.totalTokens` set to the current replayable context estimate, then ignores later usage for that live run rather than risk applying stale usage to the wrong pi turn.
188
188
 
189
189
  For shell replay, completed `stdout` / `stderr` remain the primary source. While exactly one shell call is active, the provider also emits a bounded scrubbed preview of the first few `shell-output-delta` stdout/stderr chunks so long-running commands show visible progress before completion. If a successful completed shell result is empty, the replay card uses unambiguous buffered delta data as display-only fallback data. Overlapping shell calls make delta attribution ambiguous, so those fallback/progress deltas are dropped rather than guessed. `(no output)` is kept only when no completed output or safe delta fallback is available.
190
190
 
@@ -1,12 +1,12 @@
1
1
  # Cursor Native Tool Visual Audit Workflow
2
2
 
3
- > **Platform Smoke (new):** The required cross-platform release gate includes a deterministic visual card matrix across all targets. See [docs/platform-smoke.md](./platform-smoke.md) for the required cards, assertion contract, and platform-matrix budget.
3
+ > **Release visual evidence:** `npm run smoke:visual -- --label release-check --prompt 'Read ./package.json and reply with its package name.'` is the current fork visual check. The deterministic cross-platform card matrix remains deferred under [issue #2](https://github.com/emmaneugene/pi-cursor-sdk/issues/2); see [docs/platform-smoke.md](./platform-smoke.md) for the retained future contract.
4
4
 
5
5
  This workflow is the canonical repo path for verifying Cursor SDK tool replay the way a human sees it in pi's interactive TUI, without stealing macOS focus.
6
6
 
7
7
  Use it before accepting replay-card commits or PRs, and for every Cursor provider/runtime release where TUI card/color behavior could regress. Text logs and JSONL are necessary, but they are not enough when the claim is visual parity: always keep PNGs for the exact prompt, and keep before/after PNGs when reviewing a rendering change.
8
8
 
9
- Current validation baseline: Pi 0.84.0 or later, exact `@cursor/sdk@1.0.27`, and local validation packages `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` at exact 0.84.0. Optional published Pi core peer dependencies use `"*"` ranges per current Pi package guidance.
9
+ Current validation baseline: Pi 0.84.0 or later, exact `@cursor/sdk@1.0.30`, and local validation packages `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` at exact 0.84.0. Optional published Pi core peer dependencies use `"*"` ranges per current Pi package guidance.
10
10
 
11
11
  ## Cursor SDK 1.0.17 / pi 0.79.0 cutover visual record
12
12
 
@@ -14,9 +14,9 @@ Record the required cutover validation here or in the final release handoff. The
14
14
 
15
15
  | Field | Required value / evidence |
16
16
  | --- | --- |
17
- | Command/session used | `npm run smoke:visual -- --ext "$PWD" --cwd "$PWD" --mode plan --out-dir <fresh /tmp dir> --label <matrix label> --prompt <matrix prompt>` with default native-replay isolation |
18
- | Baseline versions | `pi --version` = 0.79.0; `npm ls` = `@cursor/sdk@1.0.17` and local `@earendil-works/*@0.79.0` |
19
- | Card categories checked | Claim only categories proven by both PNG and JSONL. Required cutover categories are read, grep/search, find/glob, shell success, write, edit/diff, and true read failure. Direct `ls`/list is tracked as excluded from the current one-prompt platform matrix because composer-2-5 does not route it through native `ls` reliably; source-enumeration coverage is gated through find/glob. Neutral Cursor plan/todo/task/mode activity is optional/opportunistic and only counts when JSONL contains a completed Cursor workflow event. |
17
+ | Command/session used | `npm run smoke:visual -- --ext "$PWD" --cwd "$PWD" --mode plan --out-dir <fresh /tmp dir> --label release-check --prompt <bounded prompt>` with default native-replay isolation |
18
+ | Baseline versions | `pi --version` = 0.84.0; `npm ls` = `@cursor/sdk@1.0.30` and local `@earendil-works/*@0.84.0` |
19
+ | Card categories checked | Claim only categories proven by both PNG and JSONL. Required cutover categories are read, grep/search, find/glob, shell success, write, edit/diff, and true read failure. Direct `ls`/list is tracked as optional because composer-2-5 does not route it through native `ls` reliably; source-enumeration coverage is gated through find/glob. Neutral Cursor plan/todo/task/mode activity is optional/opportunistic and only counts when JSONL contains a completed Cursor workflow event. |
20
20
  | Observed status/card colors | Confirm native-looking cards use native pi styling; neutral Cursor activity is not red; true errors are distinct; diff previews show red/green; plan status is readable |
21
21
  | Screenshot/ANSI evidence location | External path only, for example `/tmp/pi-cursor-sdk-1016-visual.*/read-package.{ansi,txt,html,png,jsonl.path}` |
22
22
  | Debug artifact location | External `.debug/cursor-sdk-events/...` or temp artifact directory path only; do not commit raw artifacts |
@@ -29,7 +29,7 @@ Required prompt matrix for this cutover:
29
29
  | `read-package` | `Use only your file read tool. Read ./package.json and answer with only the package name. Do not use shell, grep, glob, find, or list tools.` | `toolCall.name=read`, `toolResult.toolName=read`, `isError=false` | Native-looking read card; collapsed label/path readable |
30
30
  | `grep-readme` | `Use only your grep/search tool to search ./README.md for the literal string "pi-cursor-sdk". Do not use shell, read, glob, find, ls, or list tools. Report only the first matching file path.` | `toolCall.name=grep`, `toolResult.toolName=grep`, `isError=false` | Native-looking grep/search card; match preview readable |
31
31
  | `find-readme` | `Use only your glob/file-search/find tool to find README.md from the repository root. Do not use shell, read, grep, ls, or list tools. Report matched paths exactly.` | `toolCall.name=find`, `toolResult.toolName=find`, `isError=false` | Native-looking find/glob card; matched path readable |
32
- | `list-src` | Excluded from current required platform matrix. Track manually when Cursor reliably routes this prompt through native `ls`. | `toolCall.name=ls`, `toolResult.toolName=ls`, `isError=false` when exercised | Native-looking list card; directory/path readable |
32
+ | `list-src` | Optional. Track manually when Cursor reliably routes this prompt through native `ls`. | `toolCall.name=ls`, `toolResult.toolName=ls`, `isError=false` when exercised | Native-looking list card; directory/path readable |
33
33
  | `shell-success` | `Use only your shell/terminal tool to run printf 'cursor visual smoke\\n'. Do not use read, grep, glob, find, ls, edit, or write. Report the output.` | `toolCall.name=bash`, `toolResult.toolName=bash`, `isError=false` | Shell success card is not red/error-styled; stdout readable |
34
34
  | `write-file` | `Use your normal file write tool to create .debug/visual-smoke/cursor-mode.txt with exactly two lines: alpha and beta. Do not use shell.` | `toolCall.name=write`, `toolResult.toolName=write`, `isError=false` | Native-looking write card; path/content preview readable |
35
35
  | `edit-file` | `Use your normal file edit/str-replace tool to change beta to gamma in .debug/visual-smoke/cursor-mode.txt. Do not use shell.` | `toolCall.name=edit`, `toolResult.toolName=edit`, `isError=false` | Native-looking edit card; diff preview shows red/green added/removed lines |
@@ -63,7 +63,7 @@ The canonical workflow is now offscreen and browser-rendered:
63
63
  5. Save PNG screenshots with `agent_browser` when the harness is available, or Playwright directly when running outside that harness.
64
64
  6. Inspect the session JSONL for exact persisted `toolCall` / `toolResult` data.
65
65
 
66
- This is the best default focused visual-debug path because it exercises the real pi TUI, captures card class/color/label/order/truncation issues before users see them, avoids desktop focus stealing, and leaves reviewable artifacts. Use visible Terminal/Ghostty screenshots only for terminal-specific or pixel-level bugs that cannot be judged through browser-rendered ANSI. The cross-platform release gate remains [Platform Smoke](./platform-smoke.md).
66
+ This is the best default focused visual-debug path because it exercises the real pi TUI, captures card class/color/label/order/truncation issues before users see them, avoids desktop focus stealing, and leaves reviewable artifacts. Use visible Terminal/Ghostty screenshots only for terminal-specific or pixel-level bugs that cannot be judged through browser-rendered ANSI. The cross-platform matrix is retained as a future gate under [Platform Smoke](./platform-smoke.md) and issue #2.
67
67
 
68
68
  ## Tool stack
69
69