pi-cursor-sdk 0.5.6 → 0.5.8
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 +26 -0
- package/dist/context.js +2 -4
- package/dist/cursor-agents-context.js +19 -27
- package/dist/cursor-native-tool-display-replay.js +2 -10
- package/docs/cursor-live-smoke-checklist.md +3 -3
- package/docs/cursor-model-ux-spec.md +4 -4
- package/docs/cursor-native-tool-visual-audit.md +1 -1
- package/docs/cursor-testing-lessons.md +5 -5
- package/docs/development.md +2 -4
- package/docs/reference.md +3 -3
- package/package.json +4 -9
- package/src/context.ts +2 -10
- package/src/cursor-agents-context.ts +18 -29
- package/src/cursor-native-tool-display-replay.ts +2 -10
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
**Release preparation is not a publication receipt:** confirm the exact version, source and artifact integrity in npm/GitHub publication records before relying on availability. No issue is closed by preparation alone.
|
|
4
4
|
|
|
5
|
+
## 0.5.8 - 2026-11-02
|
|
6
|
+
|
|
7
|
+
<!-- npm-release:unreleased:start -->
|
|
8
|
+
<!-- npm-release:unreleased:end -->
|
|
9
|
+
|
|
10
|
+
- Raise the Pi floor to 1.5.0 (#400) ([10d8523](https://github.com/fitchmultz/pi-cursor-sdk/commit/10d85236a00a59b8422e17a530412aff6c715236))
|
|
11
|
+
|
|
12
|
+
### What's Changed
|
|
13
|
+
* Raise the Pi floor to 1.5.0 by @fitchmultz in https://github.com/fitchmultz/pi-cursor-sdk/pull/400
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
**Full Changelog**: https://github.com/fitchmultz/pi-cursor-sdk/compare/v0.5.7...v0.5.8
|
|
17
|
+
|
|
18
|
+
## 0.5.7 - 2026-11-01
|
|
19
|
+
|
|
20
|
+
<!-- npm-release:unreleased:start -->
|
|
21
|
+
<!-- npm-release:unreleased:end -->
|
|
22
|
+
|
|
23
|
+
- Reconcile queued version source commit [d82e5a3](https://github.com/fitchmultz/pi-cursor-sdk/commit/d82e5a391285c88079fc3e90983d985bae77af7c) (`Merge pull request #397 from fitchmultz/fix/npm12-manager-scripts`), which is already an ancestor of `v0.5.6` (`4dc13ea`).
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Version-only metadata release (`package.json`, `package-lock.json`, and `CHANGELOG.md`). All functional and workflow changes from #397 already shipped in `0.5.6`; `v0.5.6...v0.5.7` contains no runtime, build, or dependency changes.
|
|
28
|
+
|
|
29
|
+
**Full Changelog**: https://github.com/fitchmultz/pi-cursor-sdk/compare/v0.5.6...v0.5.7
|
|
30
|
+
|
|
5
31
|
## 0.5.6 - 2026-11-01
|
|
6
32
|
|
|
7
33
|
<!-- npm-release:unreleased:start -->
|
package/dist/context.js
CHANGED
|
@@ -99,11 +99,9 @@ function formatToolCall(toolCall) {
|
|
|
99
99
|
}
|
|
100
100
|
function sanitizeSystemPromptForCursor(systemPrompt) {
|
|
101
101
|
let sanitized = systemPrompt;
|
|
102
|
-
//
|
|
103
|
-
sanitized = sanitized.replace(/<tools>\n[\s\S]*?\n\
|
|
102
|
+
// Pi wraps its built-in tool catalog and rules in XML sections.
|
|
103
|
+
sanitized = sanitized.replace(/<tools>\n[\s\S]*?\n\nAdditional tools may be available\.\n<\/tools>/g, "Pi tool catalog omitted: Cursor can call only Cursor SDK tools exposed in this run.");
|
|
104
104
|
sanitized = sanitized.replace(/<rules>\n[\s\S]*?\n<\/rules>\n\n(?=<docs>\nPi documentation )/g, "<rules>\n- Be concise in your responses.\n- Show file paths clearly when working with files.\n</rules>\n\n");
|
|
105
|
-
sanitized = sanitized.replace(/Available tools:\n[\s\S]*?\n\nIn addition to the tools above, you may have access to other custom tools depending on the project\.\n\n/g, "Pi tool catalog omitted: Cursor can call only Cursor SDK tools exposed in this run.\n\n");
|
|
106
|
-
sanitized = sanitized.replace(/Guidelines:\n[\s\S]*?\n\nPi documentation /g, "Guidelines:\n- Be concise in your responses.\n- Show file paths clearly when working with files.\n\nPi documentation ");
|
|
107
105
|
// Keep the Agent Skills catalog. Cursor-specific skill activation wording is normalized
|
|
108
106
|
// by cursor-skill-tool.ts before this prompt reaches the Cursor SDK provider.
|
|
109
107
|
sanitized = sanitized.replace(/\n+Semantic code intelligence priority:[\s\S]*$/g, "");
|
|
@@ -6,8 +6,6 @@ export const CURSOR_PRESERVE_PI_AGENTS_MD_ENV = "PI_CURSOR_PRESERVE_PI_AGENTS_MD
|
|
|
6
6
|
/** Opening tag prefix pi `buildSystemPrompt()` uses for each context file (path attribute only). */
|
|
7
7
|
export const PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX = '<project_instructions path="';
|
|
8
8
|
const PI_PROJECT_INSTRUCTIONS_CLOSE = "</project_instructions>";
|
|
9
|
-
const PI_PROJECT_CONTEXT_OPEN = "\n\n<project_context>\n\nProject-specific instructions and guidelines:\n\n";
|
|
10
|
-
const PI_PROJECT_CONTEXT_CLOSE = "</project_context>\n";
|
|
11
9
|
function normalizeContextPath(filePath) {
|
|
12
10
|
return filePath.replace(/\\/g, "/");
|
|
13
11
|
}
|
|
@@ -69,24 +67,21 @@ function shouldSuppressPiAgentsContext(model, contextFiles, settingSources, agen
|
|
|
69
67
|
return false;
|
|
70
68
|
return contextFiles.some((file) => shouldRemovePiAgentsContextFile(file, settingSources, agentDir));
|
|
71
69
|
}
|
|
72
|
-
/** Exact pi `buildSystemPrompt()` serialization for one context file block
|
|
70
|
+
/** Exact pi `buildSystemPrompt()` serialization for one context file block. */
|
|
73
71
|
export function serializePiProjectInstructionsBlock(file) {
|
|
74
|
-
return `${PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX}${file.path}">\n${file.content}\n${PI_PROJECT_INSTRUCTIONS_CLOSE}
|
|
72
|
+
return `${PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX}${file.path}">\n${file.content}\n${PI_PROJECT_INSTRUCTIONS_CLOSE}`;
|
|
75
73
|
}
|
|
76
|
-
/**
|
|
77
|
-
export function serializePiProjectContextSection(contextFiles
|
|
74
|
+
/** Exact pi `buildSystemPrompt()` serialization for the project_context section. */
|
|
75
|
+
export function serializePiProjectContextSection(contextFiles) {
|
|
78
76
|
if (contextFiles.length === 0)
|
|
79
77
|
return "";
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
].join("\n");
|
|
88
|
-
}
|
|
89
|
-
return `${PI_PROJECT_CONTEXT_OPEN}${contextFiles.map(serializePiProjectInstructionsBlock).join("")}${PI_PROJECT_CONTEXT_CLOSE}`;
|
|
78
|
+
return [
|
|
79
|
+
"<project_context>",
|
|
80
|
+
"Project-specific instructions and guidelines:",
|
|
81
|
+
"",
|
|
82
|
+
contextFiles.map(serializePiProjectInstructionsBlock).join("\n\n"),
|
|
83
|
+
"</project_context>",
|
|
84
|
+
].join("\n");
|
|
90
85
|
}
|
|
91
86
|
/** Remove pi context blocks that overlap Cursor setting sources. */
|
|
92
87
|
export function removePiAgentsContextFromSystemPrompt(systemPrompt, contextFiles, settingSources, agentDir) {
|
|
@@ -101,17 +96,14 @@ export function removePiAgentsContextFromSystemPrompt(systemPrompt, contextFiles
|
|
|
101
96
|
}
|
|
102
97
|
if (!removedAny)
|
|
103
98
|
return systemPrompt;
|
|
104
|
-
// Match only the exact known files
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
|
|
113
|
-
}
|
|
114
|
-
return systemPrompt;
|
|
99
|
+
// Match only the exact known files; never strip arbitrary user-authored XML
|
|
100
|
+
// or neighboring custom sections.
|
|
101
|
+
const originalSection = serializePiProjectContextSection(contextFiles);
|
|
102
|
+
const start = systemPrompt.indexOf(originalSection);
|
|
103
|
+
if (start < 0)
|
|
104
|
+
return systemPrompt;
|
|
105
|
+
const replacementSection = serializePiProjectContextSection(retainedContextFiles);
|
|
106
|
+
return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
|
|
115
107
|
}
|
|
116
108
|
export function resolveCursorFacingSystemPrompt(systemPrompt, model, systemPromptOptions, settingSourcesRaw, agentDir, runtime = "local") {
|
|
117
109
|
if (runtime === "cloud" || !systemPromptOptions)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
|
-
import { getLanguageFromPath, highlightCode
|
|
3
|
+
import { getLanguageFromPath, highlightCode } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { Image, Text } from "@earendil-works/pi-tui";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
import { resolveCursorEditDiff } from "./cursor-edit-diff.js";
|
|
@@ -307,20 +307,12 @@ function hasCursorReplayDisplayTitle(details) {
|
|
|
307
307
|
return false;
|
|
308
308
|
return isCursorReplayActivityDetails(details) || isCursorReplayGenerateImageDetails(details);
|
|
309
309
|
}
|
|
310
|
-
function formatCursorReplayExpandHint() {
|
|
311
|
-
try {
|
|
312
|
-
return keyHint("app.tools.expand", "to expand");
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
return "Ctrl+O to expand";
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
310
|
function renderExpandableCursorReplayResult(title, details, result, options, theme, context, isError) {
|
|
319
311
|
const text = firstContentText(result);
|
|
320
312
|
const summary = details.summary ?? text.split("\n").find((line) => line.trim()) ?? "completed";
|
|
321
313
|
const expandedText = details.expandedText ?? (text.includes("\n") ? text : undefined);
|
|
322
314
|
const showExpandHint = expandedText && !options.expanded && shouldShowCursorReplayCollapsedExpandHint(details.sourceToolName);
|
|
323
|
-
const expandHint = showExpandHint ? theme.fg("dim", ` (${
|
|
315
|
+
const expandHint = showExpandHint ? theme.fg("dim", ` (${context.keyHint("app.tools.expand", "to expand")})`) : "";
|
|
324
316
|
let rendered = `${theme.fg("toolTitle", theme.bold(title))} ${theme.fg(isError ? "error" : "success", summary)}${expandHint}`;
|
|
325
317
|
if (expandedText && (options.expanded || !details.collapseDetailsByDefault)) {
|
|
326
318
|
const preview = formatCursorReplayActivityPreview(details, expandedText, theme, options.expanded ? Number.POSITIVE_INFINITY : CURSOR_REPLAY_COLLAPSED_PREVIEW_LINES, !options.expanded);
|
|
@@ -70,8 +70,8 @@ The replay scan flags only error `toolResult` / error assistant messages with `T
|
|
|
70
70
|
Pass criteria:
|
|
71
71
|
|
|
72
72
|
- `node --version` reports Node 24+.
|
|
73
|
-
- `pi --version` reports official Pi
|
|
74
|
-
- `npm ls` shows exact `@cursor/sdk@1.0.40`; development `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` 1.
|
|
73
|
+
- `pi --version` reports official Pi 1.5.0 or the selected official-latest/current-`fitchmultz/pi` compatibility target.
|
|
74
|
+
- `npm ls` shows exact `@cursor/sdk@1.0.40`; development `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` 1.5.0 with matching lockfile-resolved Pi cohort, nested host TypeBox 1.3.27 and root validation TypeBox 1.3.36; and the bundled bridge runtime closure `@modelcontextprotocol/server@2.3.1`, `@modelcontextprotocol/hono@2.0.2`, `hono@4.13.13`, and `@hono/node-server@2.1.3`. These locked development snapshots are not qualification targets; resolve latest stable official Pi and current `fitchmultz/pi` main once per workflow run.
|
|
75
75
|
- `cursor/grok-4.6` appears in the model list.
|
|
76
76
|
- No Cursor key or auth token is printed.
|
|
77
77
|
- If neither `~/.pi/agent/auth.json` cursor auth nor `CURSOR_API_KEY` is available, stop and report the live smoke as blocked.
|
|
@@ -136,7 +136,7 @@ Pass criteria:
|
|
|
136
136
|
|
|
137
137
|
## 4. Focused visual card/color rendering check
|
|
138
138
|
|
|
139
|
-
This is a visual debug menu for changed card/color behavior requiring new live evidence. Select only the relevant category below, or reuse a batched existing platform suite; do not execute the entire list by default. It requires offscreen TUI visual inspection, not only JSONL or code review. Use Node 24+, official Pi
|
|
139
|
+
This is a visual debug menu for changed card/color behavior requiring new live evidence. Select only the relevant category below, or reuse a batched existing platform suite; do not execute the entire list by default. It requires offscreen TUI visual inspection, not only JSONL or code review. Use Node 24+, official Pi 1.5.0 or another current compatibility target, exact `@cursor/sdk@1.0.40`, a fresh temporary session dir, Cursor SDK `plan` mode, native replay enabled, and the checked-in visual runner. The runner resolves `pi` by directly walking the parent `PATH`, uses `process.execPath` for Node, and prepends that Node directory for both prereq checks and tmux launches so `#!/usr/bin/env node` shims use the validated Node. The default matrix is native replay only: native replay registration is forced on, settings sources are `none`, the pi bridge is off, overlapping built-in pi tools are not exposed, and inherited Cursor SDK event-debug artifact env is cleared. With `--event-debug`, debug capture writes to a deterministic directory under `VISUAL_DIR`.
|
|
140
140
|
|
|
141
141
|
```bash
|
|
142
142
|
VISUAL_DIR="$(mktemp -d /tmp/pi-cursor-sdk-1016-visual.XXXXXX)"
|
|
@@ -10,7 +10,7 @@ Current implementation notes:
|
|
|
10
10
|
|
|
11
11
|
- Cursor footer status is visible by default. `PI_CURSOR_FOOTER=0` clears the Cursor status on the next status refresh; provider runtime, mode, and transport validation remain active.
|
|
12
12
|
|
|
13
|
-
- Provider contexts support official Pi
|
|
13
|
+
- Provider contexts support official Pi 1.5.0/latest and current `fitchmultz/pi` main, including transcript-only hosts. `cursor-pi-context.ts` directly imports Pi's required public replay helpers. Current instructions and tools are replayed natively, system deltas are fingerprinted, and system messages are excluded from Cursor conversation formatting and trailing-result scans. Fresh cloud context preserves current instructions while excluding history. Native replay uses the request tool snapshot (including empty); the pi bridge retains its separate registry-owned surface. XML prompt sections are sanitized/deduplicated alongside the stock format.
|
|
14
14
|
|
|
15
15
|
- Structured conversation history labels typed tool blocks `Historical tool request/result/error`, preserving arguments, IDs and errors without declaring unmatched requests completed. User/assistant prose and code fences remain unchanged. This removes the extension's literal `Tool call` template, not model-authored narration; no prose-to-tool conversion, stripping or automatic resend is performed (#257).
|
|
16
16
|
- Cursor context variants use `base@context` pi model IDs.
|
|
@@ -24,7 +24,7 @@ Current implementation notes:
|
|
|
24
24
|
- Shared SDK initialization resolves the native platform package relative to `@cursor/sdk` before import and sets `CURSOR_TREE_SITTER_VENDOR_DIR` only when unset and both vendored parser entrypoints exist. Explicit overrides remain SDK-owned. This repairs sibling-install native lookup. Static SDK and bridge imports additionally repair the compiled-Bun extension graph; the packed extension was qualified in official compiled Pi 1.0.3 on macOS arm64 with isolated empty credentials and a fake key. Embedded Windows missing-export behavior remains unqualified.
|
|
25
25
|
- The selected vendor path is process-wide and inherited by shell commands and child Pi processes. A child using another install/worktree preserves the inherited value as an explicit override, even when stale. Unset it in the child's environment to rediscover that install's parser, or provide its absolute vendor path; see [native parser troubleshooting](reference.md#native-shell-parsing-or-module-loading-fails).
|
|
26
26
|
- Provider and discovery errors retain bounded, scrubbed name/code/message/cause fields without serializing arbitrary error objects. Module-loading and ambiguous session-authentication failures do not imply a rejected API key. Explicit key rejection retains actionable setup guidance; no automatic reload or authentication recovery is performed.
|
|
27
|
-
- Exact `@cursor/sdk@1.0.40` is an unbundled package dependency; users do not need a global SDK install. This package requires Node 24+ and official Pi
|
|
27
|
+
- Exact `@cursor/sdk@1.0.40` is an unbundled package dependency; users do not need a global SDK install. This package requires Node 24+ and official Pi 1.5.0+, while optional published Pi and TypeBox peer dependencies use `"*"` ranges per Pi guidance. Direct development Pi dependencies and their lockfile-resolved Pi cohort are 1.5.0 reproducible snapshots, not qualification targets or user runtime upgrades; nested host TypeBox remains 1.3.27; the extension's root TypeBox validation baseline is 1.3.36.
|
|
28
28
|
- Native usage contains coherent current-context components only. The origin-owned ledger records every raw turn, original wait/handle snapshots, terminal success/error/abort/abandon, and bounded public whole-agent `getUsage()` observations separately. Cumulative bills never enter native usage. Request floors use actual native source chronology and projection equivalence, not text or clocks; see [Context and accounting boundaries](#context-and-accounting-boundaries).
|
|
29
29
|
- Cursor owns one public native Provider with native API-key login and a small resolver for stored/provider-env, runtime, composed config, and ambient credentials. Startup and auth mutations are cache-only, retaining known cached/fallback identities. `PI_CURSOR_HIDE_MODELS_WHEN_LOGGED_OUT=1` hides only unauthenticated picker/list availability, not CLI selection or login. Discovery receives explicit effective native auth and never guesses a default auth store. `/cursor-refresh-models` uses native registry refresh/publication. Provider turns keep Pi's resolved `options.apiKey`; non-secret Cursor-only settings remain separate.
|
|
30
30
|
- 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.
|
|
@@ -103,7 +103,7 @@ Cursor SDK is the source of truth for Cursor model IDs and Cursor-supported para
|
|
|
103
103
|
|
|
104
104
|
Startup registers a known cached/fallback baseline without catalog/network calls. The SDK remains in the static extension graph for compiled-Bun loading; cache-only does not promise zero SDK module evaluation. Native cache-only refresh follows real login/logout/rotation/runtime-key mutations; the genuine extension context supplies composed config auth once bound. There is no polling, replayed auth lifecycle event, or independent CLI parser.
|
|
105
105
|
|
|
106
|
-
Known host limitation: official Pi 1.0.4 and 1.1.0
|
|
106
|
+
Known host limitation: official Pi has a startup refresh-admission/readiness race, demonstrated on 1.0.4 and 1.1.0 and unchanged in the 1.5.0 refresh code, that can temporarily leave fallback models and an incorrect missing-key warning despite a matching authenticated cache. The shared-owner repair is merged in `fitchmultz/pi` via [#190](https://github.com/fitchmultz/pi/pull/190) and remains fork-only after the fork's Pi 1.5.0 sync; this is not an official-host fix. See [#337](https://github.com/fitchmultz/pi-cursor-sdk/pull/337) and the [native auth/catalog fixture boundary](./cursor-testing-lessons.md#native-authcatalog-fixture-boundary). It is separate from Cursor service authentication failures and the compiled-loader repair.
|
|
107
107
|
|
|
108
108
|
Effective auth follows native precedence: runtime override, stored API-key credential (key then provider-scoped `env.CURSOR_API_KEY` then ambient), composed `models.json` key when no stored credential exists, then ambient `CURSOR_API_KEY`. Placeholder normalization does not shadow composed config. An unsupported stored credential type remains unconfigured. Native logout removes both stored credentials and the runtime override; surviving env/config auth prevents false orphan-cache deletion. Same-process environment/config changes are picked up by native registry refresh, not a watcher.
|
|
109
109
|
|
|
@@ -615,7 +615,7 @@ Use:
|
|
|
615
615
|
|
|
616
616
|
### Multi-session embedding
|
|
617
617
|
|
|
618
|
-
Each ExtensionAPI registers its own provider closure. Its native header receipt captures immutable scope/projection provenance and the usage origin before deferred work; stream entry consumes that receipt and captures the owning bridge, replay state, and cloud recorder. Default SDK sessions create independent ModelRuntime instances on supported official Pi
|
|
618
|
+
Each ExtensionAPI registers its own provider closure. Its native header receipt captures immutable scope/projection provenance and the usage origin before deferred work; stream entry consumes that receipt and captures the owning bridge, replay state, and cloud recorder. Default SDK sessions create independent ModelRuntime instances on supported official Pi 1.5.0+ and the maintained fork. Concurrent sessions, children launched inside a parent's tool before `turn_end`, and direct manual/automatic compaction, tree summaries, and bug-report summaries retain their own pool/store, persisted lineage/resume entries, journals, and debug metadata. Ownership does not depend on turn/agent event windows. Inherited tool-result IDs cannot select a sibling's live run. Replay wrappers require both their owning display state and the normalized recorded tool name before consuming a result; a foreign-owner or wrong-tool ID is rejected without consuming the original card or executing native work.
|
|
619
619
|
|
|
620
620
|
Runtime scope keys combine the persistent identity with a process-local owner assigned to the real public SessionManager object. That manager is stable across native contexts/reload on the supported hosts; independent managers opening one file do not share generations, pools, live runs, branch caches or terminal tombstones. Durable scope keys, pool-compatibility bytes, store roots and persisted resume/lineage entries keep their prior identity. Atomic exact store-root/agent-ID claims prevent an already-owned handle from being resumed or deleted by another runtime; unavailable resume claims create a fresh agent, while cleanup refuses the occupied ID. Claims release only after successful SDK disposal, not a timeout/rejection. The native ownership regression proves same-file ordinary continuation and pending bridge survival across sibling reload/tree/shutdown, restart resume and simultaneous acquisition. It does not establish #282's original trigger, cross-process locking or concurrent real SQLite/journal-write safety.
|
|
621
621
|
|
|
@@ -6,7 +6,7 @@ This workflow is the canonical repo path for verifying Cursor SDK tool replay th
|
|
|
6
6
|
|
|
7
7
|
Use it when changed replay-card behavior needs new visual proof not covered by offline rendering contracts or valid retained evidence. Text logs and JSONL are not enough for visual-parity claims: keep PNGs for the exact prompt, and before/after PNGs for a rendering comparison. Reuse a valid retained baseline instead of paying to recreate it.
|
|
8
8
|
|
|
9
|
-
Current validation baseline: Node 24+, exact `@cursor/sdk@1.0.40`, official Pi
|
|
9
|
+
Current validation baseline: Node 24+, exact `@cursor/sdk@1.0.40`, official Pi 1.5.0/latest and current `fitchmultz/pi` main. Development Pi packages `@earendil-works/pi-ai`, `@earendil-works/pi-coding-agent`, and `@earendil-works/pi-tui` are exact locked 1.5.0 snapshots, with host TypeBox 1.3.27. These locked development snapshots are not qualification targets; resolve latest stable official Pi and current `fitchmultz/pi` main once per workflow run. Optional published Pi and TypeBox peer dependencies use `"*"` ranges per Pi guidance.
|
|
10
10
|
|
|
11
11
|
## Cursor SDK 1.0.17 / pi 0.79.0 cutover visual record
|
|
12
12
|
|
|
@@ -39,7 +39,7 @@ When changing provider/runtime behavior, ask whether the bug spans **pi extensio
|
|
|
39
39
|
Native replay routing intentionally uses two layers:
|
|
40
40
|
|
|
41
41
|
1. **Extension resync** (`before_agent_start`, `turn_start`) updates pi's active tool set via `syncRegisteredNativeCursorToolsForModel`. This fixes the common case where plan-mode execute strips `grep`/`find`/`cursor` before the next turn.
|
|
42
|
-
2. **Provider routing** uses the **request tool snapshot** captured when `streamCursor()` starts (`getActiveContextToolNames` in `src/cursor-context-tools.ts`):
|
|
42
|
+
2. **Provider routing** uses the **request tool snapshot** captured when `streamCursor()` starts (`getActiveContextToolNames` in `src/cursor-context-tools.ts`): the current tools that `resolveCursorPiContext` replays with Pi's public helpers, from transcript-only host contexts or shorthand `systemPrompt`/`tools` contexts. A shorthand context without `tools` has no snapshot; an explicit empty snapshot is still a snapshot. It does not read live `pi.getActiveTools()` mid-stream. The bridge intentionally retains its separate registry-owned surface.
|
|
43
43
|
|
|
44
44
|
`src/cursor-native-replay-routing.ts` centralizes provider-side routing against the same `context.tools` snapshot:
|
|
45
45
|
|
|
@@ -56,7 +56,7 @@ If resync runs but `context.tools` is still stale (e.g. only `read` listed), the
|
|
|
56
56
|
|
|
57
57
|
## Stock/transcript provider contract
|
|
58
58
|
|
|
59
|
-
`test/cursor-provider-pi-context.test.ts` drives real `ModelRuntime` / `ModelRegistry` requests into `streamCursor`, with only Cursor SDK execution mocked. Run it against each supported host with all Pi peer imports pinned to that host (including nested native imports); a top-level package version alone is not resolution evidence. Cover official Pi
|
|
59
|
+
`test/cursor-provider-pi-context.test.ts` drives real `ModelRuntime` / `ModelRegistry` requests into `streamCursor`, with only Cursor SDK execution mocked. Run it against each supported host with all Pi peer imports pinned to that host (including nested native imports); a top-level package version alone is not resolution evidence. Cover official Pi 1.5.0, official latest, and current `fitchmultz/pi` main. The direct development Pi packages are locked 1.5.0 snapshots, not qualification targets; resolve latest stable official Pi and current `fitchmultz/pi` main once per workflow run. Their actual nested resolution is recorded with each check, including host TypeBox 1.3.27.
|
|
60
60
|
|
|
61
61
|
The test covers bootstrap/incremental prompts, empty-vs-absent request tools, native replay/drain, cloud fresh/bootstrap selection, and actual host prompt serialization for context files and skills. `test/native-cursor-flow.test.mjs` additionally exercises the compiled extension through the real loader and registered Cursor provider, substituting only the external SDK transport/storage. It verifies actual bridge tool execution, pending-work idle/abort/shutdown/deadline ownership, replay without file access, persisted usage/lineage, tree, compaction, queued steering, abort and reload/disposal. `test/native-cursor-prompt.test.mjs` owns genuine native input, hidden notices, required-budget input, current attachments, custom-only continuation, equivalent conversion, payload/order-changing rejection, and GitHub comment soft guidance across bootstrap/incremental/custom-only sends. `test/native-cursor-ownership.test.mjs` owns concurrent-session contracts, including independently reopened managers for the same file, pending bridge survival across sibling reload/tree/shutdown, durable-key stability and atomic live-handle exclusion. These owners use `test/helpers/native-cursor-harness.mjs` and run in the explicit `check:compat` list and manual official-host compatibility route; the native-platform Vitest job is not execution evidence for these Node test owners. Explicit `tools` is now an allowlist, not merely an initial active set; use `defaultTools` for a native fixture that allows replay wrappers to activate. `test/native-provider.test.mjs` additionally verifies canonical `SessionManager.appendContextEdit()` plus `refreshContext()`, unchanged raw history, and conversation filtering that preserves system instructions, the current tool declaration, and explicit tool removal (the focused native slice from #271). It is offline contract evidence. Add live proof only for changed behavior that still needs real-service evidence under the cost policy above; do not rerun unchanged live lanes or infer full live coverage from offline tests.
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ The test covers bootstrap/incremental prompts, empty-vs-absent request tools, na
|
|
|
64
64
|
|
|
65
65
|
`test/cursor-native-auth-catalog.test.ts` uses public `ModelRuntime.create({ modelsPath: null })` for cases that do not exercise configuration files. Credentials and the Cursor catalog cache remain real; config-precedence and config-edit cases still use a temporary `models.json`. Seed startup credentials and the matching cache before creating the runtime.
|
|
66
66
|
|
|
67
|
-
Official Pi 1.
|
|
67
|
+
Official Pi, including 1.5.0, retains the [file-backed startup refresh-admission/readiness limitation](./cursor-model-ux-spec.md#source-of-truth): registration starts an unawaited refresh, and an asynchronous config load can supersede the awaited session refresh before its catalog publishes. This can return the bundled fallback despite an authenticated matching cache, including when auth/cache were seeded before runtime creation. The in-memory fixture isolates Cursor auth/publication assertions from that shared host defect; it does **not** qualify or repair official file-backed startup. The shared-owner repair in `fitchmultz/pi` [#190](https://github.com/fitchmultz/pi/pull/190) admits refresh ownership before config I/O and awaits replacement publication. File-backed startup proof must use that repaired host and retain its exact revision.
|
|
68
68
|
|
|
69
69
|
## Installed SDK vs native host evidence
|
|
70
70
|
|
|
@@ -256,7 +256,7 @@ For LOCAL summary isolation, inspect actual SDK create/send options and persiste
|
|
|
256
256
|
|
|
257
257
|
`test/cursor-usage-ledger.test.ts` uses real public SessionManager custom entries and bounded filesystem journals. It protects restart, optional mirror failure, backward/equal snapshot clocks, revised/aggregate-only/large bills, linear compact-revision storage, unavailable-to-late observations, abandon without a billing fetch, late abort, owner/sibling switches, inherited cross-directory gaps, lost native claims, pricing tiers, torn-tail prefix export/native-fork recovery and malformed/symlink files. Export is a canonical view of facts and uncertainty, not an invented client-run billing join. A failed durable append must not advance recognized accounting.
|
|
258
258
|
|
|
259
|
-
For supported official hosts without committing a repair, use `node scripts/ci-compatibility.mjs --working-tree --official-only --versions
|
|
259
|
+
For supported official hosts without committing a repair, use `node scripts/ci-compatibility.mjs --working-tree --official-only --versions 1.5.0`. This hashes an isolated source snapshot, builds/packs it, tests package loading and runs real native session contracts. Keep matching host-peer resolution and exact source evidence; offline SDK transport substitution proves integration, not live service availability. See [context/accounting boundaries](./cursor-model-ux-spec.md#context-and-accounting-boundaries) for the operational ledger ceiling and public-API limits.
|
|
260
260
|
|
|
261
261
|
### False-positive edge case (2026-05-23)
|
|
262
262
|
|
|
@@ -361,7 +361,7 @@ The script writes timestamped artifacts under `--out` (default `/tmp/pi-cursor-s
|
|
|
361
361
|
|
|
362
362
|
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.
|
|
363
363
|
|
|
364
|
-
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 validation targets Node 24+, exact `@cursor/sdk@1.0.40`, official Pi
|
|
364
|
+
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 validation targets Node 24+, exact `@cursor/sdk@1.0.40`, official Pi 1.5.0/latest, and current `fitchmultz/pi` main.
|
|
365
365
|
|
|
366
366
|
## Pi provider SDK event capture
|
|
367
367
|
|
package/docs/development.md
CHANGED
|
@@ -67,9 +67,7 @@ A release reviewer must open every changed package path. A complete changed-sour
|
|
|
67
67
|
|
|
68
68
|
## Development
|
|
69
69
|
|
|
70
|
-
Required qualification targets are the latest stable official Pi and latest maintained `fitchmultz/pi` main, with optional wildcard Pi/TypeBox host peers and exact Cursor SDK **1.0.40**. CI resolves the official version/fork commit once and retains exact SDK/CLI provenance. Types, tests and package checks use each selected host's consistent dependency graph; the locked development Pi **1.
|
|
71
|
-
|
|
72
|
-
The frozen development `pi-coding-agent@1.1.0` input declares Undici 8.10.2. A version-scoped npm override selects released Undici 8.12.3 for that owner only, addressing its development audit findings without changing the Pi cohort or SDK transport. Dependency overrides apply only at the install root; this does not patch consumers' independently installed Pi hosts. Reassess the override when updating the development cohort.
|
|
70
|
+
Required qualification targets are the latest stable official Pi and latest maintained `fitchmultz/pi` main, with optional wildcard Pi/TypeBox host peers and exact Cursor SDK **1.0.40**. CI resolves the official version/fork commit once and retains exact SDK/CLI provenance. Types, tests and package checks use each selected host's consistent dependency graph; the locked development Pi **1.5.0** dependencies are reproducible snapshots, not qualification targets. Updating these snapshots does not upgrade the user's Pi installation or change the official Pi 1.5.0 minimum. After `npm ci --ignore-scripts`, run `node scripts/ci-compatibility.mjs --automation /path/to/automation` in an empty HOME/agent profile for credential-free latest qualification. Native macOS/Windows checks select the same resolved latest official graph. This builds the manifest entry, runs existing type/unit/package checks, and tests the compiled provider's registration plus production prompt shaping against native Pi transcript/tool transitions. Replay arguments must match their JSON stream deltas. A second native contract runs the registered Cursor provider with only its external SDK transport/storage substituted: real loopback bridge execution, display-only replay, persisted usage, incremental sends, tree navigation, compaction, request-boundary steering, abort and reload/disposal. Tests use no live Cursor service.
|
|
73
71
|
|
|
74
72
|
TypeScript 7 builds and checks package types. Build and typecheck commands invoke `node_modules/typescript/bin/tsc` explicitly to avoid npm's shared `tsc` shim selecting a different compiler. `@typescript/typescript6` is dev-only for AST architecture and installed-SDK contract tests because TypeScript 7 does not expose a stable compiler API. Vitest 5 runs with `clearMocks: true` by default.
|
|
75
73
|
|
|
@@ -78,7 +76,7 @@ Pull-request CI runs that suite once per selected host: the latest stable offici
|
|
|
78
76
|
For authorized uncommitted repairs, qualify an isolated immutable working-tree snapshot without committing:
|
|
79
77
|
|
|
80
78
|
```bash
|
|
81
|
-
node scripts/ci-compatibility.mjs --working-tree --official-only --versions
|
|
79
|
+
node scripts/ci-compatibility.mjs --working-tree --official-only --versions 1.5.0
|
|
82
80
|
```
|
|
83
81
|
|
|
84
82
|
This builds and packs the snapshot, checks package loading, and exercises actual official native provider/session flows. The default invocation still requires a clean checkout and includes the maintained fork. `--help` documents selection and exit codes.
|
package/docs/reference.md
CHANGED
|
@@ -49,11 +49,11 @@ If pi started without a key, run `/cursor-refresh-models` after `/login` to refr
|
|
|
49
49
|
## Requirements
|
|
50
50
|
|
|
51
51
|
- Node.js 24+
|
|
52
|
-
- This package requires official Pi
|
|
52
|
+
- This package requires official Pi 1.5.0 or later. The latest stable official Pi and current `fitchmultz/pi` main are required compatibility targets, resolved once per workflow run; locked development Pi packages are reproducible snapshots, not validation targets
|
|
53
53
|
- optional Pi and TypeBox peer metadata uses `"*"` ranges per Pi package guidance
|
|
54
54
|
- a Cursor SDK API key saved through `/login`, available as `CURSOR_API_KEY`, or passed with pi's `--api-key`
|
|
55
55
|
|
|
56
|
-
No global `@cursor/sdk` install is required. This package depends on exact `@cursor/sdk@1.0.40`, so normal package installation brings in that SDK. Its required Zod peer is supplied directly at patched version `4.6.6`, including for installers that do not auto-install peers. The bundled MCP bridge closure retains its own newer nested Zod `4.6.7` copies. This intentional locked layout keeps the SDK peer unbundled and reachable under Pi's managed npm installation; see [packaging verification](development.md#zod-peer-and-bridge-packaging). The extension intentionally does not bundle `@cursor/sdk` or its platform packages, because packing from one maintainer OS can ship the wrong optional SDK binary for another OS. The SDK has used its current single-file/new-chunk package layout since 1.0.28. Pi hosts that pass transcript-only provider contexts are supported through Pi
|
|
56
|
+
No global `@cursor/sdk` install is required. This package depends on exact `@cursor/sdk@1.0.40`, so normal package installation brings in that SDK. Its required Zod peer is supplied directly at patched version `4.6.6`, including for installers that do not auto-install peers. The bundled MCP bridge closure retains its own newer nested Zod `4.6.7` copies. This intentional locked layout keeps the SDK peer unbundled and reachable under Pi's managed npm installation; see [packaging verification](development.md#zod-peer-and-bridge-packaging). The extension intentionally does not bundle `@cursor/sdk` or its platform packages, because packing from one maintainer OS can ship the wrong optional SDK binary for another OS. The SDK has used its current single-file/new-chunk package layout since 1.0.28. Pi hosts that pass transcript-only provider contexts are supported through Pi's required public replay helpers.
|
|
57
57
|
|
|
58
58
|
## Install
|
|
59
59
|
|
|
@@ -149,7 +149,7 @@ The discovered catalog is cached at `~/.pi/agent/cursor-sdk-model-list.json` (wr
|
|
|
149
149
|
|
|
150
150
|
Only an accepted native generation can update the catalog, selection metadata, cache, and fallback warning. An effective no-auth refresh removes only the extension's valid regular-file orphaned catalog. Cancelled, superseded, or shut-down refreshes cannot install late results. SDK 1.0.37 catalog requests have no public caller-abort option, so cancellation rejects their late publication rather than promising to stop the underlying request.
|
|
151
151
|
|
|
152
|
-
Known host limitation: official Pi 1.0.4 and 1.1.0
|
|
152
|
+
Known host limitation: official Pi has a startup refresh-admission/readiness race, demonstrated on 1.0.4 and 1.1.0 and unchanged in the 1.5.0 refresh code, that can temporarily leave fallback models and an incorrect missing-key warning despite a matching authenticated cache. The shared-owner repair is merged in `fitchmultz/pi` via [#190](https://github.com/fitchmultz/pi/pull/190) and remains fork-only after the fork's Pi 1.5.0 sync; this is not an official-host fix. See [#337](https://github.com/fitchmultz/pi-cursor-sdk/pull/337). It is separate from Cursor service authentication failures and the compiled-loader repair.
|
|
153
153
|
|
|
154
154
|
```bash
|
|
155
155
|
# Cache lifetime in milliseconds (default 86400000 = 24h).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cursor-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.8",
|
|
4
4
|
"description": "pi provider extension backed by @cursor/sdk local and cloud agents",
|
|
5
5
|
"author": "Mitch Fultz (https://github.com/fitchmultz)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -184,9 +184,9 @@
|
|
|
184
184
|
},
|
|
185
185
|
"devDependencies": {
|
|
186
186
|
"@connectrpc/connect": "2.2.0",
|
|
187
|
-
"@earendil-works/pi-ai": "1.
|
|
188
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
189
|
-
"@earendil-works/pi-tui": "1.
|
|
187
|
+
"@earendil-works/pi-ai": "1.5.0",
|
|
188
|
+
"@earendil-works/pi-coding-agent": "1.5.0",
|
|
189
|
+
"@earendil-works/pi-tui": "1.5.0",
|
|
190
190
|
"@modelcontextprotocol/client": "2.3.1",
|
|
191
191
|
"@types/node": "24.19.1",
|
|
192
192
|
"@typescript/typescript6": "6.0.2",
|
|
@@ -199,11 +199,6 @@
|
|
|
199
199
|
"vitest": "5.0.3",
|
|
200
200
|
"yaml": "2.9.1"
|
|
201
201
|
},
|
|
202
|
-
"overrides": {
|
|
203
|
-
"@earendil-works/pi-coding-agent@1.1.0": {
|
|
204
|
-
"undici": "8.12.3"
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
202
|
"pi": {
|
|
208
203
|
"extensions": [
|
|
209
204
|
"./dist/index.js"
|
package/src/context.ts
CHANGED
|
@@ -139,23 +139,15 @@ function formatToolCall(toolCall: ToolCall): string {
|
|
|
139
139
|
|
|
140
140
|
function sanitizeSystemPromptForCursor(systemPrompt: string): string {
|
|
141
141
|
let sanitized = systemPrompt;
|
|
142
|
-
//
|
|
142
|
+
// Pi wraps its built-in tool catalog and rules in XML sections.
|
|
143
143
|
sanitized = sanitized.replace(
|
|
144
|
-
/<tools>\n[\s\S]*?\n\
|
|
144
|
+
/<tools>\n[\s\S]*?\n\nAdditional tools may be available\.\n<\/tools>/g,
|
|
145
145
|
"Pi tool catalog omitted: Cursor can call only Cursor SDK tools exposed in this run.",
|
|
146
146
|
);
|
|
147
147
|
sanitized = sanitized.replace(
|
|
148
148
|
/<rules>\n[\s\S]*?\n<\/rules>\n\n(?=<docs>\nPi documentation )/g,
|
|
149
149
|
"<rules>\n- Be concise in your responses.\n- Show file paths clearly when working with files.\n</rules>\n\n",
|
|
150
150
|
);
|
|
151
|
-
sanitized = sanitized.replace(
|
|
152
|
-
/Available tools:\n[\s\S]*?\n\nIn addition to the tools above, you may have access to other custom tools depending on the project\.\n\n/g,
|
|
153
|
-
"Pi tool catalog omitted: Cursor can call only Cursor SDK tools exposed in this run.\n\n",
|
|
154
|
-
);
|
|
155
|
-
sanitized = sanitized.replace(
|
|
156
|
-
/Guidelines:\n[\s\S]*?\n\nPi documentation /g,
|
|
157
|
-
"Guidelines:\n- Be concise in your responses.\n- Show file paths clearly when working with files.\n\nPi documentation ",
|
|
158
|
-
);
|
|
159
151
|
// Keep the Agent Skills catalog. Cursor-specific skill activation wording is normalized
|
|
160
152
|
// by cursor-skill-tool.ts before this prompt reaches the Cursor SDK provider.
|
|
161
153
|
sanitized = sanitized.replace(/\n+Semantic code intelligence priority:[\s\S]*$/g, "");
|
|
@@ -17,8 +17,6 @@ export const CURSOR_PRESERVE_PI_AGENTS_MD_ENV = "PI_CURSOR_PRESERVE_PI_AGENTS_MD
|
|
|
17
17
|
/** Opening tag prefix pi `buildSystemPrompt()` uses for each context file (path attribute only). */
|
|
18
18
|
export const PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX = '<project_instructions path="';
|
|
19
19
|
const PI_PROJECT_INSTRUCTIONS_CLOSE = "</project_instructions>";
|
|
20
|
-
const PI_PROJECT_CONTEXT_OPEN = "\n\n<project_context>\n\nProject-specific instructions and guidelines:\n\n";
|
|
21
|
-
const PI_PROJECT_CONTEXT_CLOSE = "</project_context>\n";
|
|
22
20
|
|
|
23
21
|
function normalizeContextPath(filePath: string): string {
|
|
24
22
|
return filePath.replace(/\\/g, "/");
|
|
@@ -109,27 +107,21 @@ function shouldSuppressPiAgentsContext(
|
|
|
109
107
|
return contextFiles.some((file) => shouldRemovePiAgentsContextFile(file, settingSources, agentDir));
|
|
110
108
|
}
|
|
111
109
|
|
|
112
|
-
/** Exact pi `buildSystemPrompt()` serialization for one context file block
|
|
110
|
+
/** Exact pi `buildSystemPrompt()` serialization for one context file block. */
|
|
113
111
|
export function serializePiProjectInstructionsBlock(file: PiAgentsContextFile): string {
|
|
114
|
-
return `${PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX}${file.path}">\n${file.content}\n${PI_PROJECT_INSTRUCTIONS_CLOSE}
|
|
112
|
+
return `${PI_PROJECT_INSTRUCTIONS_OPEN_PREFIX}${file.path}">\n${file.content}\n${PI_PROJECT_INSTRUCTIONS_CLOSE}`;
|
|
115
113
|
}
|
|
116
114
|
|
|
117
|
-
/**
|
|
118
|
-
export function serializePiProjectContextSection(
|
|
119
|
-
contextFiles: readonly PiAgentsContextFile[],
|
|
120
|
-
format: "legacy" | "transcript" = "legacy",
|
|
121
|
-
): string {
|
|
115
|
+
/** Exact pi `buildSystemPrompt()` serialization for the project_context section. */
|
|
116
|
+
export function serializePiProjectContextSection(contextFiles: readonly PiAgentsContextFile[]): string {
|
|
122
117
|
if (contextFiles.length === 0) return "";
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
].join("\n");
|
|
131
|
-
}
|
|
132
|
-
return `${PI_PROJECT_CONTEXT_OPEN}${contextFiles.map(serializePiProjectInstructionsBlock).join("")}${PI_PROJECT_CONTEXT_CLOSE}`;
|
|
118
|
+
return [
|
|
119
|
+
"<project_context>",
|
|
120
|
+
"Project-specific instructions and guidelines:",
|
|
121
|
+
"",
|
|
122
|
+
contextFiles.map(serializePiProjectInstructionsBlock).join("\n\n"),
|
|
123
|
+
"</project_context>",
|
|
124
|
+
].join("\n");
|
|
133
125
|
}
|
|
134
126
|
|
|
135
127
|
/** Remove pi context blocks that overlap Cursor setting sources. */
|
|
@@ -150,16 +142,13 @@ export function removePiAgentsContextFromSystemPrompt(
|
|
|
150
142
|
}
|
|
151
143
|
if (!removedAny) return systemPrompt;
|
|
152
144
|
|
|
153
|
-
// Match only the exact known files
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
|
|
161
|
-
}
|
|
162
|
-
return systemPrompt;
|
|
145
|
+
// Match only the exact known files; never strip arbitrary user-authored XML
|
|
146
|
+
// or neighboring custom sections.
|
|
147
|
+
const originalSection = serializePiProjectContextSection(contextFiles);
|
|
148
|
+
const start = systemPrompt.indexOf(originalSection);
|
|
149
|
+
if (start < 0) return systemPrompt;
|
|
150
|
+
const replacementSection = serializePiProjectContextSection(retainedContextFiles);
|
|
151
|
+
return systemPrompt.slice(0, start) + replacementSection + systemPrompt.slice(start + originalSection.length);
|
|
163
152
|
}
|
|
164
153
|
|
|
165
154
|
export function resolveCursorFacingSystemPrompt(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
|
-
import { getLanguageFromPath, highlightCode,
|
|
3
|
+
import { getLanguageFromPath, highlightCode, type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { Image, Text, type Component } from "@earendil-works/pi-tui";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
import { resolveCursorEditDiff } from "./cursor-edit-diff.js";
|
|
@@ -422,14 +422,6 @@ function hasCursorReplayDisplayTitle(details: CursorReplayToolDetails | undefine
|
|
|
422
422
|
return isCursorReplayActivityDetails(details) || isCursorReplayGenerateImageDetails(details);
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
-
function formatCursorReplayExpandHint(): string {
|
|
426
|
-
try {
|
|
427
|
-
return keyHint("app.tools.expand", "to expand");
|
|
428
|
-
} catch {
|
|
429
|
-
return "Ctrl+O to expand";
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
425
|
function renderExpandableCursorReplayResult(
|
|
434
426
|
title: string,
|
|
435
427
|
details: CursorReplayExpandableResultDetails,
|
|
@@ -443,7 +435,7 @@ function renderExpandableCursorReplayResult(
|
|
|
443
435
|
const summary = details.summary ?? text.split("\n").find((line) => line.trim()) ?? "completed";
|
|
444
436
|
const expandedText = details.expandedText ?? (text.includes("\n") ? text : undefined);
|
|
445
437
|
const showExpandHint = expandedText && !options.expanded && shouldShowCursorReplayCollapsedExpandHint(details.sourceToolName);
|
|
446
|
-
const expandHint = showExpandHint ? theme.fg("dim", ` (${
|
|
438
|
+
const expandHint = showExpandHint ? theme.fg("dim", ` (${context.keyHint("app.tools.expand", "to expand")})`) : "";
|
|
447
439
|
let rendered = `${theme.fg("toolTitle", theme.bold(title))} ${theme.fg(isError ? "error" : "success", summary)}${expandHint}`;
|
|
448
440
|
if (expandedText && (options.expanded || !details.collapseDetailsByDefault)) {
|
|
449
441
|
const preview = formatCursorReplayActivityPreview(
|