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
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { truncateCursorDisplayLine } from "./cursor-display-text.js";
|
|
2
|
+
import { scrubSensitiveText } from "./cursor-sensitive-text.js";
|
|
3
|
+
import { asRecord, getArray, getNumber, getRecord, getString } from "./cursor-record-utils.js";
|
|
4
|
+
const DEFAULT_CURSOR_CLOUD_API_BASE_URL = "https://api.cursor.com";
|
|
5
|
+
const CLOUD_REPORT_TIMEOUT_MS = 5000;
|
|
6
|
+
const MAX_CLOUD_ID_DISPLAY_LENGTH = 160;
|
|
7
|
+
const MAX_CLOUD_REPO_DISPLAY_LENGTH = 240;
|
|
8
|
+
const MAX_CLOUD_BRANCH_DISPLAY_LENGTH = 160;
|
|
9
|
+
const MAX_CLOUD_ARTIFACT_DISPLAY_LENGTH = 240;
|
|
10
|
+
export const MAX_CLOUD_REPORT_BRANCHES = 5;
|
|
11
|
+
export const MAX_CLOUD_REPORT_ARTIFACTS = 10;
|
|
12
|
+
function withTimeout(promise, timeoutMs = CLOUD_REPORT_TIMEOUT_MS) {
|
|
13
|
+
let timer;
|
|
14
|
+
const timeout = new Promise((resolve) => {
|
|
15
|
+
timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
16
|
+
timer.unref?.();
|
|
17
|
+
});
|
|
18
|
+
return Promise.race([promise.catch(() => undefined), timeout]).finally(() => {
|
|
19
|
+
if (timer)
|
|
20
|
+
clearTimeout(timer);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function fetchJsonWithAbortTimeout(fetchImpl, url, init, timeoutMs = CLOUD_REPORT_TIMEOUT_MS) {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
let timer;
|
|
26
|
+
const request = (async () => {
|
|
27
|
+
const response = await fetchImpl(url, { ...init, signal: controller.signal });
|
|
28
|
+
if (!response.ok)
|
|
29
|
+
return undefined;
|
|
30
|
+
return response.json();
|
|
31
|
+
})().catch(() => undefined);
|
|
32
|
+
const timeout = new Promise((resolve) => {
|
|
33
|
+
timer = setTimeout(() => {
|
|
34
|
+
controller.abort();
|
|
35
|
+
resolve(undefined);
|
|
36
|
+
}, timeoutMs);
|
|
37
|
+
timer.unref?.();
|
|
38
|
+
});
|
|
39
|
+
return Promise.race([request, timeout]).finally(() => {
|
|
40
|
+
if (timer)
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function readNonnegativeNumber(record, key) {
|
|
45
|
+
const value = getNumber(record, key);
|
|
46
|
+
return value !== undefined && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
47
|
+
}
|
|
48
|
+
function readTokenUsage(value) {
|
|
49
|
+
const record = asRecord(value);
|
|
50
|
+
const inputTokens = readNonnegativeNumber(record, "inputTokens");
|
|
51
|
+
const outputTokens = readNonnegativeNumber(record, "outputTokens");
|
|
52
|
+
const cacheReadTokens = readNonnegativeNumber(record, "cacheReadTokens");
|
|
53
|
+
const cacheWriteTokens = readNonnegativeNumber(record, "cacheWriteTokens");
|
|
54
|
+
const totalTokens = readNonnegativeNumber(record, "totalTokens");
|
|
55
|
+
if (inputTokens === undefined ||
|
|
56
|
+
outputTokens === undefined ||
|
|
57
|
+
cacheReadTokens === undefined ||
|
|
58
|
+
cacheWriteTokens === undefined ||
|
|
59
|
+
totalTokens === undefined)
|
|
60
|
+
return undefined;
|
|
61
|
+
const reasoningTokens = readNonnegativeNumber(record, "reasoningTokens");
|
|
62
|
+
return {
|
|
63
|
+
inputTokens,
|
|
64
|
+
outputTokens,
|
|
65
|
+
cacheReadTokens,
|
|
66
|
+
cacheWriteTokens,
|
|
67
|
+
totalTokens,
|
|
68
|
+
...(reasoningTokens === undefined ? {} : { reasoningTokens }),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function readNonemptyString(record, key) {
|
|
72
|
+
const value = getString(record, key);
|
|
73
|
+
return value && truncateCursorDisplayLine(value) ? value : undefined;
|
|
74
|
+
}
|
|
75
|
+
function normalizeBranches(value) {
|
|
76
|
+
if (!Array.isArray(value))
|
|
77
|
+
return [];
|
|
78
|
+
return value.flatMap((item) => {
|
|
79
|
+
const record = asRecord(item);
|
|
80
|
+
const repoUrl = readNonemptyString(record, "repoUrl");
|
|
81
|
+
if (!repoUrl)
|
|
82
|
+
return [];
|
|
83
|
+
const branch = readNonemptyString(record, "branch");
|
|
84
|
+
const prUrl = readNonemptyString(record, "prUrl");
|
|
85
|
+
return branch || prUrl ? [{ repoUrl, ...(branch ? { branch } : {}), ...(prUrl ? { prUrl } : {}) }] : [];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function normalizeArtifacts(value) {
|
|
89
|
+
if (value === undefined)
|
|
90
|
+
return undefined;
|
|
91
|
+
if (!Array.isArray(value))
|
|
92
|
+
return undefined;
|
|
93
|
+
return value.flatMap((item) => {
|
|
94
|
+
const record = asRecord(item);
|
|
95
|
+
const path = readNonemptyString(record, "path");
|
|
96
|
+
const sizeBytes = readNonnegativeNumber(record, "sizeBytes");
|
|
97
|
+
const updatedAt = readNonemptyString(record, "updatedAt");
|
|
98
|
+
return path && sizeBytes !== undefined && updatedAt ? [{ path, sizeBytes, updatedAt }] : [];
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function normalizeUsage(value) {
|
|
102
|
+
const record = asRecord(value);
|
|
103
|
+
const totalUsage = readTokenUsage(getRecord(record, "totalUsage"));
|
|
104
|
+
const runUsage = readTokenUsage(getRecord(record, "runUsage"));
|
|
105
|
+
return totalUsage || runUsage ? { ...(totalUsage ? { totalUsage } : {}), ...(runUsage ? { runUsage } : {}) } : undefined;
|
|
106
|
+
}
|
|
107
|
+
export async function fetchCursorCloudRawUsage(options) {
|
|
108
|
+
if (!options.apiKey || typeof options.fetchImpl !== "function" && typeof fetch !== "function")
|
|
109
|
+
return undefined;
|
|
110
|
+
try {
|
|
111
|
+
const baseUrl = options.baseUrl ?? DEFAULT_CURSOR_CLOUD_API_BASE_URL;
|
|
112
|
+
const url = new URL(`/v1/agents/${encodeURIComponent(options.agentId)}/usage`, baseUrl);
|
|
113
|
+
if (options.runId)
|
|
114
|
+
url.searchParams.set("runId", options.runId);
|
|
115
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
116
|
+
const body = asRecord(await fetchJsonWithAbortTimeout(fetchImpl, url, {
|
|
117
|
+
headers: {
|
|
118
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
119
|
+
"x-cursor-client-type": "sdk",
|
|
120
|
+
},
|
|
121
|
+
}, options.timeoutMs));
|
|
122
|
+
const runs = getArray(body, "runs") ?? [];
|
|
123
|
+
const matchingRun = options.runId
|
|
124
|
+
? runs.map(asRecord).find((run) => getString(run, "id") === options.runId)
|
|
125
|
+
: undefined;
|
|
126
|
+
return normalizeUsage({
|
|
127
|
+
totalUsage: getRecord(body, "totalUsage"),
|
|
128
|
+
runUsage: getRecord(matchingRun, "usage"),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function mapCursorSdkAgentUsageToCloudReport(value, runId) {
|
|
136
|
+
const record = asRecord(value);
|
|
137
|
+
const runs = (getArray(record, "runs") ?? []).map(asRecord);
|
|
138
|
+
const matchingRun = runId ? runs.find((run) => getString(run, "runId") === runId) : undefined;
|
|
139
|
+
return normalizeUsage({
|
|
140
|
+
totalUsage: getRecord(record, "usage"),
|
|
141
|
+
runUsage: getRecord(matchingRun, "usage"),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
export async function collectCursorCloudRunReport(options) {
|
|
145
|
+
const listArtifacts = options.agent.listArtifacts;
|
|
146
|
+
const sdkUsage = options.agentUsage !== undefined
|
|
147
|
+
? mapCursorSdkAgentUsageToCloudReport(options.agentUsage, options.run.id)
|
|
148
|
+
: typeof options.agent.getUsage === "function"
|
|
149
|
+
? mapCursorSdkAgentUsageToCloudReport(await withTimeout(Promise.resolve(options.agent.getUsage({ runId: options.run.id }))), options.run.id)
|
|
150
|
+
: undefined;
|
|
151
|
+
const [artifactResult, restUsage] = await Promise.all([
|
|
152
|
+
typeof listArtifacts === "function" ? withTimeout(listArtifacts.call(options.agent)) : undefined,
|
|
153
|
+
sdkUsage ? undefined : fetchCursorCloudRawUsage({ agentId: options.run.agentId, runId: options.run.id, apiKey: options.apiKey }),
|
|
154
|
+
]);
|
|
155
|
+
const usage = sdkUsage ?? restUsage;
|
|
156
|
+
const waitBranches = getArray(getRecord(asRecord(options.waitResult), "git"), "branches");
|
|
157
|
+
const runBranches = getArray(getRecord(asRecord(options.run), "git"), "branches");
|
|
158
|
+
return {
|
|
159
|
+
agentId: options.run.agentId,
|
|
160
|
+
runId: options.run.id,
|
|
161
|
+
branches: normalizeBranches(waitBranches ?? runBranches),
|
|
162
|
+
artifacts: normalizeArtifacts(artifactResult),
|
|
163
|
+
usage: normalizeUsage(usage),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function formatTokenUsage(usage) {
|
|
167
|
+
const parts = [
|
|
168
|
+
`input ${usage.inputTokens.toLocaleString("en-US")}`,
|
|
169
|
+
`output ${usage.outputTokens.toLocaleString("en-US")}`,
|
|
170
|
+
`cache read ${usage.cacheReadTokens.toLocaleString("en-US")}`,
|
|
171
|
+
`cache write ${usage.cacheWriteTokens.toLocaleString("en-US")}`,
|
|
172
|
+
`total ${usage.totalTokens.toLocaleString("en-US")}`,
|
|
173
|
+
];
|
|
174
|
+
if (usage.reasoningTokens !== undefined)
|
|
175
|
+
parts.splice(2, 0, `reasoning ${usage.reasoningTokens.toLocaleString("en-US")}`);
|
|
176
|
+
return parts.join(", ");
|
|
177
|
+
}
|
|
178
|
+
function remoteDisplayString(value, maxLength, apiKey) {
|
|
179
|
+
return typeof value === "string" ? truncateCursorDisplayLine(scrubSensitiveText(value, apiKey), maxLength) : "";
|
|
180
|
+
}
|
|
181
|
+
function formatBranchLine(branch, apiKey) {
|
|
182
|
+
const lines = [];
|
|
183
|
+
const branchName = remoteDisplayString(branch.branch, MAX_CLOUD_BRANCH_DISPLAY_LENGTH, apiKey);
|
|
184
|
+
const repoUrl = remoteDisplayString(branch.repoUrl, MAX_CLOUD_REPO_DISPLAY_LENGTH, apiKey);
|
|
185
|
+
const prUrl = remoteDisplayString(branch.prUrl, MAX_CLOUD_REPO_DISPLAY_LENGTH, apiKey);
|
|
186
|
+
if (branchName)
|
|
187
|
+
lines.push(`- branch: ${branchName}${repoUrl ? ` (${repoUrl})` : ""}`);
|
|
188
|
+
if (prUrl)
|
|
189
|
+
lines.push(`- PR: ${prUrl}`);
|
|
190
|
+
return lines;
|
|
191
|
+
}
|
|
192
|
+
export function formatCursorCloudRunReport(report, options = {}) {
|
|
193
|
+
const agentId = remoteDisplayString(report.agentId, MAX_CLOUD_ID_DISPLAY_LENGTH, options.apiKey) || "unknown";
|
|
194
|
+
const runId = remoteDisplayString(report.runId, MAX_CLOUD_ID_DISPLAY_LENGTH, options.apiKey) || "unknown";
|
|
195
|
+
const branches = normalizeBranches(report.branches);
|
|
196
|
+
const artifacts = normalizeArtifacts(report.artifacts);
|
|
197
|
+
const lines = ["Cursor cloud run:", `- agent: ${agentId}`, `- run: ${runId}`];
|
|
198
|
+
for (const branch of branches.slice(0, MAX_CLOUD_REPORT_BRANCHES))
|
|
199
|
+
lines.push(...formatBranchLine(branch, options.apiKey));
|
|
200
|
+
if (branches.length > MAX_CLOUD_REPORT_BRANCHES)
|
|
201
|
+
lines.push(`- branches: +${branches.length - MAX_CLOUD_REPORT_BRANCHES} more`);
|
|
202
|
+
if (artifacts) {
|
|
203
|
+
if (artifacts.length === 0) {
|
|
204
|
+
lines.push("- artifacts: none");
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
lines.push("- artifacts:");
|
|
208
|
+
for (const artifact of artifacts.slice(0, MAX_CLOUD_REPORT_ARTIFACTS)) {
|
|
209
|
+
const path = remoteDisplayString(artifact.path, MAX_CLOUD_ARTIFACT_DISPLAY_LENGTH, options.apiKey);
|
|
210
|
+
const updatedAt = remoteDisplayString(artifact.updatedAt, MAX_CLOUD_ARTIFACT_DISPLAY_LENGTH, options.apiKey);
|
|
211
|
+
lines.push(` - ${path} (${artifact.sizeBytes.toLocaleString("en-US")} bytes, updated ${updatedAt})`);
|
|
212
|
+
}
|
|
213
|
+
if (artifacts.length > MAX_CLOUD_REPORT_ARTIFACTS)
|
|
214
|
+
lines.push(` - +${artifacts.length - MAX_CLOUD_REPORT_ARTIFACTS} more`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const normalizedUsage = normalizeUsage(report.usage);
|
|
218
|
+
const usage = normalizedUsage?.runUsage ?? normalizedUsage?.totalUsage;
|
|
219
|
+
if (usage)
|
|
220
|
+
lines.push(`- raw usage (display only): ${formatTokenUsage(usage)}`);
|
|
221
|
+
return scrubSensitiveText(`${lines.join("\n")}\n`, options.apiKey);
|
|
222
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { isAbsolute, relative, win32 } from "node:path";
|
|
2
|
+
import { asRecord, getRecord, getString } from "./cursor-record-utils.js";
|
|
3
|
+
import { formatDisplayPath } from "./cursor-transcript-utils.js";
|
|
4
|
+
function isWindowsAbsolutePath(path) {
|
|
5
|
+
return /^[A-Za-z]:[\\/]/.test(path) || path.startsWith("\\\\");
|
|
6
|
+
}
|
|
7
|
+
export function formatCursorCompactToolPath(path, options) {
|
|
8
|
+
const trimmed = path?.trim();
|
|
9
|
+
if (!trimmed)
|
|
10
|
+
return undefined;
|
|
11
|
+
const normalized = trimmed.replace(/\\/g, "/");
|
|
12
|
+
if (normalized === "~" || normalized.startsWith("~/") || /^~[^/]+(?:\/|$)/.test(normalized))
|
|
13
|
+
return undefined;
|
|
14
|
+
if (normalized.split("/").includes(".."))
|
|
15
|
+
return undefined;
|
|
16
|
+
if (/^[A-Za-z]:(?!\/)/.test(normalized))
|
|
17
|
+
return undefined;
|
|
18
|
+
if (isWindowsAbsolutePath(trimmed)) {
|
|
19
|
+
const cwd = options.cwd;
|
|
20
|
+
if (!cwd || !isWindowsAbsolutePath(cwd))
|
|
21
|
+
return undefined;
|
|
22
|
+
const relativePath = win32.relative(cwd, trimmed);
|
|
23
|
+
if (!relativePath || relativePath.startsWith("..") || isWindowsAbsolutePath(relativePath))
|
|
24
|
+
return undefined;
|
|
25
|
+
return relativePath.replace(/\\/g, "/");
|
|
26
|
+
}
|
|
27
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(normalized))
|
|
28
|
+
return undefined;
|
|
29
|
+
if (isAbsolute(trimmed)) {
|
|
30
|
+
const cwd = options.cwd;
|
|
31
|
+
if (!cwd)
|
|
32
|
+
return undefined;
|
|
33
|
+
const relativePath = relative(cwd, trimmed);
|
|
34
|
+
if (!relativePath || relativePath.startsWith("..") || isAbsolute(relativePath))
|
|
35
|
+
return undefined;
|
|
36
|
+
return relativePath.replace(/\\/g, "/");
|
|
37
|
+
}
|
|
38
|
+
return formatDisplayPath(normalized, options.cwd);
|
|
39
|
+
}
|
|
40
|
+
function getNestedRecord(record, ...keys) {
|
|
41
|
+
let current = record;
|
|
42
|
+
for (const key of keys) {
|
|
43
|
+
current = getRecord(current, key);
|
|
44
|
+
if (!current)
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return current;
|
|
48
|
+
}
|
|
49
|
+
function summarizeShellTool(args, resultValue) {
|
|
50
|
+
const command = getString(args, "command");
|
|
51
|
+
const stdout = getString(resultValue, "stdout");
|
|
52
|
+
const stderr = getString(resultValue, "stderr");
|
|
53
|
+
return [command ? `$ ${command}` : "shell", stdout, stderr].filter((part) => Boolean(part)).join("\n");
|
|
54
|
+
}
|
|
55
|
+
export function summarizeCursorCompactToolCall(toolName, args, result, options) {
|
|
56
|
+
if (!toolName)
|
|
57
|
+
return undefined;
|
|
58
|
+
const compactName = toolName.replace(/\s+/g, " ").trim() || "unknown";
|
|
59
|
+
if (compactName === "shell")
|
|
60
|
+
return summarizeShellTool(args, getNestedRecord(result, "value"));
|
|
61
|
+
const path = formatCursorCompactToolPath(getString(args, "path"), options);
|
|
62
|
+
if (path)
|
|
63
|
+
return `${compactName} ${path}`;
|
|
64
|
+
const query = getString(args, "query") ?? getString(args, "pattern");
|
|
65
|
+
if (query)
|
|
66
|
+
return `${compactName} ${query}`;
|
|
67
|
+
return compactName;
|
|
68
|
+
}
|
|
69
|
+
export function summarizeCursorCompactConversationToolCall(step, options) {
|
|
70
|
+
const record = asRecord(step);
|
|
71
|
+
if (getString(record, "type") !== "toolCall")
|
|
72
|
+
return undefined;
|
|
73
|
+
const message = getRecord(record, "message");
|
|
74
|
+
return summarizeCursorCompactToolCall(getString(message, "type"), getRecord(message, "args"), getRecord(message, "result"), options);
|
|
75
|
+
}
|