pi-cursor-sdk 0.2.0 → 0.3.6
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 +62 -0
- package/README.md +54 -50
- package/dist/bundled-context-windows.js +39 -0
- package/dist/context-window-cache.js +92 -0
- package/dist/context.js +338 -0
- package/dist/cursor-active-tools.js +3 -0
- package/dist/cursor-agent-message-web-tools.js +165 -0
- package/dist/cursor-agents-context-registration.js +17 -0
- package/dist/cursor-agents-context.js +113 -0
- package/dist/cursor-api-key.js +34 -0
- package/dist/cursor-bridge-contract.js +27 -0
- package/dist/cursor-cloud-lifecycle.js +650 -0
- package/dist/cursor-cloud-local-state.js +460 -0
- package/dist/cursor-cloud-options.js +145 -0
- package/dist/cursor-cloud-reporting.js +222 -0
- package/dist/cursor-compact-tool-summary.js +75 -0
- package/dist/cursor-config.js +613 -0
- package/dist/cursor-context-tools.js +4 -0
- package/dist/cursor-display-only-trace.js +11 -0
- package/dist/cursor-display-text.js +18 -0
- package/dist/cursor-durable-fs.js +53 -0
- package/dist/cursor-edit-diff.js +13 -0
- package/dist/cursor-env-boolean.js +19 -0
- package/dist/cursor-fallback-models.generated.js +7760 -0
- package/dist/cursor-fallback-warning.js +15 -0
- package/dist/cursor-http1.js +45 -0
- package/dist/cursor-incomplete-tool-visibility.js +83 -0
- package/dist/cursor-live-run-accounting.js +55 -0
- package/dist/cursor-live-run-coordinator.js +406 -0
- package/dist/cursor-mcp-timeout-override.js +116 -0
- package/dist/cursor-model-lifecycle.js +32 -0
- package/dist/cursor-model.js +5 -0
- package/dist/cursor-native-replay-routing.js +35 -0
- package/dist/cursor-native-replay-trace.js +28 -0
- package/dist/cursor-native-tool-display-registration.js +102 -0
- package/dist/cursor-native-tool-display-replay.js +428 -0
- package/dist/cursor-native-tool-display-state.js +70 -0
- package/dist/cursor-native-tool-display-tools.js +123 -0
- package/dist/cursor-native-tool-names.js +11 -0
- package/dist/cursor-partial-content-emitter.js +118 -0
- package/dist/cursor-pi-tool-bridge-abort.js +114 -0
- package/dist/cursor-pi-tool-bridge-constants.js +6 -0
- package/dist/cursor-pi-tool-bridge-diagnostics.js +125 -0
- package/dist/cursor-pi-tool-bridge-env.js +18 -0
- package/dist/cursor-pi-tool-bridge-mcp.js +100 -0
- package/dist/cursor-pi-tool-bridge-run.js +355 -0
- package/dist/cursor-pi-tool-bridge-server.js +163 -0
- package/dist/cursor-pi-tool-bridge-snapshot.js +63 -0
- package/dist/cursor-pi-tool-bridge-types.js +1 -0
- package/dist/cursor-pi-tool-bridge.js +123 -0
- package/dist/cursor-provider-errors.js +311 -0
- package/dist/cursor-provider-lazy.js +39 -0
- package/dist/cursor-provider-live-run-drain.js +412 -0
- package/dist/cursor-provider-overflow.js +90 -0
- package/dist/cursor-provider-run-finalizer.js +176 -0
- package/dist/cursor-provider-run-outcome.js +76 -0
- package/dist/cursor-provider-turn-coordinator.js +275 -0
- package/dist/cursor-provider-turn-display-router.js +158 -0
- package/dist/cursor-provider-turn-emit.js +35 -0
- package/dist/cursor-provider-turn-finalize.js +154 -0
- package/dist/cursor-provider-turn-lifecycle-emitter.js +126 -0
- package/dist/cursor-provider-turn-prepare.js +374 -0
- package/dist/cursor-provider-turn-runner.js +146 -0
- package/dist/cursor-provider-turn-sdk-normalizer.js +74 -0
- package/dist/cursor-provider-turn-send.js +138 -0
- package/dist/cursor-provider-turn-shell-output.js +117 -0
- package/dist/cursor-provider-turn-tool-ledger.js +99 -0
- package/dist/cursor-provider-turn-types.js +1 -0
- package/dist/cursor-provider.js +72 -0
- package/dist/cursor-question-tool.js +194 -0
- package/dist/cursor-record-utils.js +61 -0
- package/dist/cursor-replay-activity-builders.js +114 -0
- package/dist/cursor-replay-source-names.js +27 -0
- package/dist/cursor-replay-summary-args.js +105 -0
- package/dist/cursor-replay-tool-details.js +167 -0
- package/dist/cursor-ripgrep-path.js +27 -0
- package/dist/cursor-run-final-text.js +63 -0
- package/dist/cursor-runtime-state.js +380 -0
- package/dist/cursor-sdk-billed-usage.js +86 -0
- package/dist/cursor-sdk-event-debug-constants.js +33 -0
- package/dist/cursor-sdk-event-debug-session.js +107 -0
- package/dist/cursor-sdk-event-debug.js +461 -0
- package/dist/cursor-sdk-output-filter.js +1 -0
- package/dist/cursor-sdk-process-error-guard.js +221 -0
- package/dist/cursor-sdk-runtime.js +3 -0
- package/dist/cursor-sensitive-text.js +23 -0
- package/dist/cursor-session-agent-cleanup.js +311 -0
- package/dist/cursor-session-agent-lifecycle.js +32 -0
- package/dist/cursor-session-agent-lineage.js +103 -0
- package/dist/cursor-session-agent-resume.js +417 -0
- package/dist/cursor-session-agent.js +507 -0
- package/dist/cursor-session-compaction-prep.js +21 -0
- package/dist/cursor-session-scope.js +113 -0
- package/dist/cursor-session-send-policy.js +18 -0
- package/dist/cursor-session-store.js +105 -0
- package/dist/cursor-session-turn-queue.js +50 -0
- package/dist/cursor-setting-sources.js +15 -0
- package/dist/cursor-skill-tool.js +230 -0
- package/dist/cursor-state.js +519 -0
- package/dist/cursor-task-presentation.js +59 -0
- package/dist/cursor-tool-lifecycle.js +94 -0
- package/dist/cursor-tool-manifest.js +34 -0
- package/dist/cursor-tool-presentation-registry.js +305 -0
- package/dist/cursor-tool-result-display-readers.js +158 -0
- package/dist/cursor-tool-transcript.js +32 -0
- package/dist/cursor-tool-visibility.js +28 -0
- package/dist/cursor-transcript-tool-formatters.js +618 -0
- package/dist/cursor-transcript-tool-specs.js +284 -0
- package/dist/cursor-transcript-utils.js +170 -0
- package/dist/cursor-usage-accounting.js +166 -0
- package/dist/cursor-web-tool-activity.js +23 -0
- package/dist/cursor-web-tool-args.js +12 -0
- package/dist/index.js +82 -0
- package/dist/model-discovery.js +305 -0
- package/dist/model-list-cache.js +156 -0
- package/docs/cursor-dogfood-checklist.md +2 -1
- package/docs/cursor-live-smoke-checklist.md +13 -12
- package/docs/cursor-model-ux-spec.md +25 -6
- package/docs/cursor-native-tool-replay.md +13 -13
- package/docs/cursor-native-tool-visual-audit.md +6 -3
- package/docs/cursor-testing-lessons.md +7 -7
- package/docs/cursor-tool-surfaces.md +5 -5
- package/docs/platform-smoke.md +3 -3
- package/package.json +19 -7
- package/platform-smoke.config.mjs +1 -1
- package/scripts/build.mjs +126 -0
- package/scripts/cloud-runtime-smoke.mjs +3 -1
- package/scripts/debug-provider-events.mjs +3 -1
- package/scripts/debug-sdk-events.mjs +1 -1
- package/scripts/isolated-cursor-smoke.sh +5 -4
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +1 -1
- package/scripts/lib/cursor-visual-render.mjs +1 -1
- package/scripts/lib/ensure-built.mjs +16 -0
- package/scripts/lib/local-resume-smoke-harness.mjs +1 -1
- package/scripts/local-resume-smoke.mjs +3 -1
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/scripts/platform-smoke/live-suite-runner.mjs +1 -1
- package/scripts/platform-smoke/render-ansi.mjs +1 -1
- package/scripts/platform-smoke/targets.mjs +2 -2
- package/scripts/prepare.mjs +102 -0
- package/scripts/steering-rpc-smoke.mjs +4 -2
- package/scripts/tmux-live-smoke.sh +11 -11
- package/scripts/visual-tui-smoke-self-test.mjs +4 -1
- package/scripts/visual-tui-smoke.mjs +51 -7
- package/src/bundled-context-windows.ts +4 -1
- package/src/cursor-agents-context-registration.ts +2 -2
- package/src/cursor-agents-context.ts +0 -2
- package/src/cursor-api-key.ts +5 -4
- package/src/cursor-cloud-reporting.ts +23 -2
- package/src/cursor-fallback-models.generated.ts +592 -204
- package/src/cursor-live-run-coordinator.ts +1 -0
- package/src/cursor-native-tool-display-registration.ts +10 -11
- package/src/cursor-provider-errors.ts +1 -1
- package/src/cursor-provider-lazy.ts +5 -4
- package/src/cursor-provider-live-run-drain.ts +1 -0
- package/src/cursor-provider-run-finalizer.ts +1 -0
- package/src/cursor-provider-turn-finalize.ts +12 -0
- package/src/cursor-provider-turn-types.ts +2 -0
- package/src/cursor-sdk-billed-usage.ts +107 -0
- package/src/cursor-sdk-process-error-guard.ts +6 -4
- package/src/cursor-session-agent-lifecycle.ts +8 -9
- package/src/cursor-session-agent-resume.ts +23 -0
- package/src/cursor-session-compaction-prep.ts +4 -0
- package/src/cursor-tool-manifest.ts +1 -1
- package/src/cursor-usage-accounting.ts +70 -9
- package/src/index.ts +1 -1
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +16 -0
|
@@ -43,6 +43,7 @@ export interface CursorLiveRun {
|
|
|
43
43
|
sdkRun?: CursorLiveSdkRun;
|
|
44
44
|
ignoreFutureSdkTurnUsage?: boolean;
|
|
45
45
|
accounting: CursorLiveRunAccountingState;
|
|
46
|
+
billedTurnUsage?: CursorSdkTurnUsage;
|
|
46
47
|
pendingEvents: CursorLiveQueuedEvent[];
|
|
47
48
|
textDeltas: string[];
|
|
48
49
|
emittedText: string;
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
skippedNativeToolNames,
|
|
19
19
|
} from "./cursor-native-tool-display-state.js";
|
|
20
20
|
import { isCursorReplayToolName } from "./cursor-tool-presentation-registry.js";
|
|
21
|
+
import { registerNativeCursorTool } from "./cursor-native-tool-display-tools.js";
|
|
21
22
|
|
|
22
23
|
export const CURSOR_CORE_PI_REPLAY_TOOL_NAMES = ["read", "bash", "edit", "write"] as const;
|
|
23
24
|
const CORE_PI_TOOL_NAMES = new Set<string>(CURSOR_CORE_PI_REPLAY_TOOL_NAMES);
|
|
@@ -40,12 +41,11 @@ type NativeRegistrationContext = Pick<ExtensionContext, "mode" | "model"> & {
|
|
|
40
41
|
ui: Pick<ExtensionContext["ui"], "notify">;
|
|
41
42
|
};
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
function registerNativeCursorToolsFromSet(
|
|
44
45
|
pi: CursorNativeToolRegistryApi,
|
|
45
46
|
toolNames: readonly NativeCursorToolName[],
|
|
46
|
-
):
|
|
47
|
+
): NativeCursorToolName[] {
|
|
47
48
|
const newlySkippedToolNames: NativeCursorToolName[] = [];
|
|
48
|
-
let registerNativeCursorTool: ((pi: CursorNativeToolRegistryApi, toolName: NativeCursorToolName) => void) | undefined;
|
|
49
49
|
for (const toolName of toolNames) {
|
|
50
50
|
if (registeredNativeToolNames.has(toolName) || skippedNativeToolNames.has(toolName)) continue;
|
|
51
51
|
if (hasNonBuiltinTool(pi, toolName)) {
|
|
@@ -53,7 +53,6 @@ async function registerNativeCursorToolsFromSet(
|
|
|
53
53
|
newlySkippedToolNames.push(toolName);
|
|
54
54
|
continue;
|
|
55
55
|
}
|
|
56
|
-
registerNativeCursorTool ??= (await import("./cursor-native-tool-display-tools.js")).registerNativeCursorTool;
|
|
57
56
|
registerNativeCursorTool(pi, toolName);
|
|
58
57
|
registeredNativeToolNames.add(toolName);
|
|
59
58
|
}
|
|
@@ -105,31 +104,31 @@ export function syncRegisteredNativeCursorToolsForModel(
|
|
|
105
104
|
if (changed) pi.setActiveTools([...activeToolNames]);
|
|
106
105
|
}
|
|
107
106
|
|
|
108
|
-
|
|
107
|
+
function ensureNativeCursorToolsRegisteredForModel(pi: CursorNativeToolRegistryApi, ctx: NativeRegistrationContext): void {
|
|
109
108
|
if (!isCursorModel(ctx.model) || hasAttemptedNativeCursorToolRegistration()) return;
|
|
110
109
|
|
|
111
110
|
const nonCoreToolNames = NATIVE_CURSOR_TOOL_NAMES.filter((toolName) => !isCursorCorePiReplayToolName(toolName));
|
|
112
111
|
const skippedToolNames = [
|
|
113
|
-
...
|
|
114
|
-
...
|
|
112
|
+
...registerNativeCursorToolsFromSet(pi, nonCoreToolNames),
|
|
113
|
+
...registerNativeCursorToolsFromSet(pi, CURSOR_CORE_PI_REPLAY_TOOL_NAMES),
|
|
115
114
|
];
|
|
116
115
|
notifySkippedNativeCursorToolsIfNeeded(ctx, skippedToolNames);
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
|
|
118
|
+
function ensureThenSyncNativeCursorToolsForModel(pi: CursorNativeToolRegistryApi, ctx: NativeRegistrationContext): void {
|
|
120
119
|
const requested = isCursorNativeToolRegistrationRequested(ctx.mode);
|
|
121
120
|
setCursorNativeToolDisplayRuntimeRequested(requested);
|
|
122
121
|
if (!requested) {
|
|
123
122
|
removeRegisteredNonCoreNativeCursorTools(pi);
|
|
124
123
|
return;
|
|
125
124
|
}
|
|
126
|
-
|
|
125
|
+
ensureNativeCursorToolsRegisteredForModel(pi, ctx);
|
|
127
126
|
syncRegisteredNativeCursorToolsForModel(pi, ctx.model);
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
export function registerCursorNativeToolDisplay(pi: CursorNativeToolDisplayExtensionApi): void {
|
|
131
|
-
registerCursorModelLifecycle(pi,
|
|
132
|
-
|
|
130
|
+
registerCursorModelLifecycle(pi, (ctx) => {
|
|
131
|
+
ensureThenSyncNativeCursorToolsForModel(pi, ctx);
|
|
133
132
|
});
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -166,7 +166,7 @@ function isCursorSdkStallAbortNetworkError(code: unknown, evidence: string, stac
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
|
-
* @cursor/sdk@1.0.
|
|
169
|
+
* @cursor/sdk@1.0.27 throws internal RetriableError (name/kind "RetriableError") with message
|
|
170
170
|
* "Connection stalled" or "Connection stalled repeatedly" after fetchWithRetry exhausts stalls.
|
|
171
171
|
* The ConnectError is only the cause; the top-level error is not a ConnectError.
|
|
172
172
|
*/
|
|
@@ -7,8 +7,10 @@ import {
|
|
|
7
7
|
type Model,
|
|
8
8
|
type SimpleStreamOptions,
|
|
9
9
|
} from "@earendil-works/pi-ai";
|
|
10
|
+
import { streamCursor } from "./cursor-provider.js";
|
|
11
|
+
import { sanitizeCursorProviderError } from "./cursor-provider-errors.js";
|
|
10
12
|
|
|
11
|
-
function
|
|
13
|
+
function makeProviderRuntimeErrorMessage(model: Model<Api>, error: unknown, apiKey?: string): AssistantMessage {
|
|
12
14
|
return {
|
|
13
15
|
role: "assistant",
|
|
14
16
|
content: [],
|
|
@@ -25,7 +27,7 @@ function makeProviderLoadErrorMessage(model: Model<Api>, error: unknown): Assist
|
|
|
25
27
|
},
|
|
26
28
|
stopReason: "error",
|
|
27
29
|
timestamp: Date.now(),
|
|
28
|
-
errorMessage: `
|
|
30
|
+
errorMessage: `Cursor provider runtime failed: ${sanitizeCursorProviderError(error, apiKey)}`,
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -37,12 +39,11 @@ export function streamCursorLazy(
|
|
|
37
39
|
const outer = createAssistantMessageEventStream();
|
|
38
40
|
queueMicrotask(async () => {
|
|
39
41
|
try {
|
|
40
|
-
const { streamCursor } = await import("./cursor-provider.js");
|
|
41
42
|
for await (const event of streamCursor(model, context, options)) {
|
|
42
43
|
outer.push(event);
|
|
43
44
|
}
|
|
44
45
|
} catch (error) {
|
|
45
|
-
const message =
|
|
46
|
+
const message = makeProviderRuntimeErrorMessage(model, error, options?.apiKey);
|
|
46
47
|
outer.push({ type: "error", reason: "error", error: message });
|
|
47
48
|
outer.end(message);
|
|
48
49
|
}
|
|
@@ -383,6 +383,7 @@ export async function drainCursorLiveRunTurn(
|
|
|
383
383
|
applyCursorUsage(partial, model, context, cursorLiveRuns.takeTurnInputTokens(run, toolResultInputTokens), {
|
|
384
384
|
runtime: "local",
|
|
385
385
|
turn: cursorLiveRuns.takeSdkTurnUsage(run),
|
|
386
|
+
billed: run.billedTurnUsage,
|
|
386
387
|
});
|
|
387
388
|
if (run.resumeNotice) {
|
|
388
389
|
emitDisplayOnlyTraceBlock(stream, partial, run.resumeNotice);
|
|
@@ -186,6 +186,7 @@ export class CursorRunFinalizer {
|
|
|
186
186
|
applyCursorUsage(partial, model, context, prepared.meta.promptInputTokens, {
|
|
187
187
|
runtime: prepared.runtimeTarget,
|
|
188
188
|
turn: prepared.runtime.turnCoordinator.lastSdkTurnUsage,
|
|
189
|
+
billed: prepared.runtime.billedTurnUsage,
|
|
189
190
|
});
|
|
190
191
|
if (prepared.meta.resumeNotice) emitDisplayOnlyTraceBlock(stream, partial, prepared.meta.resumeNotice);
|
|
191
192
|
if (displayOnlyTraceBlock) emitDisplayOnlyTraceBlock(stream, partial, displayOnlyTraceBlock);
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "./cursor-provider-run-outcome.js";
|
|
18
18
|
import type { CursorProviderTurnPrepareResult } from "./cursor-provider-turn-types.js";
|
|
19
19
|
import { loadCursorSdk } from "./cursor-sdk-runtime.js";
|
|
20
|
+
import { attachCursorSdkBilledTurnUsage } from "./cursor-sdk-billed-usage.js";
|
|
20
21
|
|
|
21
22
|
export async function cacheSdkContextWindow(
|
|
22
23
|
agentId: string,
|
|
@@ -149,6 +150,16 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
|
|
|
149
150
|
resolvedApiKey: params.resolvedApiKey,
|
|
150
151
|
optionsApiKey: params.optionsApiKey,
|
|
151
152
|
});
|
|
153
|
+
const billed = await attachCursorSdkBilledTurnUsage({
|
|
154
|
+
agent: params.prepared.agent,
|
|
155
|
+
agentId: params.run.agentId,
|
|
156
|
+
runtime: params.prepared.runtimeTarget,
|
|
157
|
+
runId: params.run.id,
|
|
158
|
+
});
|
|
159
|
+
params.prepared.runtime.billedTurnUsage = billed.turn;
|
|
160
|
+
if (params.prepared.runtime.liveRun) {
|
|
161
|
+
params.prepared.runtime.liveRun.billedTurnUsage = billed.turn;
|
|
162
|
+
}
|
|
152
163
|
let displayOnlyTraceBlock: string | undefined;
|
|
153
164
|
if (params.prepared.runtimeTarget === "cloud" && isCursorRunFinishedSuccessfully(outcome)) {
|
|
154
165
|
let report: CursorCloudRunReport = { agentId: params.run.agentId, runId: params.run.id, branches: [] };
|
|
@@ -158,6 +169,7 @@ export async function awaitFinalizeCursorRunOutcome(params: AwaitFinalizeCursorR
|
|
|
158
169
|
run: params.run,
|
|
159
170
|
waitResult,
|
|
160
171
|
apiKey,
|
|
172
|
+
agentUsage: billed.agentUsage,
|
|
161
173
|
});
|
|
162
174
|
} catch (error) {
|
|
163
175
|
recordCursorCloudReportingError(params.sdkEventDebug, error, apiKey);
|
|
@@ -14,6 +14,7 @@ import type { CursorSdkEventDebugSink } from "./cursor-sdk-event-debug.js";
|
|
|
14
14
|
import type { CursorSdkTurnCoordinator } from "./cursor-provider-turn-coordinator.js";
|
|
15
15
|
import type { CursorPrompt } from "./context.js";
|
|
16
16
|
import type { CursorResolvedSetting } from "./cursor-config.js";
|
|
17
|
+
import type { CursorSdkTurnUsage } from "./cursor-usage-accounting.js";
|
|
17
18
|
|
|
18
19
|
export interface CursorProviderTurnRunnerParams {
|
|
19
20
|
model: Model<Api>;
|
|
@@ -44,6 +45,7 @@ export interface CursorProviderTurnSendMeta {
|
|
|
44
45
|
|
|
45
46
|
interface CursorProviderTurnRuntimeBase {
|
|
46
47
|
turnCoordinator: CursorSdkTurnCoordinator;
|
|
48
|
+
billedTurnUsage?: CursorSdkTurnUsage;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
/**
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { SDKAgent } from "@cursor/sdk";
|
|
2
|
+
import type { CursorRuntime } from "./cursor-config.js";
|
|
3
|
+
import { asRecord, getArray, getString } from "./cursor-record-utils.js";
|
|
4
|
+
import { readCursorSdkTurnUsage, type CursorSdkTurnUsage } from "./cursor-usage-accounting.js";
|
|
5
|
+
|
|
6
|
+
const BILLED_USAGE_TIMEOUT_MS = 5000;
|
|
7
|
+
|
|
8
|
+
// ponytail: process-lifetime watermark of billed usage UUIDs per agentId; reset on process exit.
|
|
9
|
+
// Upgrade to session-scoped storage if multi-day processes retain enough agent IDs to matter.
|
|
10
|
+
const seenBilledRunIdsByAgent = new Map<string, Set<string>>();
|
|
11
|
+
|
|
12
|
+
export function isCursorSdkClientMintedRunId(runId: string): boolean {
|
|
13
|
+
return runId.startsWith("run-");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function sumCursorSdkTurnUsage(usages: readonly CursorSdkTurnUsage[]): CursorSdkTurnUsage | undefined {
|
|
17
|
+
if (usages.length === 0) return undefined;
|
|
18
|
+
return usages.reduce(
|
|
19
|
+
(total, usage) => ({
|
|
20
|
+
inputTokens: total.inputTokens + usage.inputTokens,
|
|
21
|
+
outputTokens: total.outputTokens + usage.outputTokens,
|
|
22
|
+
cacheReadTokens: total.cacheReadTokens + usage.cacheReadTokens,
|
|
23
|
+
cacheWriteTokens: total.cacheWriteTokens + usage.cacheWriteTokens,
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function peekCursorBilledUsageRunIds(agentId: string): ReadonlySet<string> {
|
|
29
|
+
return seenBilledRunIdsByAgent.get(agentId) ?? new Set();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function rememberCursorBilledUsageRunIds(agentId: string, runIds: readonly string[]): void {
|
|
33
|
+
if (runIds.length === 0) return;
|
|
34
|
+
let seen = seenBilledRunIdsByAgent.get(agentId);
|
|
35
|
+
if (!seen) {
|
|
36
|
+
seen = new Set();
|
|
37
|
+
seenBilledRunIdsByAgent.set(agentId, seen);
|
|
38
|
+
}
|
|
39
|
+
for (const runId of runIds) seen.add(runId);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function withTimeout<T>(promise: Promise<T>, timeoutMs = BILLED_USAGE_TIMEOUT_MS): Promise<T | undefined> {
|
|
43
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
44
|
+
const timeout = new Promise<undefined>((resolve) => {
|
|
45
|
+
timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
46
|
+
timer.unref?.();
|
|
47
|
+
});
|
|
48
|
+
return Promise.race([promise.catch(() => undefined), timeout]).finally(() => {
|
|
49
|
+
if (timer) clearTimeout(timer);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function selectCursorBilledTurnUsage(
|
|
54
|
+
agentUsage: unknown,
|
|
55
|
+
options: { runtime: CursorRuntime; runId?: string; seenRunIds?: ReadonlySet<string> },
|
|
56
|
+
): { turn?: CursorSdkTurnUsage; runIds: string[] } {
|
|
57
|
+
const runs = (getArray(asRecord(agentUsage), "runs") ?? []).flatMap((item) => {
|
|
58
|
+
const record = asRecord(item);
|
|
59
|
+
const runId = getString(record, "runId");
|
|
60
|
+
const usage = readCursorSdkTurnUsage(record?.usage);
|
|
61
|
+
return runId && usage ? [{ runId, usage }] : [];
|
|
62
|
+
});
|
|
63
|
+
if (options.runtime === "cloud" && options.runId) {
|
|
64
|
+
const match = runs.find((run) => run.runId === options.runId);
|
|
65
|
+
return match ? { turn: match.usage, runIds: [match.runId] } : { runIds: [] };
|
|
66
|
+
}
|
|
67
|
+
const unseen = runs.filter((run) => !options.seenRunIds?.has(run.runId));
|
|
68
|
+
return { turn: sumCursorSdkTurnUsage(unseen.map((run) => run.usage)), runIds: unseen.map((run) => run.runId) };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function fetchCursorSdkAgentUsage(
|
|
72
|
+
agent: SDKAgent,
|
|
73
|
+
options: { runtime: CursorRuntime; runId?: string },
|
|
74
|
+
): Promise<unknown | undefined> {
|
|
75
|
+
if (typeof agent.getUsage !== "function") return undefined;
|
|
76
|
+
const query =
|
|
77
|
+
options.runtime === "cloud" && options.runId && isCursorSdkClientMintedRunId(options.runId)
|
|
78
|
+
? { runId: options.runId }
|
|
79
|
+
: undefined;
|
|
80
|
+
return withTimeout(Promise.resolve(agent.getUsage(query)));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function attachCursorSdkBilledTurnUsage(options: {
|
|
84
|
+
agent: SDKAgent;
|
|
85
|
+
agentId: string;
|
|
86
|
+
runtime: CursorRuntime;
|
|
87
|
+
runId?: string;
|
|
88
|
+
}): Promise<{ agentUsage?: unknown; turn?: CursorSdkTurnUsage }> {
|
|
89
|
+
const agentUsage = await fetchCursorSdkAgentUsage(options.agent, {
|
|
90
|
+
runtime: options.runtime,
|
|
91
|
+
runId: options.runId,
|
|
92
|
+
});
|
|
93
|
+
if (!agentUsage) return {};
|
|
94
|
+
const selected = selectCursorBilledTurnUsage(agentUsage, {
|
|
95
|
+
runtime: options.runtime,
|
|
96
|
+
runId: options.runtime === "cloud" ? options.runId : undefined,
|
|
97
|
+
seenRunIds: peekCursorBilledUsageRunIds(options.agentId),
|
|
98
|
+
});
|
|
99
|
+
rememberCursorBilledUsageRunIds(options.agentId, selected.runIds);
|
|
100
|
+
return { agentUsage, turn: selected.turn };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const __testUtils = {
|
|
104
|
+
reset(): void {
|
|
105
|
+
seenBilledRunIdsByAgent.clear();
|
|
106
|
+
},
|
|
107
|
+
};
|
|
@@ -75,10 +75,12 @@ function isCursorSdkAbortError(error: unknown): boolean {
|
|
|
75
75
|
// The exact observed incident: the Cursor SDK 1.0.23 local shell executor writes a
|
|
76
76
|
// spawned child's stdin without a stream 'error' listener, so a child exiting while
|
|
77
77
|
// a write is in flight surfaces a raw `write EPIPE` uncaught exception whose stack
|
|
78
|
-
// is exactly the single async pipe-write completion frame.
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
78
|
+
// is exactly the single async pipe-write completion frame. Installed 1.0.27 attaches
|
|
79
|
+
// a no-op `error` listener before that write; keep this guard as defense in depth.
|
|
80
|
+
// Pi's own piped-stdout or dead-terminal EPIPE normally surfaces through the
|
|
81
|
+
// synchronous write-dispatch path with multiple frames (afterWriteDispatched /
|
|
82
|
+
// Socket._writeGeneric) and must stay fatal per Unix convention, so anything beyond
|
|
83
|
+
// this one-frame contract is rejected.
|
|
82
84
|
const OBSERVED_CLOSED_PIPE_STACK_FRAME =
|
|
83
85
|
/^\s+at WriteWrap\.onWriteComplete \[as oncomplete\] \(node:internal\/stream_base_commons:\d+:\d+\)$/;
|
|
84
86
|
|
|
@@ -7,6 +7,11 @@ import type {
|
|
|
7
7
|
} from "@earendil-works/pi-coding-agent";
|
|
8
8
|
import { clearCursorSdkHttp1 } from "./cursor-http1.js";
|
|
9
9
|
import { onCursorSessionScopeKeyChange } from "./cursor-session-scope.js";
|
|
10
|
+
import {
|
|
11
|
+
disposeSessionCursorAgent,
|
|
12
|
+
invalidateSessionAgent,
|
|
13
|
+
resetSessionCursorAgent,
|
|
14
|
+
} from "./cursor-session-agent.js";
|
|
10
15
|
|
|
11
16
|
export interface CursorSessionAgentLifecycleExtensionApi {
|
|
12
17
|
on(event: "session_shutdown", handler: ExtensionHandler<SessionShutdownEvent>): void;
|
|
@@ -18,11 +23,9 @@ export interface CursorSessionAgentLifecycleExtensionApi {
|
|
|
18
23
|
|
|
19
24
|
export function registerCursorSessionAgentLifecycle(pi: CursorSessionAgentLifecycleExtensionApi): void {
|
|
20
25
|
onCursorSessionScopeKeyChange(async (previousScopeKey) => {
|
|
21
|
-
const { disposeSessionCursorAgent } = await import("./cursor-session-agent.js");
|
|
22
26
|
await disposeSessionCursorAgent(previousScopeKey);
|
|
23
27
|
});
|
|
24
28
|
pi.on("session_shutdown", async (event) => {
|
|
25
|
-
const { disposeSessionCursorAgent, resetSessionCursorAgent } = await import("./cursor-session-agent.js");
|
|
26
29
|
try {
|
|
27
30
|
if (event.reason === "reload") {
|
|
28
31
|
await resetSessionCursorAgent();
|
|
@@ -33,20 +36,16 @@ export function registerCursorSessionAgentLifecycle(pi: CursorSessionAgentLifecy
|
|
|
33
36
|
clearCursorSdkHttp1();
|
|
34
37
|
}
|
|
35
38
|
});
|
|
36
|
-
pi.on("session_compact",
|
|
37
|
-
const { invalidateSessionAgent } = await import("./cursor-session-agent.js");
|
|
39
|
+
pi.on("session_compact", () => {
|
|
38
40
|
invalidateSessionAgent();
|
|
39
41
|
});
|
|
40
|
-
pi.on("session_before_tree",
|
|
41
|
-
const { invalidateSessionAgent } = await import("./cursor-session-agent.js");
|
|
42
|
+
pi.on("session_before_tree", () => {
|
|
42
43
|
invalidateSessionAgent();
|
|
43
44
|
});
|
|
44
45
|
pi.on("session_tree", async () => {
|
|
45
|
-
const { resetSessionCursorAgent } = await import("./cursor-session-agent.js");
|
|
46
46
|
await resetSessionCursorAgent();
|
|
47
47
|
});
|
|
48
|
-
pi.on("model_select",
|
|
49
|
-
const { invalidateSessionAgent } = await import("./cursor-session-agent.js");
|
|
48
|
+
pi.on("model_select", () => {
|
|
50
49
|
invalidateSessionAgent();
|
|
51
50
|
});
|
|
52
51
|
}
|
|
@@ -81,6 +81,19 @@ const state: CursorSessionResumeState = {
|
|
|
81
81
|
unownedUserEntryIds: new Set(),
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
// Compaction summarizer sends commit a one-message resume handle. Drop it so the
|
|
85
|
+
// next normal turn_end cannot persist that lineage (#223).
|
|
86
|
+
let resumeHandlePersistSuppressed = false;
|
|
87
|
+
|
|
88
|
+
export function suppressCursorSessionAgentResumeHandlePersist(): void {
|
|
89
|
+
resumeHandlePersistSuppressed = true;
|
|
90
|
+
state.pendingHandle = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function allowCursorSessionAgentResumeHandlePersist(): void {
|
|
94
|
+
resumeHandlePersistSuppressed = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
84
97
|
function hashParts(parts: readonly string[]): string {
|
|
85
98
|
const hash = createHash("sha256");
|
|
86
99
|
for (const part of parts) {
|
|
@@ -360,6 +373,7 @@ export function getMatchingCursorSessionAgentResumeHandle(poolKey: string): Curs
|
|
|
360
373
|
}
|
|
361
374
|
|
|
362
375
|
export function persistCursorSessionAgentResumeHandle(input: PendingCursorSessionAgentResumeHandle): void {
|
|
376
|
+
if (resumeHandlePersistSuppressed) return;
|
|
363
377
|
if (!isCursorLocalAgentId(input.agentId)) return;
|
|
364
378
|
state.pendingHandle = {
|
|
365
379
|
runtime: input.runtime,
|
|
@@ -371,6 +385,11 @@ export function persistCursorSessionAgentResumeHandle(input: PendingCursorSessio
|
|
|
371
385
|
}
|
|
372
386
|
|
|
373
387
|
function flushPendingCursorSessionAgentResumeHandle(branch: readonly SessionEntry[]): void {
|
|
388
|
+
if (resumeHandlePersistSuppressed) {
|
|
389
|
+
state.pendingHandle = undefined;
|
|
390
|
+
restoreFromBranch(branch);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
374
393
|
restoreFromBranch(branch);
|
|
375
394
|
const pending = state.pendingHandle;
|
|
376
395
|
state.pendingHandle = undefined;
|
|
@@ -442,6 +461,8 @@ export function registerCursorSessionAgentResume(pi: CursorSessionAgentResumeExt
|
|
|
442
461
|
restoreFromSessionManager(ctx.sessionManager);
|
|
443
462
|
});
|
|
444
463
|
pi.on("session_compact", (event, ctx) => {
|
|
464
|
+
state.pendingHandle = undefined;
|
|
465
|
+
resumeHandlePersistSuppressed = false;
|
|
445
466
|
const branch = ctx.sessionManager.getBranch();
|
|
446
467
|
if (branch.length > 0) {
|
|
447
468
|
restoreFromSessionManager(ctx.sessionManager);
|
|
@@ -471,6 +492,7 @@ function resetStateForTests(): void {
|
|
|
471
492
|
state.lastBranchHandle = undefined;
|
|
472
493
|
state.pendingHandle = undefined;
|
|
473
494
|
state.unownedUserEntryIds = new Set();
|
|
495
|
+
resumeHandlePersistSuppressed = false;
|
|
474
496
|
}
|
|
475
497
|
|
|
476
498
|
export const __testUtils = {
|
|
@@ -479,4 +501,5 @@ export const __testUtils = {
|
|
|
479
501
|
reset: resetStateForTests,
|
|
480
502
|
set: setStateForTests,
|
|
481
503
|
state,
|
|
504
|
+
isResumeHandlePersistSuppressed: () => resumeHandlePersistSuppressed,
|
|
482
505
|
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { cursorLiveRuns } from "./cursor-provider-live-run-drain.js";
|
|
2
2
|
import { resetSessionCursorAgent } from "./cursor-session-agent.js";
|
|
3
|
+
import { suppressCursorSessionAgentResumeHandlePersist } from "./cursor-session-agent-resume.js";
|
|
3
4
|
import { getCursorSessionScopeKey } from "./cursor-session-scope.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Prepare the pooled Cursor session agent for pi compaction summarization.
|
|
7
8
|
* Releases any scoped live-run drain state still tied to the pooled agent, then
|
|
8
9
|
* disposes the pool entry so summarization acquires a clean SDK agent.
|
|
10
|
+
* Suppresses local-resume handle persist so the summarizer send cannot leak
|
|
11
|
+
* a one-message handle into the next normal turn (#223).
|
|
9
12
|
*/
|
|
10
13
|
export async function prepareCursorSessionForCompaction(
|
|
11
14
|
scopeKey: string = getCursorSessionScopeKey(),
|
|
12
15
|
): Promise<void> {
|
|
16
|
+
suppressCursorSessionAgentResumeHandlePersist();
|
|
13
17
|
while (true) {
|
|
14
18
|
const run = cursorLiveRuns.getActiveForScope(scopeKey);
|
|
15
19
|
if (!run || run.disposed) break;
|
|
@@ -4,7 +4,7 @@ import type { CursorPiToolBridgeSnapshot } from "./cursor-pi-tool-bridge-types.j
|
|
|
4
4
|
export const CURSOR_TOOL_MANIFEST_ENV = "PI_CURSOR_TOOL_MANIFEST";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Representative @cursor/sdk@1.0.
|
|
7
|
+
* Representative @cursor/sdk@1.0.27 local-agent ToolType values; actual exposure can vary by run.
|
|
8
8
|
* See docs/cursor-native-tool-replay.md#sdk-tooltype-replay-matrix.
|
|
9
9
|
*/
|
|
10
10
|
export const CURSOR_HOST_TOOL_MANIFEST_SUMMARY =
|
|
@@ -91,18 +91,30 @@ function getCursorSdkUncachedInputTokens(turnUsage: CursorSdkTurnUsage): number
|
|
|
91
91
|
return turnUsage.inputTokens - turnUsage.cacheReadTokens - turnUsage.cacheWriteTokens;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function
|
|
94
|
+
export function isCursorSdkUsagePartitionSafe(turnUsage: CursorSdkTurnUsage, model: Model<Api>): boolean {
|
|
95
95
|
const counts = [turnUsage.inputTokens, turnUsage.outputTokens, turnUsage.cacheReadTokens, turnUsage.cacheWriteTokens];
|
|
96
96
|
const uncachedInput = getCursorSdkUncachedInputTokens(turnUsage);
|
|
97
97
|
return (
|
|
98
98
|
counts.every((count) => Number.isFinite(count) && count >= 0) &&
|
|
99
99
|
Number.isFinite(uncachedInput) &&
|
|
100
100
|
uncachedInput >= 0 &&
|
|
101
|
-
turnUsage.outputTokens <= model.maxTokens
|
|
101
|
+
turnUsage.outputTokens <= model.maxTokens
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function isCursorSdkUsageSafeForPiMessage(turnUsage: CursorSdkTurnUsage, model: Model<Api>): boolean {
|
|
106
|
+
return (
|
|
107
|
+
isCursorSdkUsagePartitionSafe(turnUsage, model) &&
|
|
102
108
|
turnUsage.inputTokens + turnUsage.outputTokens <= model.contextWindow
|
|
103
109
|
);
|
|
104
110
|
}
|
|
105
111
|
|
|
112
|
+
export interface CursorSdkUsageApplyOptions {
|
|
113
|
+
runtime: CursorRuntime;
|
|
114
|
+
turn?: CursorSdkTurnUsage;
|
|
115
|
+
billed?: CursorSdkTurnUsage;
|
|
116
|
+
}
|
|
117
|
+
|
|
106
118
|
export function applyCursorSdkUsage(partial: AssistantMessage, turnUsage: CursorSdkTurnUsage): void {
|
|
107
119
|
// Pi treats input/cacheRead/cacheWrite as disjoint additive prompt components.
|
|
108
120
|
partial.usage.input = getCursorSdkUncachedInputTokens(turnUsage);
|
|
@@ -117,8 +129,23 @@ function isCompatibleCursorAssistantMeasurement(assistant: AssistantMessage, mod
|
|
|
117
129
|
return assistant.api === model.api && assistant.provider === model.provider && assistant.model === model.id;
|
|
118
130
|
}
|
|
119
131
|
|
|
132
|
+
function getLatestCompactionBoundary(context: Context): { index: number; tokensBefore?: number } | undefined {
|
|
133
|
+
for (let index = context.messages.length - 1; index >= 0; index -= 1) {
|
|
134
|
+
const message = context.messages[index] as { role?: string; tokensBefore?: number };
|
|
135
|
+
if (message.role !== "compactionSummary") continue;
|
|
136
|
+
const tokensBefore = message.tokensBefore;
|
|
137
|
+
return {
|
|
138
|
+
index,
|
|
139
|
+
tokensBefore: Number.isFinite(tokensBefore) && tokensBefore !== undefined && tokensBefore > 0 ? Math.floor(tokensBefore) : undefined,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
120
145
|
function getLastAcceptedContextOccupancy(context: Context, model: Model<Api>): number {
|
|
146
|
+
const boundary = getLatestCompactionBoundary(context);
|
|
121
147
|
for (let index = context.messages.length - 1; index >= 0; index -= 1) {
|
|
148
|
+
if (boundary && index < boundary.index) break;
|
|
122
149
|
const message = context.messages[index];
|
|
123
150
|
if (message.role !== "assistant" || !("usage" in message)) continue;
|
|
124
151
|
const assistant = message as AssistantMessage;
|
|
@@ -127,7 +154,9 @@ function getLastAcceptedContextOccupancy(context: Context, model: Model<Api>): n
|
|
|
127
154
|
const { usage } = assistant;
|
|
128
155
|
const total =
|
|
129
156
|
usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
130
|
-
if (Number.isFinite(total)
|
|
157
|
+
if (!Number.isFinite(total) || total <= 0 || total > model.contextWindow) continue;
|
|
158
|
+
if (boundary?.tokensBefore !== undefined && total >= boundary.tokensBefore) continue;
|
|
159
|
+
return total;
|
|
131
160
|
}
|
|
132
161
|
return 0;
|
|
133
162
|
}
|
|
@@ -146,18 +175,50 @@ export function applyCursorApproximateUsage(partial: AssistantMessage, model: Mo
|
|
|
146
175
|
);
|
|
147
176
|
}
|
|
148
177
|
|
|
178
|
+
function applyCursorOccupancyEstimate(partial: AssistantMessage, model: Model<Api>, context: Context): void {
|
|
179
|
+
partial.usage.totalTokens = Math.max(
|
|
180
|
+
estimateCursorContextTotalTokens(partial, model, context),
|
|
181
|
+
getLastAcceptedContextOccupancy(context, model),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function isCurrentLocalOccupancy(turn: CursorSdkTurnUsage, model: Model<Api>, context: Context): boolean {
|
|
186
|
+
if (!isCursorSdkUsageSafeForPiMessage(turn, model)) return false;
|
|
187
|
+
const tokensBefore = getLatestCompactionBoundary(context)?.tokensBefore;
|
|
188
|
+
return tokensBefore === undefined || turn.inputTokens + turn.outputTokens < tokensBefore;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function applyResolvedCursorOccupancy(
|
|
192
|
+
partial: AssistantMessage,
|
|
193
|
+
model: Model<Api>,
|
|
194
|
+
context: Context,
|
|
195
|
+
localTurn: CursorSdkTurnUsage | undefined,
|
|
196
|
+
): void {
|
|
197
|
+
if (localTurn && isCurrentLocalOccupancy(localTurn, model, context)) {
|
|
198
|
+
partial.usage.totalTokens = localTurn.inputTokens + localTurn.outputTokens;
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
applyCursorOccupancyEstimate(partial, model, context);
|
|
202
|
+
}
|
|
203
|
+
|
|
149
204
|
export function applyCursorUsage(
|
|
150
205
|
partial: AssistantMessage,
|
|
151
206
|
model: Model<Api>,
|
|
152
207
|
context: Context,
|
|
153
208
|
sessionInputTokens: number,
|
|
154
|
-
sdkUsage?:
|
|
209
|
+
sdkUsage?: CursorSdkUsageApplyOptions,
|
|
155
210
|
): void {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
211
|
+
const billed = sdkUsage?.billed;
|
|
212
|
+
const localTurn = sdkUsage?.runtime === "local" ? sdkUsage.turn : undefined;
|
|
213
|
+
if (billed && isCursorSdkUsagePartitionSafe(billed, model)) {
|
|
214
|
+
applyCursorSdkUsage(partial, billed);
|
|
215
|
+
applyResolvedCursorOccupancy(partial, model, context, localTurn);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
// Only local raw turn-ended usage has a captured full-prompt/cache-partition occupancy contract.
|
|
219
|
+
if (localTurn && isCursorSdkUsageSafeForPiMessage(localTurn, model)) {
|
|
220
|
+
applyCursorSdkUsage(partial, localTurn);
|
|
221
|
+
applyResolvedCursorOccupancy(partial, model, context, localTurn);
|
|
161
222
|
return;
|
|
162
223
|
}
|
|
163
224
|
applyCursorApproximateUsage(partial, model, context, sessionInputTokens);
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { registerCursorFallbackIssueWarning } from "./cursor-fallback-warning.js
|
|
|
15
15
|
import { registerCursorAgentsContextDedup } from "./cursor-agents-context-registration.js";
|
|
16
16
|
import { registerCursorOverflowNormalization } from "./cursor-provider-overflow.js";
|
|
17
17
|
import { registerCursorSdkSessionProcessErrorGuard } from "./cursor-sdk-process-error-guard.js";
|
|
18
|
+
import { prepareCursorSessionForCompaction } from "./cursor-session-compaction-prep.js";
|
|
18
19
|
|
|
19
20
|
type CursorExtensionApi =
|
|
20
21
|
& Pick<ExtensionAPI, "registerProvider" | "registerCommand" | "on">
|
|
@@ -54,7 +55,6 @@ export default async function (pi: CursorExtensionApi) {
|
|
|
54
55
|
registerCursorSessionAgentLifecycle(pi);
|
|
55
56
|
registerCursorSessionAgentResume(pi);
|
|
56
57
|
pi.on("session_before_compact", async () => {
|
|
57
|
-
const { prepareCursorSessionForCompaction } = await import("./cursor-session-compaction-prep.js");
|
|
58
58
|
await prepareCursorSessionForCompaction();
|
|
59
59
|
});
|
|
60
60
|
registerCursorRuntimeControls(pi);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"rootDir": "src",
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"noEmit": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|