@emmaneugene/pi-cursor-sdk 0.3.7 → 0.4.0

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +99 -126
  3. package/dist/cursor-agents-context-registration.js +1 -3
  4. package/dist/cursor-agents-context.js +2 -2
  5. package/dist/cursor-config.js +2 -290
  6. package/dist/cursor-provider-errors.js +3 -58
  7. package/dist/cursor-provider-live-run-drain.js +0 -3
  8. package/dist/cursor-provider-run-finalizer.js +4 -7
  9. package/dist/cursor-provider-run-outcome.js +1 -1
  10. package/dist/cursor-provider-turn-finalize.js +3 -55
  11. package/dist/cursor-provider-turn-prepare.js +8 -144
  12. package/dist/cursor-provider-turn-runner.js +9 -23
  13. package/dist/cursor-provider-turn-send.js +8 -35
  14. package/dist/cursor-runtime-state.js +6 -268
  15. package/dist/cursor-sdk-billed-usage.js +3 -18
  16. package/dist/cursor-sdk-platform-package.js +88 -0
  17. package/dist/cursor-session-agent.js +18 -14
  18. package/dist/cursor-skill-tool.js +12 -22
  19. package/dist/cursor-state.js +5 -8
  20. package/dist/cursor-usage-accounting.js +1 -1
  21. package/docs/cursor-dogfood-checklist.md +4 -4
  22. package/docs/cursor-live-smoke-checklist.md +23 -23
  23. package/docs/cursor-model-ux-spec.md +27 -30
  24. package/docs/cursor-native-tool-replay.md +4 -4
  25. package/docs/cursor-native-tool-visual-audit.md +7 -7
  26. package/docs/cursor-testing-lessons.md +23 -16
  27. package/docs/cursor-tool-surfaces.md +2 -4
  28. package/docs/platform-smoke-implementation.md +5 -5
  29. package/docs/platform-smoke.md +27 -72
  30. package/package.json +3 -17
  31. package/platform-smoke.config.mjs +2 -1
  32. package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
  33. package/scripts/platform-smoke/card-detect.mjs +1 -1
  34. package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
  35. package/scripts/platform-smoke/scenarios.mjs +1 -1
  36. package/scripts/platform-smoke/targets.mjs +14 -5
  37. package/src/cursor-agents-context-registration.ts +0 -5
  38. package/src/cursor-agents-context.ts +1 -3
  39. package/src/cursor-config.ts +8 -379
  40. package/src/cursor-provider-errors.ts +2 -62
  41. package/src/cursor-provider-live-run-drain.ts +0 -3
  42. package/src/cursor-provider-run-finalizer.ts +4 -12
  43. package/src/cursor-provider-run-outcome.ts +0 -3
  44. package/src/cursor-provider-turn-finalize.ts +3 -61
  45. package/src/cursor-provider-turn-prepare.ts +8 -165
  46. package/src/cursor-provider-turn-runner.ts +15 -31
  47. package/src/cursor-provider-turn-send.ts +7 -38
  48. package/src/cursor-provider-turn-types.ts +9 -30
  49. package/src/cursor-runtime-state.ts +6 -345
  50. package/src/cursor-sdk-billed-usage.ts +3 -24
  51. package/src/cursor-sdk-platform-package.ts +106 -0
  52. package/src/cursor-session-agent.ts +16 -12
  53. package/src/cursor-skill-tool.ts +10 -26
  54. package/src/cursor-state.ts +5 -10
  55. package/src/cursor-usage-accounting.ts +1 -3
  56. package/dist/cursor-cloud-lifecycle.js +0 -650
  57. package/dist/cursor-cloud-local-state.js +0 -460
  58. package/dist/cursor-cloud-options.js +0 -145
  59. package/dist/cursor-cloud-reporting.js +0 -222
  60. package/dist/cursor-ripgrep-path.js +0 -27
  61. package/scripts/cloud-runtime-smoke.d.mts +0 -42
  62. package/scripts/cloud-runtime-smoke.mjs +0 -623
  63. package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
  64. package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
  65. package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
  66. package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
  67. package/scripts/lib/cloud-smoke-github.d.mts +0 -78
  68. package/scripts/lib/cloud-smoke-github.mjs +0 -331
  69. package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
  70. package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
  71. package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
  72. package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
  73. package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
  74. package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
  75. package/src/cursor-cloud-lifecycle.ts +0 -733
  76. package/src/cursor-cloud-local-state.ts +0 -536
  77. package/src/cursor-cloud-options.ts +0 -182
  78. package/src/cursor-cloud-reporting.ts +0 -267
  79. package/src/cursor-ripgrep-path.ts +0 -32
@@ -1,222 +0,0 @@
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
- }
@@ -1,27 +0,0 @@
1
- import { accessSync, constants } from "node:fs";
2
- import { createRequire } from "node:module";
3
- import { dirname, isAbsolute, join } from "node:path";
4
- const RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
5
- export function resolveBundledCursorRipgrepPath(fromModuleUrl = import.meta.url) {
6
- try {
7
- const require = createRequire(fromModuleUrl);
8
- const platformPackage = `@cursor/sdk-${process.platform}-${process.arch}`;
9
- const sdkEntry = require.resolve("@cursor/sdk");
10
- const packageDirectory = dirname(require.resolve(`${platformPackage}/package.json`, { paths: [dirname(sdkEntry)] }));
11
- const ripgrepPath = join(packageDirectory, "bin", process.platform === "win32" ? "rg.exe" : "rg");
12
- accessSync(ripgrepPath, constants.X_OK);
13
- return ripgrepPath;
14
- }
15
- catch {
16
- return undefined;
17
- }
18
- }
19
- export function ensureCursorRipgrepPath() {
20
- const configuredPath = process.env[RIPGREP_ENV];
21
- if (configuredPath && isAbsolute(configuredPath))
22
- return configuredPath;
23
- const bundledPath = resolveBundledCursorRipgrepPath();
24
- if (bundledPath)
25
- process.env[RIPGREP_ENV] = bundledPath;
26
- return bundledPath;
27
- }
@@ -1,42 +0,0 @@
1
- export function buildCloudSmokeEnv(artifactDir: string, options?: {
2
- contextHandoff?: "fresh" | "bootstrap" | "never";
3
- repoUrl?: string;
4
- startingRef?: string;
5
- directPush?: boolean;
6
- }): NodeJS.ProcessEnv;
7
- export function buildCloudSmokeWorkspace(artifactDir: string): string;
8
- export function cloudAgentIdsFromLifecycleArtifacts(artifactDir: string): string[];
9
-
10
- export {
11
- assertCloudSmokeEvidenceSafe,
12
- buildCloudSmokeEvidenceProvenance,
13
- coordinateCloudSmokeReleaseGate,
14
- listCloudSmokePackageSourcePaths,
15
- projectCloudSmokeMatrixEvidence,
16
- validateCloudSmokeMatrixEvidence,
17
- } from "./lib/cloud-smoke-cleanup-evidence.d.mts";
18
-
19
- export type {
20
- CloudSmokeBranchLaneEvidence,
21
- CloudSmokeCancelLaneEvidence,
22
- CloudSmokeCleanupEvidence,
23
- CloudSmokeDirectPushLaneEvidence,
24
- CloudSmokeEvidenceBranch,
25
- CloudSmokeEvidenceProvenance,
26
- CloudSmokeLaneEvidence,
27
- CloudSmokeLaneName,
28
- CloudSmokeLifecycleDeleteLaneEvidence,
29
- CloudSmokeMatrixEvidence,
30
- CloudSmokeMissingBranchLaneEvidence,
31
- CloudSmokePassiveArtifactsLaneEvidence,
32
- CloudSmokeReleaseGateState,
33
- CloudSmokeThrowawayRepositoryEvidence,
34
- } from "./lib/cloud-smoke-cleanup-evidence.d.mts";
35
-
36
- export {
37
- assertOwnedThrowawayRepositoryHandle,
38
- cloudSmokeRepositoryDescription,
39
- normalizeCloudSmokeGitHubRepo,
40
- } from "./lib/cloud-smoke-github.d.mts";
41
-
42
- export type { CloudSmokeOwnedRepository } from "./lib/cloud-smoke-github.d.mts";