pi-cursor-sdk 0.1.45 → 0.1.47

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.47 - 2026-06-22
6
+
7
+ ### Changed
8
+
9
+ - Update the local pi validation baseline to `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` `0.79.10` after reviewing the Pi 0.79.10 changelog, extension compaction events, provider/package docs, and release workflow.
10
+
11
+ ### Fixed
12
+
13
+ - Refresh the test event harness for Pi 0.79.10's required `session_before_compact` and `session_compact` `reason` / `willRetry` metadata.
14
+
15
+ ## 0.1.46 - 2026-06-21
16
+
17
+ ### Changed
18
+
19
+ - Update the local pi validation baseline to `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` `0.79.9` after reviewing current installed Pi extension, provider, package, and security docs.
20
+ - Bump the maintained `undici` override to `7.28.0` and refresh vulnerable transitive audit dependencies so `npm audit --audit-level=low` reports zero vulnerabilities.
21
+
22
+ ### Fixed
23
+
24
+ - Resolve maintainer shell smoke self-test failures under mise by sealing smoke PATHs with the real `process.execPath` Node executable instead of the `node` shim path.
25
+ - Harden the platform bridge visual matrix by asserting the exact JSONL tool-result order required by the documented prompt contract.
26
+
5
27
  ## 0.1.45 - 2026-06-18
6
28
 
7
29
  ### Fixed
package/README.md CHANGED
@@ -51,10 +51,10 @@ If pi started without a key, run `/cursor-refresh-models` after `/login` to refr
51
51
  ## Requirements
52
52
 
53
53
  - Node.js 22.19+
54
- - pi 0.79.4 or newer recommended; pi core peer metadata is intentionally unpinned so newer pi releases are not blocked
54
+ - pi 0.79.10 or newer recommended; pi core peer metadata is intentionally unpinned so newer pi releases are not blocked
55
55
  - a Cursor SDK API key saved through `/login`, available as `CURSOR_API_KEY`, or passed with pi's `--api-key`
56
56
 
57
- No global `@cursor/sdk` install is required. This package depends on exact `@cursor/sdk@1.0.19`, so normal package installation brings in the SDK version this extension was built and tested against. It also declares `@connectrpc/connect-node@1.7.0` directly because Cursor SDK 1.0.19 still dynamically loads the Node ConnectRPC transport during local-agent runs. Cursor SDK 1.0.19 removes the older `sqlite3 -> node-gyp@8` dependency chain, so deprecated install warnings for `inflight`, `rimraf`, `glob@7`, `npmlog`, `gauge`, `are-we-there-yet`, and `tar@6` from that chain are no longer expected. This package follows pi package guidance by declaring pi core package peers with `"*"` ranges, so users who update pi before this extension is republished are not blocked by peer metadata. The current recommended and validated pi baseline is 0.79.4 plus Cursor SDK 1.0.19; older pi compatibility paths are best-effort and older Cursor SDK compatibility paths are not maintained.
57
+ No global `@cursor/sdk` install is required. This package depends on exact `@cursor/sdk@1.0.19`, so normal package installation brings in the SDK version this extension was built and tested against. It also declares `@connectrpc/connect-node@1.7.0` directly because Cursor SDK 1.0.19 still dynamically loads the Node ConnectRPC transport during local-agent runs. Cursor SDK 1.0.19 removes the older `sqlite3 -> node-gyp@8` dependency chain, so deprecated install warnings for `inflight`, `rimraf`, `glob@7`, `npmlog`, `gauge`, `are-we-there-yet`, and `tar@6` from that chain are no longer expected. This package follows pi package guidance by declaring pi core package peers with `"*"` ranges, so users who update pi before this extension is republished are not blocked by peer metadata. The current recommended and validated pi baseline is 0.79.10 plus Cursor SDK 1.0.19; older pi compatibility paths are best-effort and older Cursor SDK compatibility paths are not maintained.
58
58
 
59
59
  ## Install
60
60
 
@@ -67,8 +67,8 @@ The replay scan flags only error `toolResult` / error assistant messages with `T
67
67
 
68
68
  Pass criteria:
69
69
 
70
- - `pi --version` reports pi 0.79.4 for this cutover baseline.
71
- - `npm ls` shows `@cursor/sdk@1.0.19` and local `@earendil-works/*@0.79.4` packages.
70
+ - `pi --version` reports pi 0.79.10 for this cutover baseline.
71
+ - `npm ls` shows `@cursor/sdk@1.0.19` and local `@earendil-works/*@0.79.10` packages.
72
72
  - `cursor/composer-2-5` appears in the model list.
73
73
  - No Cursor key or auth token is printed.
74
74
  - If neither `~/.pi/agent/auth.json` cursor auth nor `CURSOR_API_KEY` is available, stop and report the live smoke as blocked.
@@ -125,7 +125,7 @@ Observe with `tmux capture-pane -pt "$SESSION"` or attach manually.
125
125
  Pass criteria:
126
126
 
127
127
  - Footer shows `(cursor) composer-2-5`. With `--cursor-no-fast`, Cursor fast mode is off and the Cursor extension status should not show `cursor fast`; ignore unrelated status text from other extensions.
128
- - The run uses pi 0.79.4 `--session-id` successfully.
128
+ - The run uses pi 0.79.10 `--session-id` successfully.
129
129
  - Assistant answer appears correctly.
130
130
  - `/session` shows one user and one assistant message for the simple run.
131
131
  - Persisted JSONL has one assistant message. If the screen appears duplicated, inspect JSONL before deciding whether it is a rendering bug.
@@ -133,7 +133,7 @@ Pass criteria:
133
133
 
134
134
  ## 4. Focused visual card/color rendering check
135
135
 
136
- 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.79.4, `@cursor/sdk@1.0.19`, 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`.
136
+ 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.79.10, `@cursor/sdk@1.0.19`, 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
137
 
138
138
  ```bash
139
139
  VISUAL_DIR="$(mktemp -d /tmp/pi-cursor-sdk-1016-visual.XXXXXX)"
@@ -15,7 +15,7 @@ Current implementation notes:
15
15
  - Cursor status uses one coordinated `ctx.ui.setStatus("cursor", ...)` value for fast and non-default plan mode; the default pi footer remains intact.
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
- - Exact `@cursor/sdk@1.0.19` is a package dependency of this extension; users should not need a global SDK install. pi 0.79.4 is the current recommended validation baseline, while published pi core peer dependencies use `"*"` ranges per current pi package guidance. Newer pi versions are allowed to attempt loading this extension before a matching extension release exists; compatibility is best-effort until validated.
18
+ - Exact `@cursor/sdk@1.0.19` is a package dependency of this extension; users should not need a global SDK install. pi 0.79.10 is the current recommended validation baseline, while published pi core peer dependencies use `"*"` ranges per current pi package guidance. Newer pi versions are allowed to attempt loading this extension before a matching extension release exists; compatibility is best-effort until validated.
19
19
  - Cursor auth uses pi-native API-key resolution for provider `cursor`: CLI `--api-key`, stored `~/.pi/agent/auth.json` API key from `/login`, then `CURSOR_API_KEY`. The extension config file stores only non-secret Cursor-only state such as fast defaults.
20
20
  - 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`. 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.
21
21
  - 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.
@@ -6,7 +6,7 @@ This workflow is the canonical repo path for verifying Cursor SDK tool replay th
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.79.4, exact `@cursor/sdk@1.0.19`, local validation packages `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` at 0.79.4. Published pi core peer dependencies use `"*"` ranges per current pi package guidance, so newer pi installs can try the extension before a matching validation release exists.
9
+ Current validation baseline: pi 0.79.10, exact `@cursor/sdk@1.0.19`, local validation packages `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` at 0.79.10. Published pi core peer dependencies use `"*"` ranges per current pi package guidance, so newer pi installs can try the extension before a matching validation release exists.
10
10
 
11
11
  ## Cursor SDK 1.0.17 / pi 0.79.0 cutover visual record
12
12
 
@@ -243,7 +243,7 @@ The script writes timestamped artifacts under `--out` (default `/tmp/pi-cursor-s
243
243
 
244
244
  Stdout prints artifact paths and summary counts only. Raw payloads stay on disk and may contain local paths, project text, tool args/results, or secrets — do not commit or share them.
245
245
 
246
- Hard repo rule: Cursor SDK behavior claims must come from the installed `@cursor/sdk` package and/or https://cursor.com/docs/sdk/typescript, not from memory or ad-hoc probes alone. Current cutover validation targets exact `@cursor/sdk@1.0.19` and pi 0.79.4 local packages.
246
+ Hard repo rule: Cursor SDK behavior claims must come from the installed `@cursor/sdk` package and/or https://cursor.com/docs/sdk/typescript, not from memory or ad-hoc probes alone. Current cutover validation targets exact `@cursor/sdk@1.0.19` and pi 0.79.10 local packages.
247
247
 
248
248
  ## Pi provider SDK event capture
249
249
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-cursor-sdk",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
4
4
  "description": "pi provider extension backed by @cursor/sdk local agents",
5
5
  "author": "Mitch Fultz (https://github.com/fitchmultz)",
6
6
  "license": "MIT",
@@ -120,9 +120,9 @@
120
120
  "typebox": "*"
121
121
  },
122
122
  "devDependencies": {
123
- "@earendil-works/pi-ai": "0.79.4",
124
- "@earendil-works/pi-coding-agent": "0.79.4",
125
- "@earendil-works/pi-tui": "0.79.4",
123
+ "@earendil-works/pi-ai": "0.79.10",
124
+ "@earendil-works/pi-coding-agent": "0.79.10",
125
+ "@earendil-works/pi-tui": "0.79.10",
126
126
  "@xterm/xterm": "^6.0.0",
127
127
  "node-pty": "^1.1.0",
128
128
  "playwright": "^1.60.0",
@@ -136,9 +136,23 @@
136
136
  ]
137
137
  },
138
138
  "overrides": {
139
- "undici": "7.25.0"
139
+ "undici": "7.28.0"
140
140
  },
141
141
  "allowScripts": {
142
142
  "node-pty@1.1.0": true
143
+ },
144
+ "peerDependenciesMeta": {
145
+ "@earendil-works/pi-ai": {
146
+ "optional": true
147
+ },
148
+ "@earendil-works/pi-coding-agent": {
149
+ "optional": true
150
+ },
151
+ "@earendil-works/pi-tui": {
152
+ "optional": true
153
+ },
154
+ "typebox": {
155
+ "optional": true
156
+ }
143
157
  }
144
158
  }
@@ -147,7 +147,7 @@ EOF_SELFTEST_NODE
147
147
  chmod +x "$fake_pi" "$fake_node"
148
148
 
149
149
  ENV_BIN="$(smoke_resolve_cmd env)"
150
- NODE_BIN="$(smoke_resolve_cmd node)"
150
+ NODE_BIN="$(smoke_resolve_node_cmd)"
151
151
  if [[ "$SHELL_BIN" != /* ]]; then
152
152
  SHELL_BIN="$(smoke_resolve_cmd "$SHELL_BIN")"
153
153
  fi
@@ -260,7 +260,7 @@ EOF_SELFTEST_NPM
260
260
  no_pi_path="$no_pi_bin:/usr/bin:/bin"
261
261
  no_pi_output_file="$temp_dir/no-pi-output.txt"
262
262
  set +e
263
- PATH="$no_pi_path" REAL_HOME="$temp_dir/no-auth" PI_BIN=pi-must-not-exist REPO="$no_pi_repo" ISOLATED="$no_pi_isolated" SKIP_LIVE=1 SKIP_UNIT=1 "$SHELL_BIN" "$ROOT/scripts/isolated-cursor-smoke.sh" >"$no_pi_output_file" 2>&1
263
+ env -i PATH="$no_pi_path" REAL_HOME="$temp_dir/no-auth" PI_BIN=pi-must-not-exist REPO="$no_pi_repo" ISOLATED="$no_pi_isolated" SKIP_LIVE=1 SKIP_UNIT=1 "$SHELL_BIN" "$ROOT/scripts/isolated-cursor-smoke.sh" >"$no_pi_output_file" 2>&1
264
264
  no_pi_status=$?
265
265
  set -e
266
266
  if [[ "$no_pi_status" != "0" ]]; then
@@ -290,7 +290,7 @@ if [[ -f "${SECRETS_FILE:-$REAL_HOME/.secrets}" ]]; then
290
290
  set -u
291
291
  fi
292
292
 
293
- NODE_BIN="$(smoke_resolve_cmd node)"
293
+ NODE_BIN="$(smoke_resolve_node_cmd)"
294
294
  NPM_BIN="$(smoke_resolve_cmd npm)"
295
295
  ENV_BIN="$(smoke_resolve_cmd env)"
296
296
  if [[ "$SHELL_BIN" != /* ]]; then
@@ -31,6 +31,18 @@ smoke_resolve_cmd() {
31
31
  printf '%s\n' "$path"
32
32
  }
33
33
 
34
+ smoke_resolve_node_cmd() {
35
+ local node_cmd node_path
36
+ node_cmd="$(smoke_resolve_cmd node)"
37
+ if ! node_path="$("$node_cmd" -p 'process.execPath' 2>/dev/null)" || [[ -z "$node_path" ]]; then
38
+ smoke_fail "failed to resolve real node executable from $node_cmd"
39
+ fi
40
+ if [[ "$node_path" != /* ]]; then
41
+ smoke_fail "real node executable did not resolve to an absolute path: $node_path"
42
+ fi
43
+ printf '%s\n' "$node_path"
44
+ }
45
+
34
46
  smoke_build_sealed_node_path() {
35
47
  local node_bin="$1"
36
48
  local base_path
@@ -43,6 +43,7 @@ export const SCENARIOS = {
43
43
  promptTemplate: `Native visual matrix.
44
44
 
45
45
  Use Cursor-native tools only. Do not use pi__ tools.
46
+ On Windows/PowerShell shell commands, do not use &&; if you add a cd command, separate commands with a semicolon (;).
46
47
 
47
48
  Steps:
48
49
  1. read ./package.json and remember the package name.
@@ -130,6 +131,7 @@ BRIDGE_MATRIX_OK bash_ok=<yes/no> read_ok=<yes/no> read_missing_error=<yes/no>`,
130
131
  { id: "bridge-read-failure", toolName: "read", isError: true, contains: "definitely-missing-platform-smoke-file.txt" },
131
132
  { id: "bridge-shell-success", toolName: "bash", isError: false, contains: "bridge visual smoke" },
132
133
  ],
134
+ expectedJSONLResultToolOrder: ["bash", "read", "read"],
133
135
  visualEvidence: [
134
136
  { id: "bridge-read-success", pattern: "^\\s*read (?:\\./package\\.json|.*[\\\\/]package\\.json)", jsonlResultId: "bridge-read-success" },
135
137
  { id: "bridge-read-failure", pattern: "^\\s*read \\./definitely-missing-platform-smoke-file\\.txt|ENOENT: no such file", jsonlResultId: "bridge-read-failure" },
@@ -576,6 +576,11 @@ async function executeLiveSuite(config, targetName, suiteName, suiteDir, slug, l
576
576
  id: `jsonl-result-${requirement.id}`,
577
577
  fn: () => jsonlResults.some((result) => matchesJsonlResult(result, requirement)),
578
578
  }));
579
+ const expectedJSONLResultToolOrder = scenario?.expectedJSONLResultToolOrder;
580
+ const jsonlResultOrderChecks = Array.isArray(expectedJSONLResultToolOrder) ? [{
581
+ id: "jsonl-result-tool-order",
582
+ fn: () => jsonlResults.map((result) => result.toolName).join("\n") === expectedJSONLResultToolOrder.join("\n"),
583
+ }] : [];
579
584
  const bridgeDiagnostics = [
580
585
  ...collectBridgeDiagnostics(terminalText),
581
586
  ...collectBridgeDiagnosticFile(resolve(liveArtifactDir, "bridge-diagnostics.jsonl")),
@@ -641,6 +646,7 @@ async function executeLiveSuite(config, targetName, suiteName, suiteDir, slug, l
641
646
  ...cardChecks.map((check) => ({ id: check.id, fn: () => check.ok })),
642
647
  ...jsonlToolChecks,
643
648
  ...jsonlResultChecks,
649
+ ...jsonlResultOrderChecks,
644
650
  ...bridgeDiagnosticChecks,
645
651
  ...(visualEvidence.checks ?? []).map((check) => ({ id: check.id, fn: () => check.ok === true, error: check.error })),
646
652
  ...visualEvidenceResultChecks,
@@ -338,7 +338,7 @@ EOF_SELFTEST_NODE
338
338
  chmod +x "$fake_pi" "$fake_node"
339
339
 
340
340
  ENV_BIN="$(smoke_resolve_cmd env)"
341
- NODE_BIN="$(smoke_resolve_cmd node)"
341
+ NODE_BIN="$(smoke_resolve_node_cmd)"
342
342
  smoke_load_cursor_sdk_event_debug_env_names "$NODE_BIN" "$ROOT/shared/cursor-sdk-event-debug-env.mjs"
343
343
  hostile_path="$bin_dir:$PATH"
344
344
  [[ "$(smoke_build_sealed_node_path "$NODE_BIN" "")" != *: ]] || fail "self-test failed: empty inherited PATH left a trailing PATH separator"
@@ -380,7 +380,7 @@ if [[ "${1:-}" == "--self-test" ]]; then
380
380
  fi
381
381
 
382
382
  PI_BIN="$(smoke_resolve_cmd pi)"
383
- NODE_BIN="$(smoke_resolve_cmd node)"
383
+ NODE_BIN="$(smoke_resolve_node_cmd)"
384
384
  NPM_BIN="$(smoke_resolve_cmd npm)"
385
385
  RG_BIN="$(smoke_resolve_cmd rg)"
386
386
  TMUX_BIN="$(smoke_resolve_cmd tmux)"