@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.
- package/CHANGELOG.md +16 -0
- package/README.md +99 -126
- package/dist/cursor-agents-context-registration.js +1 -3
- package/dist/cursor-agents-context.js +2 -2
- package/dist/cursor-config.js +2 -290
- package/dist/cursor-provider-errors.js +3 -58
- package/dist/cursor-provider-live-run-drain.js +0 -3
- package/dist/cursor-provider-run-finalizer.js +4 -7
- package/dist/cursor-provider-run-outcome.js +1 -1
- package/dist/cursor-provider-turn-finalize.js +3 -55
- package/dist/cursor-provider-turn-prepare.js +8 -144
- package/dist/cursor-provider-turn-runner.js +9 -23
- package/dist/cursor-provider-turn-send.js +8 -35
- package/dist/cursor-runtime-state.js +6 -268
- package/dist/cursor-sdk-billed-usage.js +3 -18
- package/dist/cursor-sdk-platform-package.js +88 -0
- package/dist/cursor-session-agent.js +18 -14
- package/dist/cursor-skill-tool.js +12 -22
- package/dist/cursor-state.js +5 -8
- package/dist/cursor-usage-accounting.js +1 -1
- package/docs/cursor-dogfood-checklist.md +4 -4
- package/docs/cursor-live-smoke-checklist.md +23 -23
- package/docs/cursor-model-ux-spec.md +27 -30
- package/docs/cursor-native-tool-replay.md +4 -4
- package/docs/cursor-native-tool-visual-audit.md +7 -7
- package/docs/cursor-testing-lessons.md +23 -16
- package/docs/cursor-tool-surfaces.md +2 -4
- package/docs/platform-smoke-implementation.md +5 -5
- package/docs/platform-smoke.md +27 -72
- package/package.json +3 -17
- package/platform-smoke.config.mjs +2 -1
- package/scripts/lib/local-resume-smoke-harness.mjs +0 -18
- package/scripts/platform-smoke/card-detect.mjs +1 -1
- package/scripts/platform-smoke/local-resume-runner.mjs +1 -1
- package/scripts/platform-smoke/scenarios.mjs +1 -1
- package/scripts/platform-smoke/targets.mjs +14 -5
- package/src/cursor-agents-context-registration.ts +0 -5
- package/src/cursor-agents-context.ts +1 -3
- package/src/cursor-config.ts +8 -379
- package/src/cursor-provider-errors.ts +2 -62
- package/src/cursor-provider-live-run-drain.ts +0 -3
- package/src/cursor-provider-run-finalizer.ts +4 -12
- package/src/cursor-provider-run-outcome.ts +0 -3
- package/src/cursor-provider-turn-finalize.ts +3 -61
- package/src/cursor-provider-turn-prepare.ts +8 -165
- package/src/cursor-provider-turn-runner.ts +15 -31
- package/src/cursor-provider-turn-send.ts +7 -38
- package/src/cursor-provider-turn-types.ts +9 -30
- package/src/cursor-runtime-state.ts +6 -345
- package/src/cursor-sdk-billed-usage.ts +3 -24
- package/src/cursor-sdk-platform-package.ts +106 -0
- package/src/cursor-session-agent.ts +16 -12
- package/src/cursor-skill-tool.ts +10 -26
- package/src/cursor-state.ts +5 -10
- package/src/cursor-usage-accounting.ts +1 -3
- package/dist/cursor-cloud-lifecycle.js +0 -650
- package/dist/cursor-cloud-local-state.js +0 -460
- package/dist/cursor-cloud-options.js +0 -145
- package/dist/cursor-cloud-reporting.js +0 -222
- package/dist/cursor-ripgrep-path.js +0 -27
- package/scripts/cloud-runtime-smoke.d.mts +0 -42
- package/scripts/cloud-runtime-smoke.mjs +0 -623
- package/scripts/lib/cloud-smoke-artifacts.d.mts +0 -16
- package/scripts/lib/cloud-smoke-artifacts.mjs +0 -94
- package/scripts/lib/cloud-smoke-cleanup-evidence.d.mts +0 -209
- package/scripts/lib/cloud-smoke-cleanup-evidence.mjs +0 -585
- package/scripts/lib/cloud-smoke-github.d.mts +0 -78
- package/scripts/lib/cloud-smoke-github.mjs +0 -331
- package/scripts/lib/cloud-smoke-pi-runner.d.mts +0 -42
- package/scripts/lib/cloud-smoke-pi-runner.mjs +0 -214
- package/scripts/lib/cloud-smoke-shutdown.d.mts +0 -67
- package/scripts/lib/cloud-smoke-shutdown.mjs +0 -133
- package/shared/cursor-cloud-lifecycle-constants.d.mts +0 -3
- package/shared/cursor-cloud-lifecycle-constants.mjs +0 -7
- package/src/cursor-cloud-lifecycle.ts +0 -733
- package/src/cursor-cloud-local-state.ts +0 -536
- package/src/cursor-cloud-options.ts +0 -182
- package/src/cursor-cloud-reporting.ts +0 -267
- package/src/cursor-ripgrep-path.ts +0 -32
|
@@ -48,13 +48,7 @@ interface CursorProviderTurnRuntimeBase {
|
|
|
48
48
|
billedTurnUsage?: CursorSdkTurnUsage;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
/**
|
|
52
|
-
* Runtime-agnostic lifecycle operations for a prepared turn.
|
|
53
|
-
*
|
|
54
|
-
* Local implementations delegate to the session agent lease; cloud
|
|
55
|
-
* implementations no-op the local-only operations (commitSend,
|
|
56
|
-
* trackRunCompletion, abandon) and dispose the cloud agent instead.
|
|
57
|
-
*/
|
|
51
|
+
/** Lifecycle operations for a prepared local turn, delegated to the session agent lease. */
|
|
58
52
|
export interface CursorProviderTurnLifecycle {
|
|
59
53
|
trackRunCompletion(completion: Promise<unknown>): void;
|
|
60
54
|
commitSend(context: Context, bootstrapped: boolean): void;
|
|
@@ -74,7 +68,13 @@ export interface LiveCursorProviderTurnRuntime extends CursorProviderTurnRuntime
|
|
|
74
68
|
|
|
75
69
|
export type CursorProviderTurnRuntime = DirectCursorProviderTurnRuntime | LiveCursorProviderTurnRuntime;
|
|
76
70
|
|
|
77
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Single owned model for a prepared local provider turn.
|
|
73
|
+
*
|
|
74
|
+
* Send, finalize, and cleanup phases receive this immutable object instead of
|
|
75
|
+
* keeping parallel liveRun/turnCoordinator/resource bags in sync by convention.
|
|
76
|
+
*/
|
|
77
|
+
export interface CursorProviderTurnPrepareResult {
|
|
78
78
|
agent: SDKAgent;
|
|
79
79
|
cwd: string;
|
|
80
80
|
payload: CursorProviderTurnSendPayload;
|
|
@@ -83,33 +83,12 @@ interface CursorProviderTurnPrepareResultBase {
|
|
|
83
83
|
textDeltas: string[];
|
|
84
84
|
restoreCursorSdkOutputFilter: () => void;
|
|
85
85
|
lifecycle: CursorProviderTurnLifecycle;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface LocalCursorProviderTurnPrepareResult extends CursorProviderTurnPrepareResultBase {
|
|
89
|
-
runtimeTarget: "local";
|
|
90
|
-
runtime: CursorProviderTurnRuntime;
|
|
91
86
|
sessionAgentScopeKey: string;
|
|
92
87
|
sessionAgentLease: SessionCursorAgentLease;
|
|
93
88
|
localForce: CursorResolvedSetting<boolean>;
|
|
89
|
+
runtime: CursorProviderTurnRuntime;
|
|
94
90
|
}
|
|
95
91
|
|
|
96
|
-
export interface CloudCursorProviderTurnPrepareResult extends CursorProviderTurnPrepareResultBase {
|
|
97
|
-
runtimeTarget: "cloud";
|
|
98
|
-
runtime: DirectCursorProviderTurnRuntime;
|
|
99
|
-
sessionAgentScopeKey?: undefined;
|
|
100
|
-
sessionAgentLease?: undefined;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Single owned model for a prepared provider turn.
|
|
105
|
-
*
|
|
106
|
-
* Send, finalize, and cleanup phases receive this immutable object instead of
|
|
107
|
-
* keeping parallel liveRun/turnCoordinator/resource bags in sync by convention.
|
|
108
|
-
*/
|
|
109
|
-
export type CursorProviderTurnPrepareResult =
|
|
110
|
-
| LocalCursorProviderTurnPrepareResult
|
|
111
|
-
| CloudCursorProviderTurnPrepareResult;
|
|
112
|
-
|
|
113
92
|
export interface CursorProviderTurnSend {
|
|
114
93
|
run: Awaited<ReturnType<SDKAgent["send"]>>;
|
|
115
94
|
cursorAgentMessageOffset: number | undefined;
|
|
@@ -1,106 +1,38 @@
|
|
|
1
|
-
import type { ExtensionAPI, ExtensionContext
|
|
2
|
-
import {
|
|
3
|
-
registerCursorCloudLifecycleLedger,
|
|
4
|
-
runCursorCloudLifecycleCommand,
|
|
5
|
-
} from "./cursor-cloud-lifecycle.js";
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
6
2
|
import {
|
|
7
3
|
CURSOR_AUTO_REVIEW_ENV,
|
|
8
|
-
CURSOR_CLOUD_ACK_ENV,
|
|
9
|
-
CURSOR_CLOUD_ALLOW_LOCAL_STATE_ENV,
|
|
10
|
-
CURSOR_CLOUD_AUTO_CREATE_PR_ENV,
|
|
11
|
-
CURSOR_CLOUD_BRANCH_ENV,
|
|
12
|
-
CURSOR_CLOUD_CONTEXT_ENV,
|
|
13
|
-
CURSOR_CLOUD_DIRECT_PUSH_ENV,
|
|
14
|
-
CURSOR_CLOUD_ENV_ENV,
|
|
15
|
-
CURSOR_CLOUD_ENV_FROM_FILES_ENV,
|
|
16
|
-
CURSOR_CLOUD_ENV_NAME_ENV,
|
|
17
|
-
CURSOR_CLOUD_ENV_TYPE_ENV,
|
|
18
|
-
CURSOR_CLOUD_REPO_ENV,
|
|
19
|
-
CURSOR_CLOUD_SKIP_REVIEWER_REQUEST_ENV,
|
|
20
4
|
CURSOR_LOCAL_FORCE_ENV,
|
|
21
5
|
CURSOR_LOCAL_RESUME_ENV,
|
|
22
|
-
CURSOR_RUNTIME_ENV,
|
|
23
6
|
CURSOR_SANDBOX_ENV,
|
|
24
|
-
getCursorSdkProjectConfigPath,
|
|
25
|
-
getCursorSdkUserConfigPath,
|
|
26
7
|
loadCursorSdkConfig,
|
|
27
|
-
mergeCursorSdkConfigForUpdate,
|
|
28
|
-
parseExplicitCursorCloudEnvNames,
|
|
29
8
|
resolveCursorSdkConfig,
|
|
30
|
-
updateCursorSdkConfig,
|
|
31
9
|
type CursorExplicitSdkConfig,
|
|
32
10
|
type CursorResolvedSdkConfig,
|
|
33
11
|
type CursorResolvedSetting,
|
|
34
|
-
type CursorRuntime,
|
|
35
12
|
type CursorSdkConfig,
|
|
36
13
|
} from "./cursor-config.js";
|
|
37
|
-
import { asRecord } from "./cursor-record-utils.js";
|
|
38
14
|
import { getResolvedSessionCursorHttp1Enabled } from "./cursor-http1.js";
|
|
39
15
|
import { getCursorSessionCwd, getCursorSessionProjectTrusted } from "./cursor-session-scope.js";
|
|
40
16
|
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
export const CURSOR_CLOUD_ACK_DISCLOSURE = [
|
|
44
|
-
"Cursor Cloud executes this work remotely.",
|
|
45
|
-
"Fresh context is used by default; prior Pi context is included only with explicit bootstrap opt-in.",
|
|
46
|
-
"Pi-local tools and the Pi bridge are unavailable, and Pi environment variables are not forwarded.",
|
|
47
|
-
"Cursor may create branches, commit, push, and open pull requests.",
|
|
48
|
-
"Cloud agents remain until you archive or delete them.",
|
|
49
|
-
"Cloud Agents run in Max Mode, are billed at Cursor API pricing, and may require spend-limit setup.",
|
|
50
|
-
].join("\n\n");
|
|
51
|
-
|
|
52
|
-
interface CursorRuntimeEntryData {
|
|
53
|
-
runtime: CursorRuntime;
|
|
54
|
-
cloudAcknowledged?: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type CursorRuntimeStateExtensionApi = Pick<
|
|
58
|
-
ExtensionAPI,
|
|
59
|
-
"appendEntry" | "getFlag" | "registerFlag" | "registerCommand" | "on"
|
|
60
|
-
>;
|
|
17
|
+
export type CursorRuntimeStateExtensionApi = Pick<ExtensionAPI, "getFlag" | "registerFlag">;
|
|
61
18
|
|
|
62
19
|
type CursorRuntimeContext = Pick<ExtensionContext, "cwd">;
|
|
63
20
|
|
|
64
|
-
type CursorStatusRefresh = (ctx: ExtensionContext) => void;
|
|
65
|
-
|
|
66
21
|
interface CursorCliConfigSnapshot {
|
|
67
22
|
config: CursorExplicitSdkConfig;
|
|
68
|
-
cloudEnvNames?: string;
|
|
69
23
|
}
|
|
70
24
|
|
|
71
25
|
let cliCursorSnapshot: CursorCliConfigSnapshot = { config: {} };
|
|
72
26
|
let cliLocalForceConsumed = false;
|
|
73
27
|
let envLocalForceConsumed = false;
|
|
74
|
-
let sessionCursorRuntime: CursorRuntime | undefined;
|
|
75
|
-
let sessionCursorCloudAcknowledged = false;
|
|
76
|
-
|
|
77
|
-
function isCursorRuntimeEntryData(value: unknown): value is CursorRuntimeEntryData {
|
|
78
|
-
const record = asRecord(value);
|
|
79
|
-
if (!record) return false;
|
|
80
|
-
return (record.runtime === "local" || record.runtime === "cloud")
|
|
81
|
-
&& (record.cloudAcknowledged === undefined || typeof record.cloudAcknowledged === "boolean");
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function stringFlagValue(value: boolean | string | undefined): string | undefined {
|
|
85
|
-
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
86
|
-
}
|
|
87
28
|
|
|
88
29
|
export function getCursorCliConfig(): CursorExplicitSdkConfig {
|
|
89
|
-
|
|
90
|
-
const envNames = parseExplicitCursorCloudEnvNames(cliCursorSnapshot.cloudEnvNames, "--cursor-cloud-env");
|
|
91
|
-
if (envNames) config.cloud = { ...config.cloud, envNames };
|
|
92
|
-
return config;
|
|
30
|
+
return structuredClone(cliCursorSnapshot.config);
|
|
93
31
|
}
|
|
94
32
|
|
|
95
33
|
export function getCursorSessionConfig(): CursorSdkConfig {
|
|
96
34
|
const useHttp1ForAgent = getResolvedSessionCursorHttp1Enabled();
|
|
97
35
|
return {
|
|
98
|
-
...(sessionCursorRuntime
|
|
99
|
-
? {
|
|
100
|
-
runtime: sessionCursorRuntime,
|
|
101
|
-
...(sessionCursorCloudAcknowledged ? { cloud: { acknowledged: true } } : {}),
|
|
102
|
-
}
|
|
103
|
-
: {}),
|
|
104
36
|
...(useHttp1ForAgent === undefined ? {} : { local: { useHttp1ForAgent } }),
|
|
105
37
|
};
|
|
106
38
|
}
|
|
@@ -128,7 +60,6 @@ export function resolveEffectiveCursorConfigForContext(ctx: CursorRuntimeContext
|
|
|
128
60
|
export type CursorRuntimeResolution =
|
|
129
61
|
| {
|
|
130
62
|
kind: "valid";
|
|
131
|
-
runtime: CursorResolvedSetting<CursorRuntime>;
|
|
132
63
|
useHttp1ForAgent: CursorResolvedSetting<boolean>;
|
|
133
64
|
}
|
|
134
65
|
| { kind: "invalid"; message: string };
|
|
@@ -138,7 +69,6 @@ export function resolveCursorStatusRuntime(ctx: CursorRuntimeContext): CursorRun
|
|
|
138
69
|
const config = resolveEffectiveCursorConfigForContext(ctx);
|
|
139
70
|
return {
|
|
140
71
|
kind: "valid",
|
|
141
|
-
runtime: config.runtime,
|
|
142
72
|
useHttp1ForAgent: config.local.useHttp1ForAgent,
|
|
143
73
|
};
|
|
144
74
|
} catch (error) {
|
|
@@ -146,21 +76,13 @@ export function resolveCursorStatusRuntime(ctx: CursorRuntimeContext): CursorRun
|
|
|
146
76
|
}
|
|
147
77
|
}
|
|
148
78
|
|
|
149
|
-
export function formatResolvedCursorRuntime(runtime: CursorResolvedSetting<CursorRuntime>): string {
|
|
150
|
-
const cap = runtime.cappedBy;
|
|
151
|
-
return cap
|
|
152
|
-
? `${runtime.value} (source: ${runtime.source} safety cap over ${cap.cappedSource} ${cap.cappedValue})`
|
|
153
|
-
: `${runtime.value} (source: ${runtime.source})`;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
79
|
export function formatCursorStatus(
|
|
157
|
-
runtime: CursorRuntime | "invalid",
|
|
158
80
|
fast: boolean | undefined,
|
|
159
81
|
mode: "agent" | "plan" | "invalid",
|
|
160
82
|
useHttp1ForAgent = false,
|
|
161
83
|
): string {
|
|
162
|
-
const parts = [
|
|
163
|
-
if (
|
|
84
|
+
const parts = ["cursor", fast === true ? "fast:on" : fast === false ? "fast:off" : "fast:n/a"];
|
|
85
|
+
if (useHttp1ForAgent) parts.push("http1");
|
|
164
86
|
if (mode === "invalid") parts.push("mode invalid");
|
|
165
87
|
else if (mode === "plan") parts.push("plan");
|
|
166
88
|
return parts.join(" · ");
|
|
@@ -183,40 +105,7 @@ export function consumeCursorLocalForceOverride(resolved: { value: boolean; sour
|
|
|
183
105
|
return false;
|
|
184
106
|
}
|
|
185
107
|
|
|
186
|
-
export function restoreSessionCursorRuntimeState(branch: readonly SessionEntry[]): void {
|
|
187
|
-
sessionCursorRuntime = undefined;
|
|
188
|
-
sessionCursorCloudAcknowledged = false;
|
|
189
|
-
for (const entry of branch) {
|
|
190
|
-
if (entry.type !== "custom" || entry.customType !== CURSOR_RUNTIME_ENTRY_TYPE) continue;
|
|
191
|
-
if (isCursorRuntimeEntryData(entry.data)) {
|
|
192
|
-
sessionCursorRuntime = entry.data.runtime;
|
|
193
|
-
sessionCursorCloudAcknowledged ||= entry.data.cloudAcknowledged === true;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
108
|
export function restoreCursorCliState(pi: Pick<ExtensionAPI, "getFlag">): void {
|
|
199
|
-
const runtime = stringFlagValue(pi.getFlag("cursor-runtime"));
|
|
200
|
-
const repo = stringFlagValue(pi.getFlag("cursor-cloud-repo"));
|
|
201
|
-
const branch = stringFlagValue(pi.getFlag("cursor-cloud-branch"));
|
|
202
|
-
const contextHandoff = stringFlagValue(pi.getFlag("cursor-cloud-context"));
|
|
203
|
-
const environmentType = stringFlagValue(pi.getFlag("cursor-cloud-env-type"));
|
|
204
|
-
const environmentName = stringFlagValue(pi.getFlag("cursor-cloud-env-name"));
|
|
205
|
-
const cloudEnvNames = stringFlagValue(pi.getFlag("cursor-cloud-env"));
|
|
206
|
-
const cloud: NonNullable<CursorExplicitSdkConfig["cloud"]> = {
|
|
207
|
-
...(repo ? { repo } : {}),
|
|
208
|
-
...(branch ? { branch } : {}),
|
|
209
|
-
...(contextHandoff ? { contextHandoff } : {}),
|
|
210
|
-
...(pi.getFlag("cursor-cloud-direct-push") === true ? { directPush: true } : {}),
|
|
211
|
-
...(pi.getFlag("cursor-cloud-auto-create-pr") === true ? { autoCreatePR: true } : {}),
|
|
212
|
-
...(pi.getFlag("cursor-cloud-skip-reviewer-request") === true ? { skipReviewerRequest: true } : {}),
|
|
213
|
-
...(pi.getFlag("cursor-cloud-allow-local-state") === true ? { allowLocalState: true } : {}),
|
|
214
|
-
...(pi.getFlag("cursor-cloud-env-from-files") === true ? { envFromFiles: true } : {}),
|
|
215
|
-
...(environmentType || environmentName
|
|
216
|
-
? { environment: { ...(environmentType ? { type: environmentType } : {}), ...(environmentName ? { name: environmentName } : {}) } }
|
|
217
|
-
: {}),
|
|
218
|
-
...(pi.getFlag("cursor-cloud-ack") === true ? { acknowledged: true } : {}),
|
|
219
|
-
};
|
|
220
109
|
const local: NonNullable<CursorExplicitSdkConfig["local"]> = {
|
|
221
110
|
...(pi.getFlag("cursor-auto-review") === true ? { autoReview: true } : {}),
|
|
222
111
|
...(pi.getFlag("cursor-sandbox") === true ? { sandboxOptions: { enabled: true } } : {}),
|
|
@@ -229,94 +118,12 @@ export function restoreCursorCliState(pi: Pick<ExtensionAPI, "getFlag">): void {
|
|
|
229
118
|
};
|
|
230
119
|
cliCursorSnapshot = {
|
|
231
120
|
config: {
|
|
232
|
-
...(runtime ? { runtime } : {}),
|
|
233
|
-
...(Object.keys(cloud).length ? { cloud } : {}),
|
|
234
121
|
...(Object.keys(local).length ? { local } : {}),
|
|
235
122
|
},
|
|
236
|
-
...(cloudEnvNames ? { cloudEnvNames } : {}),
|
|
237
123
|
};
|
|
238
124
|
}
|
|
239
125
|
|
|
240
|
-
function
|
|
241
|
-
pi: Pick<ExtensionAPI, "appendEntry">,
|
|
242
|
-
runtime: CursorRuntime,
|
|
243
|
-
cloudAcknowledged = false,
|
|
244
|
-
): void {
|
|
245
|
-
const acknowledged = sessionCursorCloudAcknowledged || cloudAcknowledged;
|
|
246
|
-
pi.appendEntry<CursorRuntimeEntryData>(CURSOR_RUNTIME_ENTRY_TYPE, {
|
|
247
|
-
runtime,
|
|
248
|
-
...(acknowledged ? { cloudAcknowledged: true } : {}),
|
|
249
|
-
});
|
|
250
|
-
sessionCursorRuntime = runtime;
|
|
251
|
-
sessionCursorCloudAcknowledged = acknowledged;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function registerCursorRuntimeFlags(pi: Pick<ExtensionAPI, "registerFlag">): void {
|
|
255
|
-
pi.registerFlag("cursor-runtime", {
|
|
256
|
-
description: `Select Cursor runtime for this run: local or cloud (or set ${CURSOR_RUNTIME_ENV})`,
|
|
257
|
-
type: "string",
|
|
258
|
-
default: "",
|
|
259
|
-
});
|
|
260
|
-
pi.registerFlag("cursor-cloud-repo", {
|
|
261
|
-
description: `Set Cursor cloud repository URL for this run (or set ${CURSOR_CLOUD_REPO_ENV})`,
|
|
262
|
-
type: "string",
|
|
263
|
-
default: "",
|
|
264
|
-
});
|
|
265
|
-
pi.registerFlag("cursor-cloud-branch", {
|
|
266
|
-
description: `Set Cursor cloud branch/ref for this run (or set ${CURSOR_CLOUD_BRANCH_ENV})`,
|
|
267
|
-
type: "string",
|
|
268
|
-
default: "",
|
|
269
|
-
});
|
|
270
|
-
pi.registerFlag("cursor-cloud-context", {
|
|
271
|
-
description: `Set Cursor cloud context handoff: never, fresh, or bootstrap (or set ${CURSOR_CLOUD_CONTEXT_ENV})`,
|
|
272
|
-
type: "string",
|
|
273
|
-
default: "",
|
|
274
|
-
});
|
|
275
|
-
pi.registerFlag("cursor-cloud-direct-push", {
|
|
276
|
-
description: `Allow Cursor cloud direct push for this run (or set ${CURSOR_CLOUD_DIRECT_PUSH_ENV}=1)`,
|
|
277
|
-
type: "boolean",
|
|
278
|
-
default: false,
|
|
279
|
-
});
|
|
280
|
-
pi.registerFlag("cursor-cloud-auto-create-pr", {
|
|
281
|
-
description: `Ask Cursor cloud to create a pull request for this run (or set ${CURSOR_CLOUD_AUTO_CREATE_PR_ENV}=1)`,
|
|
282
|
-
type: "boolean",
|
|
283
|
-
default: false,
|
|
284
|
-
});
|
|
285
|
-
pi.registerFlag("cursor-cloud-skip-reviewer-request", {
|
|
286
|
-
description: `Ask Cursor cloud not to request you as a reviewer for this run (or set ${CURSOR_CLOUD_SKIP_REVIEWER_REQUEST_ENV}=1)`,
|
|
287
|
-
type: "boolean",
|
|
288
|
-
default: false,
|
|
289
|
-
});
|
|
290
|
-
pi.registerFlag("cursor-cloud-allow-local-state", {
|
|
291
|
-
description: `Allow Cursor cloud to proceed with local-only state for this run (or set ${CURSOR_CLOUD_ALLOW_LOCAL_STATE_ENV}=1)`,
|
|
292
|
-
type: "boolean",
|
|
293
|
-
default: false,
|
|
294
|
-
});
|
|
295
|
-
pi.registerFlag("cursor-cloud-env", {
|
|
296
|
-
description: `Reserved Cursor cloud env var names; env forwarding is not implemented yet (or set ${CURSOR_CLOUD_ENV_ENV})`,
|
|
297
|
-
type: "string",
|
|
298
|
-
default: "",
|
|
299
|
-
});
|
|
300
|
-
pi.registerFlag("cursor-cloud-env-from-files", {
|
|
301
|
-
description: `Reserved Cursor cloud env-file forwarding flag; not implemented yet (or set ${CURSOR_CLOUD_ENV_FROM_FILES_ENV}=1)`,
|
|
302
|
-
type: "boolean",
|
|
303
|
-
default: false,
|
|
304
|
-
});
|
|
305
|
-
pi.registerFlag("cursor-cloud-env-type", {
|
|
306
|
-
description: `Select Cursor-managed cloud environment type: cloud, pool, or machine (or set ${CURSOR_CLOUD_ENV_TYPE_ENV})`,
|
|
307
|
-
type: "string",
|
|
308
|
-
default: "",
|
|
309
|
-
});
|
|
310
|
-
pi.registerFlag("cursor-cloud-env-name", {
|
|
311
|
-
description: `Select Cursor-managed cloud environment name (or set ${CURSOR_CLOUD_ENV_NAME_ENV})`,
|
|
312
|
-
type: "string",
|
|
313
|
-
default: "",
|
|
314
|
-
});
|
|
315
|
-
pi.registerFlag("cursor-cloud-ack", {
|
|
316
|
-
description: `Acknowledge first-use Cursor cloud runtime risks for this run (or set ${CURSOR_CLOUD_ACK_ENV}=1)`,
|
|
317
|
-
type: "boolean",
|
|
318
|
-
default: false,
|
|
319
|
-
});
|
|
126
|
+
export function registerCursorLocalRuntimeFlags(pi: Pick<ExtensionAPI, "registerFlag">): void {
|
|
320
127
|
pi.registerFlag("cursor-auto-review", {
|
|
321
128
|
description: `Enable Cursor SDK local Auto-review for this run (or set ${CURSOR_AUTO_REVIEW_ENV}=1)`,
|
|
322
129
|
type: "boolean",
|
|
@@ -344,154 +151,8 @@ function registerCursorRuntimeFlags(pi: Pick<ExtensionAPI, "registerFlag">): voi
|
|
|
344
151
|
});
|
|
345
152
|
}
|
|
346
153
|
|
|
347
|
-
async function confirmCloudAcknowledgement(
|
|
348
|
-
ctx: Pick<ExtensionContext, "hasUI" | "ui">,
|
|
349
|
-
alreadyAcknowledged: boolean,
|
|
350
|
-
): Promise<boolean> {
|
|
351
|
-
if (alreadyAcknowledged) return true;
|
|
352
|
-
if (!ctx.hasUI) {
|
|
353
|
-
ctx.ui.notify(
|
|
354
|
-
`Cursor cloud runtime requires first-use acknowledgement. Pass --cursor-cloud-ack or set ${CURSOR_CLOUD_ACK_ENV}=1, then retry.`,
|
|
355
|
-
"error",
|
|
356
|
-
);
|
|
357
|
-
return false;
|
|
358
|
-
}
|
|
359
|
-
const confirmed = await ctx.ui.confirm("Enable Cursor Cloud runtime?", CURSOR_CLOUD_ACK_DISCLOSURE);
|
|
360
|
-
if (!confirmed) ctx.ui.notify("Cursor cloud runtime change cancelled; no settings were written.", "info");
|
|
361
|
-
return confirmed;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function registerCursorRuntimeCommand(
|
|
365
|
-
pi: Pick<ExtensionAPI, "appendEntry" | "registerCommand">,
|
|
366
|
-
refreshStatus: CursorStatusRefresh,
|
|
367
|
-
): void {
|
|
368
|
-
pi.registerCommand("cursor-runtime", {
|
|
369
|
-
description: "Set Cursor runtime for this session: local or cloud",
|
|
370
|
-
handler: async (args, ctx) => {
|
|
371
|
-
const usage = "Usage: /cursor-runtime local|cloud [--save-user|--save-project]";
|
|
372
|
-
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
373
|
-
const raw = tokens[0];
|
|
374
|
-
const saveUser = tokens.includes("--save-user");
|
|
375
|
-
const saveProject = tokens.includes("--save-project");
|
|
376
|
-
const extra = tokens.slice(1).filter((token) => token !== "--save-user" && token !== "--save-project");
|
|
377
|
-
const currentResolution = resolveCursorStatusRuntime(ctx);
|
|
378
|
-
if (!raw) {
|
|
379
|
-
ctx.ui.notify(
|
|
380
|
-
currentResolution.kind === "invalid"
|
|
381
|
-
? `${currentResolution.message} ${usage}`
|
|
382
|
-
: `Cursor runtime is ${formatResolvedCursorRuntime(currentResolution.runtime)}. ${usage}`,
|
|
383
|
-
currentResolution.kind === "invalid" ? "error" : "info",
|
|
384
|
-
);
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
if ((raw !== "local" && raw !== "cloud") || extra.length > 0 || (saveUser && saveProject)) {
|
|
388
|
-
ctx.ui.notify(`Invalid Cursor runtime arguments. ${usage}`, "error");
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
if (currentResolution.kind === "invalid") {
|
|
392
|
-
ctx.ui.notify(`${currentResolution.message} Fix the explicit override before changing the session runtime.`, "error");
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
if (saveProject && (getCursorSessionCwd() !== ctx.cwd || !getCursorSessionProjectTrusted())) {
|
|
396
|
-
ctx.ui.notify(
|
|
397
|
-
"Cannot save Cursor project config without explicit project-trust provenance. Ensure .pi/settings.json or another Pi project resource exists, trust the project, then restart pi; or restart with --approve. Project-local package installs must use --approve on every run that reads or writes .pi/cursor-sdk.json.",
|
|
398
|
-
"error",
|
|
399
|
-
);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
const cloudAcknowledged = raw === "cloud" && await confirmCloudAcknowledgement(
|
|
403
|
-
ctx,
|
|
404
|
-
resolveEffectiveCursorConfigForContext(ctx).cloud.acknowledged.value,
|
|
405
|
-
);
|
|
406
|
-
if (raw === "cloud" && !cloudAcknowledged) return;
|
|
407
|
-
if (saveUser || saveProject) {
|
|
408
|
-
try {
|
|
409
|
-
if (saveUser) {
|
|
410
|
-
updateCursorSdkConfig(
|
|
411
|
-
getCursorSdkUserConfigPath(),
|
|
412
|
-
(current) => mergeCursorSdkConfigForUpdate(current, {
|
|
413
|
-
runtime: raw,
|
|
414
|
-
...(cloudAcknowledged ? { cloud: { acknowledged: true } } : {}),
|
|
415
|
-
}),
|
|
416
|
-
{ newFileMode: 0o600 },
|
|
417
|
-
);
|
|
418
|
-
} else {
|
|
419
|
-
updateCursorSdkConfig(
|
|
420
|
-
getCursorSdkProjectConfigPath(ctx.cwd),
|
|
421
|
-
(current) => mergeCursorSdkConfigForUpdate(current, { runtime: raw }),
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
} catch (error) {
|
|
425
|
-
const effectiveResolution = resolveCursorStatusRuntime(ctx);
|
|
426
|
-
refreshStatus(ctx);
|
|
427
|
-
const effective = effectiveResolution.kind === "valid"
|
|
428
|
-
? ` Effective runtime remains ${formatResolvedCursorRuntime(effectiveResolution.runtime)}.`
|
|
429
|
-
: ` ${effectiveResolution.message}`;
|
|
430
|
-
ctx.ui.notify(
|
|
431
|
-
`Failed to save Cursor runtime preference to ${saveUser ? "user" : "project"} config: ${error instanceof Error ? error.message : String(error)}.${effective}`,
|
|
432
|
-
"error",
|
|
433
|
-
);
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
try {
|
|
438
|
-
persistCursorRuntimePreference(pi, raw, cloudAcknowledged);
|
|
439
|
-
} catch (error) {
|
|
440
|
-
const effectiveResolution = resolveCursorStatusRuntime(ctx);
|
|
441
|
-
refreshStatus(ctx);
|
|
442
|
-
const effective = effectiveResolution.kind === "valid"
|
|
443
|
-
? ` Effective runtime is ${formatResolvedCursorRuntime(effectiveResolution.runtime)}.`
|
|
444
|
-
: ` ${effectiveResolution.message}`;
|
|
445
|
-
const persisted = saveUser
|
|
446
|
-
? "User config was saved, but persisting the session runtime entry failed."
|
|
447
|
-
: saveProject
|
|
448
|
-
? "Project config was saved, but persisting the session runtime entry failed."
|
|
449
|
-
: "Persisting the session runtime entry failed.";
|
|
450
|
-
ctx.ui.notify(
|
|
451
|
-
`${persisted} ${error instanceof Error ? error.message : String(error)}.${effective}`,
|
|
452
|
-
"error",
|
|
453
|
-
);
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
const effectiveResolution = resolveCursorStatusRuntime(ctx);
|
|
457
|
-
refreshStatus(ctx);
|
|
458
|
-
const saved = saveUser
|
|
459
|
-
? " Saved to user config."
|
|
460
|
-
: saveProject
|
|
461
|
-
? " Saved to project config; cloud acknowledgement remains session/user-scoped."
|
|
462
|
-
: "";
|
|
463
|
-
const effective = effectiveResolution.kind === "valid"
|
|
464
|
-
? ` Effective runtime is ${formatResolvedCursorRuntime(effectiveResolution.runtime)}.`
|
|
465
|
-
: ` ${effectiveResolution.message}`;
|
|
466
|
-
ctx.ui.notify(
|
|
467
|
-
raw === "cloud"
|
|
468
|
-
? `Cursor runtime request saved for this session and cloud risk acknowledged.${effective}${saved}`
|
|
469
|
-
: `Cursor runtime request saved for this session.${effective}${saved}`,
|
|
470
|
-
"info",
|
|
471
|
-
);
|
|
472
|
-
},
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export function registerCursorCloudRuntimeControls(
|
|
477
|
-
pi: CursorRuntimeStateExtensionApi,
|
|
478
|
-
options: { refreshStatus: CursorStatusRefresh },
|
|
479
|
-
): void {
|
|
480
|
-
registerCursorCloudLifecycleLedger(pi);
|
|
481
|
-
registerCursorRuntimeFlags(pi);
|
|
482
|
-
registerCursorRuntimeCommand(pi, options.refreshStatus);
|
|
483
|
-
pi.registerCommand("cursor-cloud", {
|
|
484
|
-
description: "List, archive, or delete recorded Cursor cloud agents for this session branch",
|
|
485
|
-
handler: async (args, ctx) => {
|
|
486
|
-
await runCursorCloudLifecycleCommand(pi, args, ctx);
|
|
487
|
-
},
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
|
|
491
154
|
export function resetCursorRuntimeStateForTests(): void {
|
|
492
155
|
cliCursorSnapshot = { config: {} };
|
|
493
156
|
cliLocalForceConsumed = false;
|
|
494
157
|
envLocalForceConsumed = false;
|
|
495
|
-
sessionCursorRuntime = undefined;
|
|
496
|
-
sessionCursorCloudAcknowledged = false;
|
|
497
158
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { SDKAgent } from "@cursor/sdk";
|
|
2
|
-
import type { CursorRuntime } from "./cursor-config.js";
|
|
3
2
|
import { asRecord, getArray, getString } from "./cursor-record-utils.js";
|
|
4
3
|
import { readCursorSdkTurnUsage, type CursorSdkTurnUsage } from "./cursor-usage-accounting.js";
|
|
5
4
|
|
|
@@ -9,10 +8,6 @@ const BILLED_USAGE_TIMEOUT_MS = 5000;
|
|
|
9
8
|
// Upgrade to session-scoped storage if multi-day processes retain enough agent IDs to matter.
|
|
10
9
|
const seenBilledRunIdsByAgent = new Map<string, Set<string>>();
|
|
11
10
|
|
|
12
|
-
export function isCursorSdkClientMintedRunId(runId: string): boolean {
|
|
13
|
-
return runId.startsWith("run-");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
export function sumCursorSdkTurnUsage(usages: readonly CursorSdkTurnUsage[]): CursorSdkTurnUsage | undefined {
|
|
17
12
|
if (usages.length === 0) return undefined;
|
|
18
13
|
return usages.reduce(
|
|
@@ -52,7 +47,7 @@ function withTimeout<T>(promise: Promise<T>, timeoutMs = BILLED_USAGE_TIMEOUT_MS
|
|
|
52
47
|
|
|
53
48
|
export function selectCursorBilledTurnUsage(
|
|
54
49
|
agentUsage: unknown,
|
|
55
|
-
options: {
|
|
50
|
+
options: { seenRunIds?: ReadonlySet<string> },
|
|
56
51
|
): { turn?: CursorSdkTurnUsage; runIds: string[] } {
|
|
57
52
|
const runs = (getArray(asRecord(agentUsage), "runs") ?? []).flatMap((item) => {
|
|
58
53
|
const record = asRecord(item);
|
|
@@ -60,40 +55,24 @@ export function selectCursorBilledTurnUsage(
|
|
|
60
55
|
const usage = readCursorSdkTurnUsage(record?.usage);
|
|
61
56
|
return runId && usage ? [{ runId, usage }] : [];
|
|
62
57
|
});
|
|
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
58
|
const unseen = runs.filter((run) => !options.seenRunIds?.has(run.runId));
|
|
68
59
|
return { turn: sumCursorSdkTurnUsage(unseen.map((run) => run.usage)), runIds: unseen.map((run) => run.runId) };
|
|
69
60
|
}
|
|
70
61
|
|
|
71
62
|
export async function fetchCursorSdkAgentUsage(
|
|
72
63
|
agent: SDKAgent,
|
|
73
|
-
options: { runtime: CursorRuntime; runId?: string },
|
|
74
64
|
): Promise<unknown | undefined> {
|
|
75
65
|
if (typeof agent.getUsage !== "function") return undefined;
|
|
76
|
-
|
|
77
|
-
options.runtime === "cloud" && options.runId && isCursorSdkClientMintedRunId(options.runId)
|
|
78
|
-
? { runId: options.runId }
|
|
79
|
-
: undefined;
|
|
80
|
-
return withTimeout(Promise.resolve(agent.getUsage(query)));
|
|
66
|
+
return withTimeout(Promise.resolve(agent.getUsage()));
|
|
81
67
|
}
|
|
82
68
|
|
|
83
69
|
export async function attachCursorSdkBilledTurnUsage(options: {
|
|
84
70
|
agent: SDKAgent;
|
|
85
71
|
agentId: string;
|
|
86
|
-
runtime: CursorRuntime;
|
|
87
|
-
runId?: string;
|
|
88
72
|
}): Promise<{ agentUsage?: unknown; turn?: CursorSdkTurnUsage }> {
|
|
89
|
-
const agentUsage = await fetchCursorSdkAgentUsage(options.agent
|
|
90
|
-
runtime: options.runtime,
|
|
91
|
-
runId: options.runId,
|
|
92
|
-
});
|
|
73
|
+
const agentUsage = await fetchCursorSdkAgentUsage(options.agent);
|
|
93
74
|
if (!agentUsage) return {};
|
|
94
75
|
const selected = selectCursorBilledTurnUsage(agentUsage, {
|
|
95
|
-
runtime: options.runtime,
|
|
96
|
-
runId: options.runtime === "cloud" ? options.runId : undefined,
|
|
97
76
|
seenRunIds: peekCursorBilledUsageRunIds(options.agentId),
|
|
98
77
|
});
|
|
99
78
|
rememberCursorBilledUsageRunIds(options.agentId, selected.runIds);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
4
|
+
|
|
5
|
+
const RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
6
|
+
const TREE_SITTER_VENDOR_ENV = "CURSOR_TREE_SITTER_VENDOR_DIR";
|
|
7
|
+
|
|
8
|
+
function cursorSdkPlatformPackageName(): string {
|
|
9
|
+
return `@cursor/sdk-${process.platform}-${process.arch}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function resolveCursorSdkPlatformPackageDir(
|
|
13
|
+
fromModuleUrl: string | URL = import.meta.url,
|
|
14
|
+
): string | undefined {
|
|
15
|
+
try {
|
|
16
|
+
const require = createRequire(fromModuleUrl);
|
|
17
|
+
const sdkEntry = require.resolve("@cursor/sdk");
|
|
18
|
+
return dirname(
|
|
19
|
+
require.resolve(`${cursorSdkPlatformPackageName()}/package.json`, {
|
|
20
|
+
paths: [dirname(sdkEntry)],
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
} catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function resolveCursorSdkPlatformBinary(
|
|
29
|
+
binaryName: string,
|
|
30
|
+
fromModuleUrl: string | URL = import.meta.url,
|
|
31
|
+
): string | undefined {
|
|
32
|
+
try {
|
|
33
|
+
const packageDirectory = resolveCursorSdkPlatformPackageDir(fromModuleUrl);
|
|
34
|
+
if (!packageDirectory) return undefined;
|
|
35
|
+
const binaryPath = join(packageDirectory, "bin", binaryName);
|
|
36
|
+
accessSync(binaryPath, constants.X_OK);
|
|
37
|
+
return binaryPath;
|
|
38
|
+
} catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function resolveBundledCursorRipgrepPath(
|
|
44
|
+
fromModuleUrl: string | URL = import.meta.url,
|
|
45
|
+
): string | undefined {
|
|
46
|
+
return resolveCursorSdkPlatformBinary(process.platform === "win32" ? "rg.exe" : "rg", fromModuleUrl);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function ensureCursorRipgrepPath(): string | undefined {
|
|
50
|
+
const configuredPath = process.env[RIPGREP_ENV];
|
|
51
|
+
if (configuredPath && isAbsolute(configuredPath)) return configuredPath;
|
|
52
|
+
|
|
53
|
+
const bundledPath = resolveBundledCursorRipgrepPath();
|
|
54
|
+
if (bundledPath) process.env[RIPGREP_ENV] = bundledPath;
|
|
55
|
+
return bundledPath;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function resolveBundledCursorTreeSitterVendorDir(
|
|
59
|
+
fromModuleUrl: string | URL = import.meta.url,
|
|
60
|
+
): string | undefined {
|
|
61
|
+
const packageDirectory = resolveCursorSdkPlatformPackageDir(fromModuleUrl);
|
|
62
|
+
if (!packageDirectory) return undefined;
|
|
63
|
+
const vendorDir = join(packageDirectory, "vendor");
|
|
64
|
+
if (!existsSync(join(vendorDir, "tree-sitter", "index.js"))) return undefined;
|
|
65
|
+
return vendorDir;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function ensureCursorTreeSitterVendorDir(): string | undefined {
|
|
69
|
+
const configuredPath = process.env[TREE_SITTER_VENDOR_ENV];
|
|
70
|
+
if (configuredPath && isAbsolute(configuredPath)) return configuredPath;
|
|
71
|
+
|
|
72
|
+
const bundledPath = resolveBundledCursorTreeSitterVendorDir();
|
|
73
|
+
if (bundledPath) process.env[TREE_SITTER_VENDOR_ENV] = bundledPath;
|
|
74
|
+
return bundledPath;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function resolveBundledCursorSandboxPath(
|
|
78
|
+
fromModuleUrl: string | URL = import.meta.url,
|
|
79
|
+
): string | undefined {
|
|
80
|
+
return resolveCursorSdkPlatformBinary(
|
|
81
|
+
process.platform === "win32" ? "cursorsandbox.exe" : "cursorsandbox",
|
|
82
|
+
fromModuleUrl,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The SDK finds `cursorsandbox` by walking from `process.argv[1]`, not from
|
|
88
|
+
* `require.resolve`. Point that walk at the installed platform package for the
|
|
89
|
+
* duration of local `Agent.create` / `Agent.resume`.
|
|
90
|
+
*/
|
|
91
|
+
export async function runWithCursorSdkPlatformPackageVisible<T>(
|
|
92
|
+
run: () => Promise<T>,
|
|
93
|
+
fromModuleUrl: string | URL = import.meta.url,
|
|
94
|
+
): Promise<T> {
|
|
95
|
+
const packageDirectory = resolveCursorSdkPlatformPackageDir(fromModuleUrl);
|
|
96
|
+
if (!packageDirectory) return run();
|
|
97
|
+
const hostEntry = join(packageDirectory, "package.json");
|
|
98
|
+
if (!existsSync(hostEntry)) return run();
|
|
99
|
+
const previousArgv1 = process.argv[1];
|
|
100
|
+
process.argv[1] = hostEntry;
|
|
101
|
+
try {
|
|
102
|
+
return await run();
|
|
103
|
+
} finally {
|
|
104
|
+
if (process.argv[1] === hostEntry) process.argv[1] = previousArgv1;
|
|
105
|
+
}
|
|
106
|
+
}
|