pi-cursor-sdk 0.1.20 → 0.1.21
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 +32 -0
- package/README.md +49 -9
- package/docs/cursor-dogfood-checklist.md +57 -0
- package/docs/cursor-live-smoke-checklist.md +115 -9
- package/docs/cursor-model-ux-spec.md +57 -17
- package/docs/cursor-native-tool-replay.md +15 -7
- package/docs/cursor-native-tool-visual-audit.md +104 -59
- package/docs/cursor-testing-lessons.md +8 -3
- package/docs/cursor-tool-surfaces.md +69 -0
- package/package.json +34 -10
- package/scripts/debug-provider-events.d.mts +59 -0
- package/scripts/debug-provider-events.mjs +70 -175
- package/scripts/debug-sdk-events.d.mts +90 -0
- package/scripts/debug-sdk-events.mjs +36 -98
- package/scripts/fixtures/plan-strip-shim/index.ts +12 -0
- package/scripts/isolated-cursor-smoke.sh +264 -102
- package/scripts/lib/cursor-child-process.d.mts +10 -0
- package/scripts/lib/cursor-child-process.mjs +50 -0
- package/scripts/lib/cursor-cli-args.d.mts +63 -0
- package/scripts/lib/cursor-cli-args.mjs +129 -0
- package/scripts/lib/cursor-script-fail.d.mts +1 -0
- package/scripts/lib/cursor-script-fail.mjs +13 -0
- package/scripts/lib/cursor-sdk-output-filter.d.mts +5 -0
- package/scripts/lib/cursor-smoke-env.d.mts +38 -0
- package/scripts/lib/cursor-smoke-env.mjs +81 -0
- package/scripts/lib/cursor-smoke-shell.sh +174 -0
- package/scripts/lib/cursor-visual-render.d.mts +15 -0
- package/scripts/lib/cursor-visual-render.mjs +131 -0
- package/scripts/probe-mcp-coldstart.mjs +20 -38
- package/scripts/refresh-cursor-model-snapshots.mjs +29 -65
- package/scripts/steering-rpc-smoke.mjs +170 -65
- package/scripts/tmux-live-smoke.sh +152 -98
- package/scripts/visual-tui-smoke.mjs +659 -0
- package/shared/cursor-sdk-event-debug-env.d.mts +12 -0
- package/shared/cursor-sdk-event-debug-env.mjs +13 -0
- package/shared/cursor-sensitive-text.d.mts +1 -0
- package/{scripts/lib/cursor-probe-utils.mjs → shared/cursor-sensitive-text.mjs} +1 -13
- package/shared/cursor-setting-sources.d.mts +5 -0
- package/shared/cursor-setting-sources.mjs +22 -0
- package/src/context.ts +21 -12
- package/src/cursor-bridge-contract.ts +1 -3
- package/src/cursor-incomplete-tool-visibility.ts +22 -5
- package/src/cursor-native-tool-display-registration.ts +63 -27
- package/src/cursor-native-tool-display-replay.ts +246 -144
- package/src/cursor-native-tool-display-state.ts +2 -0
- package/src/cursor-native-tool-display-tools.ts +149 -41
- package/src/cursor-provider-live-run-drain.ts +1 -52
- package/src/cursor-provider-run-finalizer.ts +235 -0
- package/src/cursor-provider-run-outcome.ts +149 -0
- package/src/cursor-provider-turn-api-key.ts +8 -0
- package/src/cursor-provider-turn-coordinator.ts +98 -446
- package/src/cursor-provider-turn-display-router.ts +216 -0
- package/src/cursor-provider-turn-emit.ts +59 -0
- package/src/cursor-provider-turn-finalize.ts +119 -0
- package/src/cursor-provider-turn-lifecycle-emitter.ts +97 -0
- package/src/cursor-provider-turn-message-offset.ts +15 -0
- package/src/cursor-provider-turn-prepare.ts +216 -0
- package/src/cursor-provider-turn-runner.ts +138 -0
- package/src/cursor-provider-turn-sdk-normalizer.ts +88 -0
- package/src/cursor-provider-turn-send.ts +103 -0
- package/src/cursor-provider-turn-shell-output.ts +107 -0
- package/src/cursor-provider-turn-tool-ledger.ts +126 -0
- package/src/cursor-provider-turn-types.ts +87 -0
- package/src/cursor-provider.ts +16 -504
- package/src/cursor-replay-activity-builders.ts +276 -0
- package/src/cursor-replay-source-names.ts +33 -0
- package/src/cursor-replay-summary-args.ts +191 -0
- package/src/cursor-replay-tool-details.ts +464 -0
- package/src/cursor-run-final-text.ts +56 -0
- package/src/cursor-sdk-abort-error-guard.ts +4 -0
- package/src/cursor-sdk-event-debug-constants.ts +14 -5
- package/src/cursor-sdk-event-debug.ts +2 -1
- package/src/cursor-sensitive-text.ts +3 -36
- package/src/cursor-session-agent.ts +3 -1
- package/src/cursor-setting-sources.ts +7 -10
- package/src/cursor-state.ts +232 -28
- package/src/cursor-tool-lifecycle.ts +9 -8
- package/src/cursor-tool-manifest.ts +41 -0
- package/src/cursor-tool-names.ts +18 -106
- package/src/cursor-tool-presentation-registry.ts +556 -0
- package/src/cursor-tool-transcript.ts +1 -1
- package/src/cursor-tool-visibility.ts +3 -27
- package/src/cursor-transcript-tool-formatters.ts +0 -59
- package/src/cursor-transcript-tool-specs.ts +158 -233
- package/src/cursor-transcript-utils.ts +0 -44
- package/src/cursor-web-tool-activity.ts +10 -60
- package/src/cursor-web-tool-args.ts +39 -0
- package/src/index.ts +4 -10
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { getField } from "./cursor-record-utils.js";
|
|
2
|
+
import { getToolName } from "./cursor-transcript-utils.js";
|
|
3
|
+
|
|
4
|
+
export type CursorToolDisplaySource = "started" | "fallback" | "transcript";
|
|
5
|
+
|
|
6
|
+
export interface ToolCompletionDedupeInput {
|
|
7
|
+
identity?: string;
|
|
8
|
+
source?: CursorToolDisplaySource;
|
|
9
|
+
fingerprint: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ToolCompletionDedupeReason =
|
|
13
|
+
| "identity-already-completed"
|
|
14
|
+
| "fallback-fingerprint-already-completed"
|
|
15
|
+
| "fingerprint-already-completed";
|
|
16
|
+
|
|
17
|
+
export class CursorToolCompletionLedger {
|
|
18
|
+
private readonly startedToolCalls = new Map<string, unknown>();
|
|
19
|
+
private readonly bridgeStartedToolCallIds = new Set<string>();
|
|
20
|
+
private readonly completedToolIdentities = new Set<string>();
|
|
21
|
+
private readonly completedStartedToolFingerprints = new Set<string>();
|
|
22
|
+
private readonly completedFallbackToolFingerprints = new Set<string>();
|
|
23
|
+
|
|
24
|
+
getStartedToolCall(callId: string): unknown | undefined {
|
|
25
|
+
return this.startedToolCalls.get(callId);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
hasStartedToolCall(callId: string): boolean {
|
|
29
|
+
return this.startedToolCalls.has(callId);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
registerStartedToolCall(callId: string, toolCall: unknown): void {
|
|
33
|
+
this.startedToolCalls.set(callId, toolCall);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
markBridgeStarted(callId: string): void {
|
|
37
|
+
this.bridgeStartedToolCallIds.add(callId);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
takeBridgeStartedCallId(callId: string): string | undefined {
|
|
41
|
+
if (!this.bridgeStartedToolCallIds.has(callId)) return undefined;
|
|
42
|
+
this.bridgeStartedToolCallIds.delete(callId);
|
|
43
|
+
return callId;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
clearStartedToolCall(callId: string): void {
|
|
47
|
+
this.startedToolCalls.delete(callId);
|
|
48
|
+
this.bridgeStartedToolCallIds.delete(callId);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
removeStartedToolCallForStep(toolCall: unknown, stepId: unknown): string | undefined {
|
|
52
|
+
if (typeof stepId === "string" && this.startedToolCalls.has(stepId)) {
|
|
53
|
+
this.clearStartedToolCall(stepId);
|
|
54
|
+
return stepId;
|
|
55
|
+
}
|
|
56
|
+
const fingerprint = getStartedToolCallFingerprint(toolCall);
|
|
57
|
+
for (const [callId, startedToolCall] of this.startedToolCalls) {
|
|
58
|
+
if (getStartedToolCallFingerprint(startedToolCall) !== fingerprint) continue;
|
|
59
|
+
this.clearStartedToolCall(callId);
|
|
60
|
+
return callId;
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
recordCompletedIdentity(identity: string): void {
|
|
66
|
+
this.completedToolIdentities.add(identity);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
shouldSkipDuplicateCompletion(input: ToolCompletionDedupeInput): ToolCompletionDedupeReason | undefined {
|
|
70
|
+
if (input.identity && this.completedToolIdentities.has(input.identity)) {
|
|
71
|
+
return "identity-already-completed";
|
|
72
|
+
}
|
|
73
|
+
if (input.source === "started") {
|
|
74
|
+
if (this.completedFallbackToolFingerprints.has(input.fingerprint)) {
|
|
75
|
+
return "fallback-fingerprint-already-completed";
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
if (
|
|
80
|
+
this.completedStartedToolFingerprints.has(input.fingerprint) ||
|
|
81
|
+
this.completedFallbackToolFingerprints.has(input.fingerprint)
|
|
82
|
+
) {
|
|
83
|
+
return "fingerprint-already-completed";
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
recordCompletedTool(input: ToolCompletionDedupeInput): void {
|
|
89
|
+
if (input.identity) this.completedToolIdentities.add(input.identity);
|
|
90
|
+
if (input.source === "started") {
|
|
91
|
+
this.completedStartedToolFingerprints.add(input.fingerprint);
|
|
92
|
+
} else {
|
|
93
|
+
this.completedFallbackToolFingerprints.add(input.fingerprint);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
clear(): void {
|
|
98
|
+
this.startedToolCalls.clear();
|
|
99
|
+
this.bridgeStartedToolCallIds.clear();
|
|
100
|
+
this.completedToolIdentities.clear();
|
|
101
|
+
this.completedStartedToolFingerprints.clear();
|
|
102
|
+
this.completedFallbackToolFingerprints.clear();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Exposed for incomplete-tool discard iteration. */
|
|
106
|
+
startedToolCallEntries(): IterableIterator<[string, unknown]> {
|
|
107
|
+
return this.startedToolCalls.entries();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
clearStartedToolCalls(): void {
|
|
111
|
+
this.startedToolCalls.clear();
|
|
112
|
+
this.bridgeStartedToolCallIds.clear();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function getToolFingerprint(value: unknown): string {
|
|
117
|
+
try {
|
|
118
|
+
return JSON.stringify(value);
|
|
119
|
+
} catch {
|
|
120
|
+
return String(value);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function getStartedToolCallFingerprint(toolCall: unknown): string {
|
|
125
|
+
return getToolFingerprint({ toolName: getToolName(toolCall), args: getField(toolCall, "args") });
|
|
126
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Api,
|
|
3
|
+
AssistantMessage,
|
|
4
|
+
AssistantMessageEventStream,
|
|
5
|
+
Context,
|
|
6
|
+
Model,
|
|
7
|
+
SimpleStreamOptions,
|
|
8
|
+
} from "@earendil-works/pi-ai";
|
|
9
|
+
import type { AgentModeOption, SDKAgent, SDKImage } from "@cursor/sdk";
|
|
10
|
+
import type { CursorLiveRun } from "./cursor-live-run-coordinator.js";
|
|
11
|
+
import type { SessionCursorAgentLease } from "./cursor-session-agent.js";
|
|
12
|
+
import type { planCursorSessionSend } from "./cursor-session-agent.js";
|
|
13
|
+
import type { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
|
|
14
|
+
import type { CursorSdkTurnCoordinator } from "./cursor-provider-turn-coordinator.js";
|
|
15
|
+
import type { CursorPrompt } from "./context.js";
|
|
16
|
+
|
|
17
|
+
export interface CursorProviderTurnRunnerParams {
|
|
18
|
+
model: Model<Api>;
|
|
19
|
+
context: Context;
|
|
20
|
+
stream: AssistantMessageEventStream;
|
|
21
|
+
partial: AssistantMessage;
|
|
22
|
+
options?: SimpleStreamOptions;
|
|
23
|
+
sdkEventDebugRef: { current?: CursorSdkEventDebugSink };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface CursorProviderTurnSendPayload {
|
|
27
|
+
text: string;
|
|
28
|
+
images?: SDKImage[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface CursorProviderTurnSendMeta {
|
|
32
|
+
sendPlan: ReturnType<typeof planCursorSessionSend>;
|
|
33
|
+
prompt: CursorPrompt;
|
|
34
|
+
bootstrap: boolean;
|
|
35
|
+
promptInputTokens: number;
|
|
36
|
+
useNativeToolReplay: boolean;
|
|
37
|
+
bridgeEnabled: boolean;
|
|
38
|
+
nativeReplayId: string;
|
|
39
|
+
agentMode: AgentModeOption;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface CursorProviderTurnRuntimeBase {
|
|
43
|
+
turnCoordinator: CursorSdkTurnCoordinator;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface DirectCursorProviderTurnRuntime extends CursorProviderTurnRuntimeBase {
|
|
47
|
+
kind: "direct";
|
|
48
|
+
liveRun?: undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface LiveCursorProviderTurnRuntime extends CursorProviderTurnRuntimeBase {
|
|
52
|
+
kind: "live";
|
|
53
|
+
liveRun: CursorLiveRun;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type CursorProviderTurnRuntime = DirectCursorProviderTurnRuntime | LiveCursorProviderTurnRuntime;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Single owned model for a prepared provider turn.
|
|
60
|
+
*
|
|
61
|
+
* Send, finalize, and cleanup phases receive this immutable object instead of
|
|
62
|
+
* keeping parallel liveRun/turnCoordinator/resource bags in sync by convention.
|
|
63
|
+
*/
|
|
64
|
+
export interface PreparedCursorProviderTurn {
|
|
65
|
+
agent: SDKAgent;
|
|
66
|
+
cwd: string;
|
|
67
|
+
payload: CursorProviderTurnSendPayload;
|
|
68
|
+
meta: CursorProviderTurnSendMeta;
|
|
69
|
+
contextWindowAgentId: string;
|
|
70
|
+
textDeltas: string[];
|
|
71
|
+
sessionAgentScopeKey: string;
|
|
72
|
+
sessionAgentLease: SessionCursorAgentLease;
|
|
73
|
+
restoreCursorSdkOutputFilter: () => void;
|
|
74
|
+
runtime: CursorProviderTurnRuntime;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type CursorProviderTurnPrepareResult = PreparedCursorProviderTurn;
|
|
78
|
+
|
|
79
|
+
export interface CursorProviderTurnSend {
|
|
80
|
+
run: Awaited<ReturnType<SDKAgent["send"]>>;
|
|
81
|
+
cursorAgentMessageOffset: number | undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface CursorProviderTurnSendResult {
|
|
85
|
+
send: CursorProviderTurnSend;
|
|
86
|
+
abortRegistration: { signal: AbortSignal; listener: () => void } | undefined;
|
|
87
|
+
}
|