pi-cursor-sdk 0.1.36 → 0.1.38
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 +38 -0
- package/docs/cursor-model-ux-spec.md +1 -1
- package/docs/cursor-native-tool-replay.md +9 -9
- package/package.json +1 -1
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/src/context-window-cache.ts +10 -14
- package/src/context.ts +1 -1
- package/src/cursor-agent-message-web-tools.ts +2 -1
- package/src/cursor-agents-context-registration.ts +18 -0
- package/src/cursor-agents-context.ts +21 -30
- package/src/cursor-edit-diff.ts +4 -2
- package/src/cursor-fallback-warning.ts +22 -0
- package/src/cursor-incomplete-tool-visibility.ts +5 -11
- package/src/cursor-live-run-coordinator.ts +1 -1
- package/src/cursor-mcp-timeout-override.ts +0 -2
- package/src/cursor-model-lifecycle.ts +72 -0
- package/src/cursor-native-replay-routing.ts +1 -1
- package/src/cursor-native-replay-trace.ts +1 -1
- package/src/cursor-native-tool-display-registration.ts +16 -28
- package/src/cursor-native-tool-display-replay.ts +12 -47
- package/src/cursor-native-tool-display-state.ts +1 -1
- package/src/cursor-native-tool-display-tools.ts +10 -18
- package/src/cursor-native-tool-names.ts +16 -0
- package/src/cursor-pi-tool-bridge-env.ts +12 -0
- package/src/cursor-pi-tool-bridge-mcp.ts +16 -21
- package/src/cursor-pi-tool-bridge-run.ts +5 -5
- package/src/cursor-pi-tool-bridge-server.ts +8 -3
- package/src/cursor-pi-tool-bridge-snapshot.ts +7 -13
- package/src/cursor-pi-tool-bridge.ts +7 -7
- package/src/cursor-provider-lazy.ts +51 -0
- package/src/cursor-provider-live-run-drain.ts +1 -1
- package/src/cursor-provider-run-finalizer.ts +5 -5
- package/src/cursor-provider-run-outcome.ts +0 -1
- package/src/cursor-provider-turn-coordinator.ts +4 -5
- package/src/cursor-provider-turn-display-router.ts +5 -1
- package/src/cursor-provider-turn-emit.ts +1 -1
- package/src/cursor-provider-turn-lifecycle-emitter.ts +1 -5
- package/src/cursor-provider-turn-prepare.ts +13 -9
- package/src/cursor-provider-turn-runner.ts +3 -11
- package/src/cursor-provider-turn-sdk-normalizer.ts +28 -5
- package/src/cursor-provider-turn-send.ts +7 -2
- package/src/cursor-provider-turn-types.ts +1 -3
- package/src/cursor-provider.ts +3 -2
- package/src/cursor-question-tool.ts +5 -18
- package/src/cursor-record-utils.ts +42 -0
- package/src/cursor-replay-activity-builders.ts +16 -122
- package/src/cursor-replay-tool-details.ts +57 -197
- package/src/cursor-sdk-event-debug.ts +6 -6
- package/src/cursor-sensitive-text.ts +4 -4
- package/src/cursor-session-agent-lifecycle.ts +47 -0
- package/src/cursor-session-agent.ts +9 -47
- package/src/cursor-session-scope.ts +23 -4
- package/src/cursor-setting-sources.ts +8 -8
- package/src/cursor-skill-tool.ts +25 -32
- package/src/cursor-state.ts +66 -45
- package/src/cursor-tool-lifecycle.ts +16 -9
- package/src/cursor-tool-presentation-registry.ts +42 -169
- package/src/cursor-tool-result-display-readers.ts +185 -0
- package/src/cursor-tool-transcript.ts +17 -33
- package/src/cursor-tool-visibility.ts +9 -1
- package/src/cursor-transcript-tool-formatters.ts +23 -172
- package/src/cursor-transcript-tool-specs.ts +17 -57
- package/src/cursor-transcript-utils.ts +2 -34
- package/src/cursor-usage-accounting.ts +0 -6
- package/src/cursor-web-tool-activity.ts +4 -12
- package/src/cursor-web-tool-args.ts +1 -9
- package/src/index.ts +15 -16
- package/src/model-discovery.ts +5 -4
- package/src/model-list-cache.ts +37 -38
- package/src/cursor-native-tool-display.ts +0 -10
- package/src/cursor-provider-turn-api-key.ts +0 -1
- package/src/cursor-provider-turn-message-offset.ts +0 -15
- package/src/cursor-session-cwd.ts +0 -28
- package/src/cursor-tool-names.ts +0 -18
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.38 - 2026-06-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Add shared Cursor replay result readers so transcript formatting, native replay cards, and activity builders consume the same MCP-like content/diff/file-preview extraction logic.
|
|
10
|
+
- Add a canonical Cursor model lifecycle sync helper for session start, before-agent-start, model selection, and turn start registration paths.
|
|
11
|
+
- Add lazy Cursor provider registration so extension startup can register models and commands without importing the Cursor SDK runtime until the provider is invoked.
|
|
12
|
+
- Add shared Cursor native tool-name and pi-tool-bridge environment helpers for provider/runtime registration code.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Centralize Cursor tool presentation ownership in the typed presentation registry, including labels, aliases, lifecycle titles, replay metadata, side-effect policies, and web-tool classification.
|
|
17
|
+
- Consolidate Cursor session cwd, session file/id, generation, and scope-key handling in `cursor-session-scope`; remove the older cwd/message-offset helper split.
|
|
18
|
+
- Simplify Cursor session-agent lifecycle invalidation on model select, compaction preparation, tree navigation, shutdown, and scope changes.
|
|
19
|
+
- Refine Cursor tool lifecycle/replay display routing so completed replay cards, inactive traces, native replay activation, and duplicate step/delta completions share one display path.
|
|
20
|
+
- Keep Cursor agents-context dedup and fallback-catalog warning registration model-scoped through the shared lifecycle helper.
|
|
21
|
+
- Keep edit/write replay previews on the shared structured diff/file preview renderers while retaining SDK expanded-text fallback behavior.
|
|
22
|
+
- Update maintainer docs and repo map entries for the new ownership boundaries.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Clear started Cursor tool calls when a completed delta reports the same tool under a different SDK call id, preventing stale native replay edit starts from surfacing as `Cursor edit did not complete` after successful final text.
|
|
27
|
+
- Keep Cursor agents-context dedup registration in a tracked module so clean package builds resolve `src/index.ts` imports.
|
|
28
|
+
- Accept Windows-rendered absolute `README.md` paths in platform-smoke grep-card detection without weakening prompt false-positive checks.
|
|
29
|
+
- Preserve Cursor skill activation and question-tool registration through lazy provider/runtime import boundaries.
|
|
30
|
+
- Preserve fast local discovery incomplete-tool suppression while still surfacing aborts, SDK failures, and no-text incomplete runs.
|
|
31
|
+
|
|
32
|
+
## 0.1.37 - 2026-06-06
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Cut Cursor native replay over to one canonical replay surface: neutral `cursor` activity cards plus native-compatible `read`, `bash`, `grep`, `find`, `ls`, `edit`, and `write` cards. Legacy `cursor_*` replay wrapper names, alias exports, old `cursorToolName` replay-detail parsing, and replay-only prompt metadata are removed instead of preserved behind compatibility shims (#123).
|
|
37
|
+
- Keep edit/write replay previews on the shared structured diff/file preview renderers, while retaining unstructured `expandedText` unified-diff extraction only as a fallback for current SDK payloads that do not include structured diff fields.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Stop registering duplicate replay-only prompt snippets/guidelines for every Cursor SDK activity wrapper, eliminating the inflated prompt metadata reported by issue #123 while preserving current TUI replay card titles, summaries, typed details, and `sourceToolName` display metadata.
|
|
42
|
+
|
|
5
43
|
## 0.1.36 - 2026-06-05
|
|
6
44
|
|
|
7
45
|
### Fixed
|
|
@@ -30,7 +30,7 @@ Current implementation notes:
|
|
|
30
30
|
- 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.
|
|
31
31
|
- 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.
|
|
32
32
|
- Cursor internal tool activity is recorded from SDK events and scrubbed. Maintainer reference for all 16 `@cursor/sdk@1.0.17` `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 interactive TTY sessions, 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 the TUI can show native-looking cards 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, image, and MCP activity use neutral Cursor activity cards with pi's default success/error shell. Neutral Cursor activity calls include `activityTitle` and, when available, `activitySummary` so partial/collapsed cards preserve identity such as `Cursor plan`, `Cursor todos`, `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/aborted, produced no assistant text, or involved external/side-effectful tools; incomplete fast local discovery starts (`read`, `grep`, `glob`, `ls`) remain maintainer-debug-only after successful text-producing runs so stale SDK start events do not create red post-answer 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 used only as display-only fallback for empty successful shell completions, and overlapping shell calls drop ambiguous deltas instead of guessing. Non-interactive runs keep bounded scrubbed transcript output instead, preserving `pi -p` assistant text output. Cursor text deltas stream live when no live-run turn split is active.
|
|
33
|
-
-
|
|
33
|
+
- 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.
|
|
34
34
|
- Cursor SDK usage events report cumulative internal agent/tool/cache work, not the replayable pi prompt context. The extension does not copy raw Cursor SDK usage into pi usage or compaction. For Cursor assistant messages, `usage.input`/`usage.output` are approximate pi session activity components: initial Cursor prompt input is counted once, consumed split-run tool results are counted as deduped input on the following assistant turn, and assistant output includes visible text/thinking/tool-call content. `usage.totalTokens` is the replayable Cursor prompt/context estimate derived from the same `buildCursorPrompt()` path used for `Agent.send`; it may differ from `input + output` and is the context-safe value for display/compaction. `src/cursor-usage-accounting.ts` owns this usage policy, and `src/cursor-live-run-accounting.ts` owns prompt-once and consumed-tool-result accounting so provider usage and bridge result resolution share the same matched tool-result boundary.
|
|
35
35
|
- 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 external/side-effectful started calls are surfaced at run completion through the same native replay routing as completed tools (activity cards when allowed, otherwise inactive/transcript traces), while fast local discovery starts are debug-only after a successful text-producing run. Cursor-reported completed/step errors remain visible.
|
|
36
36
|
- 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.
|
|
@@ -70,9 +70,9 @@ Edit and write activity replays through pi-facing `edit` and `write` cards only
|
|
|
70
70
|
|
|
71
71
|
Source of truth for SDK tool names: `@cursor/sdk@1.0.17` conversation `ToolType` values and https://cursor.com/docs/sdk/typescript
|
|
72
72
|
|
|
73
|
-
Implementation owners: `src/cursor-tool-presentation-registry.ts` (canonical names, labels, visibility, replay policy, bridge exclusions for internal replay wrappers, and display-spec key completeness), `src/cursor-transcript-tool-specs.ts` (registry-keyed
|
|
73
|
+
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).
|
|
74
74
|
|
|
75
|
-
**Maintainer invariants — edit/write replay previews:** All colored diff rendering (native `edit` cards and `Cursor edit` activity fallbacks) flows through the single `formatCursorReplayDiff()` in `src/cursor-native-tool-display-replay.ts`. Activity write fallbacks with structured `fileContentAfterWrite` use the same `formatCursorReplayFilePreview()` path as native `write` cards. Structured `diffString` (and `diff`/`lines*`) or `fileContentAfterWrite` on `CursorReplay*Details` (including activity variants) is the source of truth for TUI preview coloring/highlighting. `expandedText` on activity details is for summary/expansion and
|
|
75
|
+
**Maintainer invariants — edit/write replay previews:** All colored diff rendering (native `edit` cards and `Cursor edit` activity fallbacks) flows through the single `formatCursorReplayDiff()` in `src/cursor-native-tool-display-replay.ts`. Activity write fallbacks with structured `fileContentAfterWrite` use the same `formatCursorReplayFilePreview()` path as native `write` cards. Structured `diffString` (and `diff`/`lines*`) or `fileContentAfterWrite` on `CursorReplay*Details` (including activity variants) is the source of truth for TUI preview coloring/highlighting. `expandedText` on activity details is for summary/expansion and as a fallback when the current SDK reports a unified diff only in text; it is never the primary preview source when structured fields are present. No parallel +/- coloring loops exist.
|
|
76
76
|
|
|
77
77
|
This matrix covers **Cursor native tool replay only**. It does not describe the [live pi MCP bridge](#live-bridge-vs-replay) or Cursor-native host tools, settings, plugins, and configured MCP servers from the Cursor SDK local-agent path.
|
|
78
78
|
|
|
@@ -98,15 +98,15 @@ This matrix covers **Cursor native tool replay only**. It does not describe the
|
|
|
98
98
|
| *(host/MCP alias)* `WebFetch` / `web_fetch` / similar | neutral activity | `cursor` | Collapsed label **Cursor web fetch**; display-only Cursor web access reported by the SDK, not an executable pi web tool |
|
|
99
99
|
| _(no spec; future/unknown SDK name)_ | neutral activity | `cursor` | Collapsed label **Cursor** plus SDK tool name via `buildGenericPiToolDisplay()`; bounded fallback transcript only |
|
|
100
100
|
|
|
101
|
-
**Unknown/future fallback path:** SDK tool names with no registry-backed
|
|
101
|
+
**Unknown/future fallback path:** SDK tool names with no registry-backed display implementation entry (future or unknown types) use `buildGenericPiToolDisplay()` in `src/cursor-transcript-tool-specs.ts` with bounded `formatFallback()` content from `src/cursor-transcript-tool-formatters.ts`. Lookup uses `Object.hasOwn()` on the display implementation table so inherited object keys such as `constructor` or `toString` cannot accidentally match a registry spec. When native replay is enabled, those completions queue through neutral pi tool name `cursor` (not native pi `read`/`bash`/… cards). Collapsed labels read like **Cursor futureSemSearchWidget** (title `Cursor` plus the SDK tool name) with optional bounded `activitySummary` from scrubbed args/result lines. Errors keep `details.summary` undefined so unbounded raw errors do not leak into replay cards (#52). Known explicit specs still win over this path; real pi bridge tool names such as `edit` and `write` are not suppressed by internal replay-wrapper exclusions.
|
|
102
102
|
|
|
103
|
-
**Replay detail disposition model:** `src/cursor-replay-tool-details.ts` stores replay card disposition separately from SDK source tool identity. Variants are `nativeEdit`, `nativeWrite`, `activity` (`sourceToolName` + display `title`), `generateImage`, and `genericFallback`. Path-only or notebook edit/write fallbacks produce `activity` details (neutral `cursor` cards) instead of structured edit/write variants with optional `title` escape hatches. Native edit/write cards use `nativeEdit` / `nativeWrite` only when pi-facing replay args satisfy the matching schema. The renderer dispatches on `variant` only
|
|
103
|
+
**Replay detail disposition model:** `src/cursor-replay-tool-details.ts` stores replay card disposition separately from SDK source tool identity. Variants are `nativeEdit`, `nativeWrite`, `activity` (`sourceToolName` + display `title`), `generateImage`, and `genericFallback`. Path-only or notebook edit/write fallbacks produce `activity` details (neutral `cursor` cards) instead of structured edit/write variants with optional `title` escape hatches. Native edit/write cards use `nativeEdit` / `nativeWrite` only when pi-facing replay args satisfy the matching schema. The renderer dispatches on `variant` only.
|
|
104
104
|
|
|
105
|
-
Neutral activity rows use pi tool name `cursor` with `activityTitle` / `activitySummary` metadata.
|
|
105
|
+
Neutral activity rows use pi tool name `cursor` with `activityTitle` / `activitySummary` metadata. User-visible collapsed cards use labels like **Cursor semantic search**.
|
|
106
106
|
|
|
107
107
|
## Runtime alias normalization
|
|
108
108
|
|
|
109
|
-
Before lookup
|
|
109
|
+
Before display lookup, completed SDK tool names pass through `normalizeCursorToolName()` in `src/cursor-tool-presentation-registry.ts`; MCP web tool names are additionally remapped by `resolveTranscriptToolName()` in `src/cursor-web-tool-activity.ts`. Documented aliases:
|
|
110
110
|
|
|
111
111
|
| Runtime alias | Canonical SDK name |
|
|
112
112
|
| --- | --- |
|
|
@@ -184,15 +184,15 @@ For shell replay, completed `stdout` / `stderr` remain the primary source. If a
|
|
|
184
184
|
|
|
185
185
|
Non-interactive and session consumers still receive bounded scrubbed transcript data so `pi -p` keeps printing normal assistant text.
|
|
186
186
|
|
|
187
|
-
##
|
|
187
|
+
## Replay-name policy
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
Cursor native replay has one neutral replay tool name, `cursor`, plus native-compatible card names when renderer-compatible: `read`, `bash`, `grep`, `find`, `ls`, `edit`, and `write`. Neutral replay identity lives in `activityTitle`, `activitySummary`, and typed replay details, not in extra registered tool names.
|
|
190
190
|
|
|
191
191
|
Bridge MCP names are also not pi tool names. Cursor may see names such as `pi__sem_reindex` inside the local MCP bridge, but pi session output uses the real pi tool name.
|
|
192
192
|
|
|
193
193
|
## Conflicts and opt out
|
|
194
194
|
|
|
195
|
-
Native replay wrappers are registered only for tool names not already owned by another extension. If another extension already owns a wrapper name needed for replay, pi-cursor-sdk skips only the conflicting wrapper and uses the scrubbed Cursor activity transcript for that tool instead.
|
|
195
|
+
Native replay wrappers are registered only for tool names not already owned by another extension. If another extension already owns a wrapper name needed for replay, pi-cursor-sdk skips only the conflicting wrapper and uses the scrubbed Cursor activity transcript for that tool instead.
|
|
196
196
|
|
|
197
197
|
Disable native replay registration entirely:
|
|
198
198
|
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ import { resolve } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
const CARD_PATTERNS = [
|
|
13
13
|
{ id: "read", pattern: /^\s*read (?:\.\/)?package\.json\s*$/i },
|
|
14
|
-
{ id: "grep", pattern: /^\s*grep \/pi-cursor-sdk\/ in
|
|
14
|
+
{ id: "grep", pattern: /^\s*grep \/pi-cursor-sdk\/ in\s+(?:(?:\S+[\\/])?README\.md)\s*$/i },
|
|
15
15
|
{ id: "find", pattern: /^\s*find README\.md in\s+\S+/i },
|
|
16
16
|
{ id: "list", pattern: /^\s*(?:find \* in src|find src\/\* in \.|Get-ChildItem -Name \.\/src)\s*/i },
|
|
17
17
|
{ id: "shell-success", pattern: /^\s*cursor visual smoke\s*$/i },
|
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { BUNDLED_CONTEXT_WINDOWS } from "./bundled-context-windows.js";
|
|
5
|
+
import { asRecord } from "./cursor-record-utils.js";
|
|
5
6
|
|
|
6
7
|
const CONTEXT_WINDOW_CACHE_FILE = "cursor-sdk-context-windows.json";
|
|
7
8
|
let userContextWindowOverrideLoadCount = 0;
|
|
@@ -18,18 +19,16 @@ function isPositiveInteger(value: unknown): value is number {
|
|
|
18
19
|
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
22
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
22
|
function parseContextWindowCacheFile(value: unknown): ContextWindowCacheFile | undefined {
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
const record = asRecord(value);
|
|
24
|
+
if (!record) return undefined;
|
|
25
|
+
const { contextWindows } = record;
|
|
28
26
|
if (contextWindows === undefined) return {};
|
|
29
|
-
|
|
27
|
+
const contextWindowRecord = asRecord(contextWindows);
|
|
28
|
+
if (!contextWindowRecord) return undefined;
|
|
30
29
|
return {
|
|
31
30
|
contextWindows: Object.fromEntries(
|
|
32
|
-
Object.entries(
|
|
31
|
+
Object.entries(contextWindowRecord).filter((entry): entry is [string, number] => isPositiveInteger(entry[1])),
|
|
33
32
|
),
|
|
34
33
|
};
|
|
35
34
|
}
|
|
@@ -68,12 +67,9 @@ export function getCachedContextWindow(modelId: string): number | undefined {
|
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
export function getCheckpointContextWindow(checkpoint: unknown): number | undefined {
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
const { maxTokens } = tokenDetails;
|
|
75
|
-
if (!isPositiveInteger(maxTokens)) return undefined;
|
|
76
|
-
return maxTokens;
|
|
70
|
+
const tokenDetails = asRecord(checkpoint)?.tokenDetails;
|
|
71
|
+
const maxTokens = asRecord(tokenDetails)?.maxTokens;
|
|
72
|
+
return isPositiveInteger(maxTokens) ? maxTokens : undefined;
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
export function saveCachedContextWindow(modelId: string, contextWindow: number): void {
|
package/src/context.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import type { Context, Message, ToolCall } from "@earendil-works/pi-ai";
|
|
3
3
|
import { convertToLlm } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import type { SDKImage } from "@cursor/sdk";
|
|
5
|
-
import { getCursorReplayPromptLabel } from "./cursor-tool-
|
|
5
|
+
import { getCursorReplayPromptLabel } from "./cursor-tool-presentation-registry.js";
|
|
6
6
|
|
|
7
7
|
export interface CursorPrompt {
|
|
8
8
|
text: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentMessage } from "@cursor/sdk";
|
|
2
|
-
import { asRecord, getArray, getString
|
|
2
|
+
import { asRecord, getArray, getString } from "./cursor-record-utils.js";
|
|
3
|
+
import { stringifyUnknown } from "./cursor-transcript-utils.js";
|
|
3
4
|
import { loadCursorSdk } from "./cursor-sdk-runtime.js";
|
|
4
5
|
|
|
5
6
|
const CURSOR_AGENT_MESSAGE_PAGE_LIMIT = 8;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
|
|
2
|
+
|
|
3
|
+
export type CursorAgentsContextExtensionApi = CursorModelLifecycleExtensionApi;
|
|
4
|
+
|
|
5
|
+
export function registerCursorAgentsContextDedup(pi: CursorAgentsContextExtensionApi): void {
|
|
6
|
+
registerCursorModelLifecycle(pi, {
|
|
7
|
+
beforeAgentStart: async (event, ctx) => {
|
|
8
|
+
const { resolveCursorFacingSystemPrompt } = await import("./cursor-agents-context.js");
|
|
9
|
+
const resolved = resolveCursorFacingSystemPrompt(
|
|
10
|
+
event.systemPrompt,
|
|
11
|
+
ctx.model,
|
|
12
|
+
event.systemPromptOptions,
|
|
13
|
+
);
|
|
14
|
+
if (resolved === event.systemPrompt) return undefined;
|
|
15
|
+
return { systemPrompt: resolved };
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
BeforeAgentStartEvent,
|
|
3
|
-
BeforeAgentStartEventResult,
|
|
4
2
|
BuildSystemPromptOptions,
|
|
5
|
-
ExtensionAPI,
|
|
6
3
|
ExtensionContext,
|
|
7
|
-
ExtensionHandler,
|
|
8
4
|
} from "@earendil-works/pi-coding-agent";
|
|
9
5
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
10
6
|
import { parseEnvBoolean } from "./cursor-env-boolean.js";
|
|
11
7
|
import { isCursorModel } from "./cursor-model.js";
|
|
12
8
|
import {
|
|
13
|
-
|
|
14
|
-
cursorSettingSourcesLoadUserAgentsRules,
|
|
9
|
+
cursorSettingSourcesIncludes,
|
|
15
10
|
getEffectiveCursorSettingSources,
|
|
11
|
+
resolveCursorSettingSources,
|
|
16
12
|
} from "./cursor-setting-sources.js";
|
|
17
13
|
import type { SettingSource } from "@cursor/sdk";
|
|
14
|
+
export { registerCursorAgentsContextDedup, type CursorAgentsContextExtensionApi } from "./cursor-agents-context-registration.js";
|
|
18
15
|
|
|
19
16
|
export const CURSOR_PRESERVE_PI_AGENTS_MD_ENV = "PI_CURSOR_PRESERVE_PI_AGENTS_MD";
|
|
20
17
|
|
|
@@ -49,18 +46,24 @@ export function getAgentsContextFileBaseName(filePath: string): string {
|
|
|
49
46
|
return normalized.slice(normalized.lastIndexOf("/") + 1).toLowerCase();
|
|
50
47
|
}
|
|
51
48
|
|
|
49
|
+
function isPiAgentDirContextFilePath(
|
|
50
|
+
filePath: string,
|
|
51
|
+
fileName: "agents.md" | "claude.md",
|
|
52
|
+
agentDir: string = getAgentDir(),
|
|
53
|
+
): boolean {
|
|
54
|
+
const normalized = normalizeContextPath(filePath);
|
|
55
|
+
const expectedPath = `${normalizeDirPath(agentDir)}/${fileName}`;
|
|
56
|
+
return normalized.toLowerCase() === expectedPath.toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
|
|
52
59
|
/** Actual pi agent dir `AGENTS.md` — overlaps Cursor `user` setting source (global agent instructions). */
|
|
53
60
|
export function isPiAgentDirAgentsMdPath(filePath: string, agentDir: string = getAgentDir()): boolean {
|
|
54
|
-
|
|
55
|
-
const agentsMdPath = `${normalizeDirPath(agentDir)}/agents.md`;
|
|
56
|
-
return normalized.toLowerCase() === agentsMdPath.toLowerCase();
|
|
61
|
+
return isPiAgentDirContextFilePath(filePath, "agents.md", agentDir);
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
/** Actual pi agent dir `CLAUDE.md` — kept because Cursor user rules use `~/.claude/CLAUDE.md`. */
|
|
60
65
|
export function isPiAgentDirClaudeMdPath(filePath: string, agentDir: string = getAgentDir()): boolean {
|
|
61
|
-
|
|
62
|
-
const claudeMdPath = `${normalizeDirPath(agentDir)}/claude.md`;
|
|
63
|
-
return normalized.toLowerCase() === claudeMdPath.toLowerCase();
|
|
66
|
+
return isPiAgentDirContextFilePath(filePath, "claude.md", agentDir);
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
/**
|
|
@@ -87,9 +90,9 @@ export function shouldRemovePiAgentsContextFile(
|
|
|
87
90
|
): boolean {
|
|
88
91
|
switch (classifyContextFileOverlap(file.path, agentDir)) {
|
|
89
92
|
case "cursor-user-agents":
|
|
90
|
-
return
|
|
93
|
+
return cursorSettingSourcesIncludes(settingSources, "user");
|
|
91
94
|
case "cursor-project-rules":
|
|
92
|
-
return
|
|
95
|
+
return cursorSettingSourcesIncludes(settingSources, "project");
|
|
93
96
|
default:
|
|
94
97
|
return false;
|
|
95
98
|
}
|
|
@@ -153,24 +156,12 @@ export function resolveCursorFacingSystemPrompt(
|
|
|
153
156
|
): string {
|
|
154
157
|
if (!systemPromptOptions) return systemPrompt;
|
|
155
158
|
const contextFiles = systemPromptOptions.contextFiles ?? [];
|
|
156
|
-
const settingSources =
|
|
159
|
+
const settingSources =
|
|
160
|
+
settingSourcesRaw === undefined
|
|
161
|
+
? getEffectiveCursorSettingSources()
|
|
162
|
+
: resolveCursorSettingSources(settingSourcesRaw);
|
|
157
163
|
if (!shouldSuppressPiAgentsContext(model, contextFiles, settingSources, agentDir)) {
|
|
158
164
|
return systemPrompt;
|
|
159
165
|
}
|
|
160
166
|
return removePiAgentsContextFromSystemPrompt(systemPrompt, contextFiles, settingSources, agentDir);
|
|
161
167
|
}
|
|
162
|
-
|
|
163
|
-
type CursorAgentsContextExtensionApi = Pick<ExtensionAPI, "on">;
|
|
164
|
-
|
|
165
|
-
export function registerCursorAgentsContextDedup(pi: CursorAgentsContextExtensionApi): void {
|
|
166
|
-
const handler: ExtensionHandler<BeforeAgentStartEvent, BeforeAgentStartEventResult> = (event, ctx) => {
|
|
167
|
-
const resolved = resolveCursorFacingSystemPrompt(
|
|
168
|
-
event.systemPrompt,
|
|
169
|
-
ctx.model,
|
|
170
|
-
event.systemPromptOptions,
|
|
171
|
-
);
|
|
172
|
-
if (resolved === event.systemPrompt) return;
|
|
173
|
-
return { systemPrompt: resolved };
|
|
174
|
-
};
|
|
175
|
-
pi.on("before_agent_start", handler);
|
|
176
|
-
}
|
package/src/cursor-edit-diff.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { asRecord } from "./cursor-record-utils.js";
|
|
2
|
+
|
|
1
3
|
const CURSOR_EDIT_DIFF_FIELD_ORDER = ["diffString", "diff", "unifiedDiff", "patch"] as const;
|
|
2
4
|
|
|
3
5
|
export function resolveCursorEditDiff(source: unknown): string | undefined {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
const record = asRecord(source);
|
|
7
|
+
if (!record) return undefined;
|
|
6
8
|
for (const key of CURSOR_EDIT_DIFF_FIELD_ORDER) {
|
|
7
9
|
const value = record[key];
|
|
8
10
|
if (typeof value === "string" && value.length > 0) return value;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { isCursorModel } from "./cursor-model.js";
|
|
3
|
+
import { registerCursorModelLifecycle, type CursorModelLifecycleExtensionApi } from "./cursor-model-lifecycle.js";
|
|
4
|
+
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
5
|
+
import type { CursorModelFallbackIssue } from "./model-discovery.js";
|
|
6
|
+
|
|
7
|
+
export type CursorFallbackWarningExtensionApi = CursorModelLifecycleExtensionApi;
|
|
8
|
+
|
|
9
|
+
export function registerCursorFallbackIssueWarning(
|
|
10
|
+
pi: CursorFallbackWarningExtensionApi,
|
|
11
|
+
issue: CursorModelFallbackIssue,
|
|
12
|
+
): void {
|
|
13
|
+
const warnedSessionScopeKeys = new Set<string>();
|
|
14
|
+
|
|
15
|
+
registerCursorModelLifecycle(pi, (ctx: ExtensionContext) => {
|
|
16
|
+
if (!isCursorModel(ctx.model) || !ctx.hasUI) return;
|
|
17
|
+
const scopeKey = getCursorSessionScopeKey();
|
|
18
|
+
if (warnedSessionScopeKeys.has(scopeKey)) return;
|
|
19
|
+
warnedSessionScopeKeys.add(scopeKey);
|
|
20
|
+
ctx.ui.notify(issue.message, "warning");
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CURSOR_REPLAY_ACTIVITY_TOOL_NAME } from "./cursor-tool-
|
|
1
|
+
import { CURSOR_REPLAY_ACTIVITY_TOOL_NAME, getCursorToolActivityTitle } from "./cursor-tool-presentation-registry.js";
|
|
2
2
|
import { truncateCursorDisplayLine } from "./cursor-display-text.js";
|
|
3
3
|
import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
4
4
|
import {
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
parseCursorReplayToolDetails,
|
|
11
11
|
resolveIncompleteReplayActivitySourceToolName,
|
|
12
12
|
} from "./cursor-replay-tool-details.js";
|
|
13
|
-
import {
|
|
13
|
+
import { asRecord } from "./cursor-record-utils.js";
|
|
14
|
+
import { type CursorPiToolDisplay } from "./cursor-transcript-utils.js";
|
|
14
15
|
import { classifyCursorToolVisibility } from "./cursor-tool-visibility.js";
|
|
15
16
|
|
|
16
17
|
export type IncompleteCursorToolDiscardReason = DiscardedIncompleteStartedToolCallReason;
|
|
@@ -59,11 +60,6 @@ export function resolveIncompleteCursorToolVisibility(
|
|
|
59
60
|
return "emit";
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
function buildGenericIncompleteActivityTitle(displayName: string): string {
|
|
63
|
-
if (!displayName || displayName === "unknown") return "Cursor tool";
|
|
64
|
-
return `Cursor ${truncateArg(displayName)}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
63
|
export function formatIncompleteCursorToolReasonText(reason: IncompleteCursorToolDiscardReason): string {
|
|
68
64
|
switch (reason) {
|
|
69
65
|
case DISCARDED_INCOMPLETE_TOOL_CALL_REASON:
|
|
@@ -79,7 +75,7 @@ export function formatIncompleteCursorToolReasonText(reason: IncompleteCursorToo
|
|
|
79
75
|
|
|
80
76
|
export function getIncompleteCursorToolActivityTitle(toolCall: unknown): string {
|
|
81
77
|
const visibility = classifyCursorToolVisibility(toolCall);
|
|
82
|
-
return visibility.incompleteTitle ??
|
|
78
|
+
return visibility.incompleteTitle ?? getCursorToolActivityTitle(visibility.displayName);
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
export function buildIncompleteCursorToolDisplay(
|
|
@@ -103,7 +99,6 @@ export function buildIncompleteCursorToolDisplay(
|
|
|
103
99
|
return {
|
|
104
100
|
toolName: CURSOR_REPLAY_ACTIVITY_TOOL_NAME,
|
|
105
101
|
args: {
|
|
106
|
-
cursorToolName: visibility.normalizedName,
|
|
107
102
|
activityTitle,
|
|
108
103
|
activitySummary: reasonText,
|
|
109
104
|
incomplete: true,
|
|
@@ -125,8 +120,7 @@ export function formatIncompleteCursorToolTrace(display: CursorPiToolDisplay): s
|
|
|
125
120
|
formatIncompleteCursorToolReasonText(DISCARDED_INCOMPLETE_TOOL_CALL_REASON);
|
|
126
121
|
return `${truncateCursorDisplayLine(parsed.title)}: ${truncateCursorDisplayLine(summary)}\n`;
|
|
127
122
|
}
|
|
128
|
-
const
|
|
129
|
-
const detailRecord = details && typeof details === "object" ? (details as Record<string, unknown>) : undefined;
|
|
123
|
+
const detailRecord = asRecord(display.result.details);
|
|
130
124
|
const argsRecord = display.args;
|
|
131
125
|
const title =
|
|
132
126
|
(typeof detailRecord?.title === "string" && detailRecord.title.trim()) ||
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type CursorLiveRunAccountingState,
|
|
8
8
|
type CursorLiveToolResultConsumption,
|
|
9
9
|
} from "./cursor-live-run-accounting.js";
|
|
10
|
-
import type { CursorNativeToolDisplayItem } from "./cursor-native-tool-display.js";
|
|
10
|
+
import type { CursorNativeToolDisplayItem } from "./cursor-native-tool-display-state.js";
|
|
11
11
|
import type { CursorPiBridgeToolRequest, CursorPiToolBridgeRun } from "./cursor-pi-tool-bridge.js";
|
|
12
12
|
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
13
13
|
import type { CursorSdkEventDebugRecorder } from "./cursor-sdk-event-debug.js";
|
|
@@ -151,8 +151,6 @@ export function restoreCursorMcpToolTimeoutOverride(): void {
|
|
|
151
151
|
installedConnectTimeoutMs = DEFAULT_CURSOR_MCP_CONNECT_TIMEOUT_MS;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export const restoreCursorMcpToolTimeoutOverrideForTests = restoreCursorMcpToolTimeoutOverride;
|
|
155
|
-
|
|
156
154
|
export const cursorMcpToolTimeoutOverrideDefaults = {
|
|
157
155
|
cursorSdkDefaultTimeoutMs: CURSOR_SDK_MCP_DEFAULT_TIMEOUT_MS,
|
|
158
156
|
defaultOverrideTimeoutMs: DEFAULT_CURSOR_MCP_TOOL_TIMEOUT_MS,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BeforeAgentStartEvent,
|
|
3
|
+
BeforeAgentStartEventResult,
|
|
4
|
+
ExtensionContext,
|
|
5
|
+
ExtensionHandler,
|
|
6
|
+
SessionStartEvent,
|
|
7
|
+
TurnStartEvent,
|
|
8
|
+
} from "@earendil-works/pi-coding-agent";
|
|
9
|
+
|
|
10
|
+
export type CursorModelLifecycleContext = ExtensionContext;
|
|
11
|
+
|
|
12
|
+
type CursorModelSelectEvent = { model: ExtensionContext["model"] };
|
|
13
|
+
|
|
14
|
+
type CursorModelLifecycleSyncHandler = (ctx: CursorModelLifecycleContext) => Promise<void> | void;
|
|
15
|
+
type CursorModelSessionStartHandler = ExtensionHandler<SessionStartEvent>;
|
|
16
|
+
type CursorModelSelectHandler = (event: CursorModelSelectEvent, ctx: CursorModelLifecycleContext) => Promise<void> | void;
|
|
17
|
+
type CursorModelTurnStartHandler = ExtensionHandler<TurnStartEvent>;
|
|
18
|
+
type CursorModelBeforeAgentStartHandler = ExtensionHandler<BeforeAgentStartEvent, BeforeAgentStartEventResult>;
|
|
19
|
+
|
|
20
|
+
export interface CursorModelLifecycleExtensionApi {
|
|
21
|
+
on(event: "session_start", handler: ExtensionHandler<SessionStartEvent>): void;
|
|
22
|
+
on(event: "before_agent_start", handler: CursorModelBeforeAgentStartHandler): void;
|
|
23
|
+
on(event: "model_select", handler: (event: CursorModelSelectEvent, ctx: ExtensionContext) => Promise<void> | void): void;
|
|
24
|
+
on(event: "turn_start", handler: ExtensionHandler<TurnStartEvent>): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CursorModelLifecycleHandlers {
|
|
28
|
+
sessionStart?: CursorModelSessionStartHandler;
|
|
29
|
+
modelSelect?: CursorModelSelectHandler;
|
|
30
|
+
turnStart?: CursorModelTurnStartHandler;
|
|
31
|
+
sync?: CursorModelLifecycleSyncHandler;
|
|
32
|
+
beforeAgentStart?: CursorModelBeforeAgentStartHandler;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeLifecycleHandlers(
|
|
36
|
+
handlerOrHandlers: CursorModelLifecycleSyncHandler | CursorModelLifecycleHandlers,
|
|
37
|
+
): CursorModelLifecycleHandlers {
|
|
38
|
+
return typeof handlerOrHandlers === "function" ? { sync: handlerOrHandlers } : handlerOrHandlers;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function registerCursorModelLifecycle(
|
|
42
|
+
pi: CursorModelLifecycleExtensionApi,
|
|
43
|
+
handlerOrHandlers: CursorModelLifecycleSyncHandler | CursorModelLifecycleHandlers,
|
|
44
|
+
): void {
|
|
45
|
+
const handlers = normalizeLifecycleHandlers(handlerOrHandlers);
|
|
46
|
+
const sync = handlers.sync;
|
|
47
|
+
if (handlers.sessionStart || sync) {
|
|
48
|
+
pi.on("session_start", async (event, ctx) => {
|
|
49
|
+
await handlers.sessionStart?.(event, ctx);
|
|
50
|
+
await sync?.(ctx);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (handlers.modelSelect || sync) {
|
|
54
|
+
pi.on("model_select", async (event, ctx) => {
|
|
55
|
+
const effectiveCtx = { ...ctx, model: event.model };
|
|
56
|
+
await handlers.modelSelect?.(event, effectiveCtx);
|
|
57
|
+
await sync?.(effectiveCtx);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (handlers.turnStart || sync) {
|
|
61
|
+
pi.on("turn_start", async (event, ctx) => {
|
|
62
|
+
await handlers.turnStart?.(event, ctx);
|
|
63
|
+
await sync?.(ctx);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (handlers.beforeAgentStart || sync) {
|
|
67
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
68
|
+
await sync?.(ctx);
|
|
69
|
+
return await handlers.beforeAgentStart?.(event, ctx);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canRenderCursorToolNatively } from "./cursor-native-tool-display.js";
|
|
1
|
+
import { canRenderCursorToolNatively } from "./cursor-native-tool-display-state.js";
|
|
2
2
|
import { getActiveContextToolNames } from "./cursor-context-tools.js";
|
|
3
3
|
import type { Context } from "@earendil-works/pi-ai";
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CursorPiToolDisplay } from "./cursor-
|
|
1
|
+
import type { CursorPiToolDisplay } from "./cursor-transcript-utils.js";
|
|
2
2
|
import { asRecord } from "./cursor-record-utils.js";
|
|
3
3
|
import { truncateCursorDisplayLine } from "./cursor-display-text.js";
|
|
4
4
|
|