@tickernelz/paperclip-pro-adapter-cursor-local 2026.925.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 (74) hide show
  1. package/LICENSE +22 -0
  2. package/dist/cli/format-event.d.ts +2 -0
  3. package/dist/cli/format-event.d.ts.map +1 -0
  4. package/dist/cli/format-event.js +296 -0
  5. package/dist/cli/format-event.js.map +1 -0
  6. package/dist/cli/index.d.ts +2 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +2 -0
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +102 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/server/execute.d.ts +15 -0
  15. package/dist/server/execute.d.ts.map +1 -0
  16. package/dist/server/execute.js +640 -0
  17. package/dist/server/execute.js.map +1 -0
  18. package/dist/server/execute.remote.test.d.ts +2 -0
  19. package/dist/server/execute.remote.test.d.ts.map +1 -0
  20. package/dist/server/execute.remote.test.js +284 -0
  21. package/dist/server/execute.remote.test.js.map +1 -0
  22. package/dist/server/execute.test.d.ts +2 -0
  23. package/dist/server/execute.test.d.ts.map +1 -0
  24. package/dist/server/execute.test.js +294 -0
  25. package/dist/server/execute.test.js.map +1 -0
  26. package/dist/server/index.d.ts +7 -0
  27. package/dist/server/index.d.ts.map +1 -0
  28. package/dist/server/index.js +62 -0
  29. package/dist/server/index.js.map +1 -0
  30. package/dist/server/parse.d.ts +13 -0
  31. package/dist/server/parse.d.ts.map +1 -0
  32. package/dist/server/parse.js +139 -0
  33. package/dist/server/parse.js.map +1 -0
  34. package/dist/server/remote-command.d.ts +20 -0
  35. package/dist/server/remote-command.d.ts.map +1 -0
  36. package/dist/server/remote-command.js +172 -0
  37. package/dist/server/remote-command.js.map +1 -0
  38. package/dist/server/remote-command.test.d.ts +2 -0
  39. package/dist/server/remote-command.test.d.ts.map +1 -0
  40. package/dist/server/remote-command.test.js +123 -0
  41. package/dist/server/remote-command.test.js.map +1 -0
  42. package/dist/server/skills.d.ts +8 -0
  43. package/dist/server/skills.d.ts.map +1 -0
  44. package/dist/server/skills.js +69 -0
  45. package/dist/server/skills.js.map +1 -0
  46. package/dist/server/test.d.ts +10 -0
  47. package/dist/server/test.d.ts.map +1 -0
  48. package/dist/server/test.js +334 -0
  49. package/dist/server/test.js.map +1 -0
  50. package/dist/server/test.test.d.ts +2 -0
  51. package/dist/server/test.test.d.ts.map +1 -0
  52. package/dist/server/test.test.js +116 -0
  53. package/dist/server/test.test.js.map +1 -0
  54. package/dist/shared/stream.d.ts +5 -0
  55. package/dist/shared/stream.d.ts.map +1 -0
  56. package/dist/shared/stream.js +13 -0
  57. package/dist/shared/stream.js.map +1 -0
  58. package/dist/shared/trust.d.ts +2 -0
  59. package/dist/shared/trust.d.ts.map +1 -0
  60. package/dist/shared/trust.js +7 -0
  61. package/dist/shared/trust.js.map +1 -0
  62. package/dist/ui/build-config.d.ts +3 -0
  63. package/dist/ui/build-config.d.ts.map +1 -0
  64. package/dist/ui/build-config.js +36 -0
  65. package/dist/ui/build-config.js.map +1 -0
  66. package/dist/ui/index.d.ts +3 -0
  67. package/dist/ui/index.d.ts.map +1 -0
  68. package/dist/ui/index.js +3 -0
  69. package/dist/ui/index.js.map +1 -0
  70. package/dist/ui/parse-stdout.d.ts +3 -0
  71. package/dist/ui/parse-stdout.d.ts.map +1 -0
  72. package/dist/ui/parse-stdout.js +378 -0
  73. package/dist/ui/parse-stdout.js.map +1 -0
  74. package/package.json +58 -0
@@ -0,0 +1,334 @@
1
+ import { asNumber, asString, asStringArray, parseObject, ensurePathInEnv, } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
2
+ import { ensureAdapterExecutionTargetCommandResolvable, ensureAdapterExecutionTargetDirectory, maybeRunSandboxInstallCommand, runAdapterExecutionTargetProcess, describeAdapterExecutionTarget, resolveAdapterExecutionTargetCwd, } from "@tickernelz/paperclip-pro-adapter-utils/execution-target";
3
+ import fs from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { DEFAULT_CURSOR_LOCAL_MODEL, SANDBOX_INSTALL_COMMAND } from "../index.js";
7
+ import { parseCursorJsonl } from "./parse.js";
8
+ import { isDefaultCursorCommand, prepareCursorSandboxCommand } from "./remote-command.js";
9
+ import { hasCursorTrustBypassArg } from "../shared/trust.js";
10
+ function summarizeStatus(checks) {
11
+ if (checks.some((check) => check.level === "error"))
12
+ return "fail";
13
+ if (checks.some((check) => check.level === "warn"))
14
+ return "warn";
15
+ return "pass";
16
+ }
17
+ function isNonEmpty(value) {
18
+ return typeof value === "string" && value.trim().length > 0;
19
+ }
20
+ function firstNonEmptyLine(text) {
21
+ return (text
22
+ .split(/\r?\n/)
23
+ .map((line) => line.trim())
24
+ .find(Boolean) ?? "");
25
+ }
26
+ function summarizeProbeDetail(stdout, stderr, parsedError) {
27
+ const raw = parsedError?.trim() || firstNonEmptyLine(stderr) || firstNonEmptyLine(stdout);
28
+ if (!raw)
29
+ return null;
30
+ const clean = raw.replace(/\s+/g, " ").trim();
31
+ const max = 240;
32
+ return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean;
33
+ }
34
+ export function cursorConfigPath(cursorHome) {
35
+ return path.join(cursorHome ?? path.join(os.homedir(), ".cursor"), "cli-config.json");
36
+ }
37
+ export async function readCursorAuthInfo(cursorHome) {
38
+ let raw;
39
+ try {
40
+ raw = await fs.readFile(cursorConfigPath(cursorHome), "utf8");
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ let parsed;
46
+ try {
47
+ parsed = JSON.parse(raw);
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ if (typeof parsed !== "object" || parsed === null)
53
+ return null;
54
+ const obj = parsed;
55
+ const authInfo = obj.authInfo;
56
+ if (typeof authInfo !== "object" || authInfo === null)
57
+ return null;
58
+ const info = authInfo;
59
+ const email = typeof info.email === "string" && info.email.trim().length > 0 ? info.email.trim() : null;
60
+ const displayName = typeof info.displayName === "string" && info.displayName.trim().length > 0 ? info.displayName.trim() : null;
61
+ const userId = typeof info.userId === "number" ? info.userId : null;
62
+ if (!email && !displayName && userId == null)
63
+ return null;
64
+ return { email, displayName, userId };
65
+ }
66
+ const CURSOR_AUTH_REQUIRED_RE = /(?:authentication\s+required|not\s+authenticated|not\s+logged\s+in|unauthorized|invalid(?:\s+or\s+missing)?\s+api(?:[_\s-]?key)?|cursor[_\s-]?api[_\s-]?key|run\s+'?agent\s+login'?\s+first|api(?:[_\s-]?key)?(?:\s+is)?\s+required)/i;
67
+ export async function testEnvironment(ctx) {
68
+ const checks = [];
69
+ const config = parseObject(ctx.config);
70
+ let command = asString(config.command, "agent");
71
+ const target = ctx.executionTarget ?? null;
72
+ const targetIsRemote = target?.kind === "remote";
73
+ const targetIsSandbox = target?.kind === "remote" && target.transport === "sandbox";
74
+ const cwd = resolveAdapterExecutionTargetCwd(target, asString(config.cwd, ""), process.cwd());
75
+ const targetLabel = targetIsRemote
76
+ ? ctx.environmentName ?? describeAdapterExecutionTarget(target)
77
+ : null;
78
+ const runId = `cursor-envtest-${Date.now()}-${Math.random().toString(16).slice(2)}`;
79
+ if (targetLabel) {
80
+ checks.push({
81
+ code: "cursor_environment_target",
82
+ level: "info",
83
+ message: `Probing inside environment: ${targetLabel}`,
84
+ });
85
+ }
86
+ try {
87
+ await ensureAdapterExecutionTargetDirectory(runId, target, cwd, {
88
+ cwd,
89
+ env: {},
90
+ createIfMissing: true,
91
+ });
92
+ checks.push({
93
+ code: "cursor_cwd_valid",
94
+ level: "info",
95
+ message: `Working directory is valid: ${cwd}`,
96
+ });
97
+ }
98
+ catch (err) {
99
+ checks.push({
100
+ code: "cursor_cwd_invalid",
101
+ level: "error",
102
+ message: err instanceof Error ? err.message : "Invalid working directory",
103
+ detail: cwd,
104
+ });
105
+ }
106
+ const envConfig = parseObject(config.env);
107
+ let env = {};
108
+ for (const [key, value] of Object.entries(envConfig)) {
109
+ if (typeof value === "string")
110
+ env[key] = value;
111
+ }
112
+ const sandboxCommand = await prepareCursorSandboxCommand({
113
+ runId,
114
+ target,
115
+ command,
116
+ cwd,
117
+ env,
118
+ timeoutSec: 45,
119
+ graceSec: 5,
120
+ });
121
+ command = sandboxCommand.command;
122
+ env = sandboxCommand.env;
123
+ const installCheck = await maybeRunSandboxInstallCommand({
124
+ runId,
125
+ target,
126
+ adapterKey: "cursor",
127
+ installCommand: SANDBOX_INSTALL_COMMAND,
128
+ detectCommand: command,
129
+ env,
130
+ });
131
+ if (installCheck)
132
+ checks.push(installCheck);
133
+ const finalSandboxCommand = await prepareCursorSandboxCommand({
134
+ runId,
135
+ target,
136
+ command,
137
+ cwd,
138
+ env,
139
+ remoteSystemHomeDirHint: sandboxCommand.remoteSystemHomeDir,
140
+ timeoutSec: 45,
141
+ graceSec: 5,
142
+ });
143
+ command = finalSandboxCommand.command;
144
+ env = finalSandboxCommand.env;
145
+ const runtimeEnv = ensurePathInEnv({ ...process.env, ...env });
146
+ try {
147
+ await ensureAdapterExecutionTargetCommandResolvable(command, target, cwd, runtimeEnv);
148
+ checks.push({
149
+ code: "cursor_command_resolvable",
150
+ level: "info",
151
+ message: `Command is executable: ${command}`,
152
+ });
153
+ }
154
+ catch (err) {
155
+ checks.push({
156
+ code: "cursor_command_unresolvable",
157
+ level: "error",
158
+ message: err instanceof Error ? err.message : "Command is not executable",
159
+ detail: command,
160
+ });
161
+ }
162
+ const configCursorApiKey = env.CURSOR_API_KEY;
163
+ const hostCursorApiKey = targetIsRemote ? undefined : process.env.CURSOR_API_KEY;
164
+ if (isNonEmpty(configCursorApiKey) || isNonEmpty(hostCursorApiKey)) {
165
+ const source = isNonEmpty(configCursorApiKey) ? "adapter config env" : "server environment";
166
+ checks.push({
167
+ code: "cursor_api_key_present",
168
+ level: "info",
169
+ message: "CURSOR_API_KEY is set for Cursor authentication.",
170
+ detail: `Detected in ${source}.`,
171
+ });
172
+ }
173
+ else if (!targetIsRemote) {
174
+ const cursorHome = isNonEmpty(env.CURSOR_HOME) ? env.CURSOR_HOME : undefined;
175
+ const cursorAuth = await readCursorAuthInfo(cursorHome).catch(() => null);
176
+ if (cursorAuth) {
177
+ checks.push({
178
+ code: "cursor_native_auth_present",
179
+ level: "info",
180
+ message: "Cursor is authenticated via `agent login`.",
181
+ detail: cursorAuth.email
182
+ ? `Logged in as ${cursorAuth.email}.`
183
+ : `Credentials found in ${cursorConfigPath(cursorHome)}.`,
184
+ });
185
+ }
186
+ else {
187
+ checks.push({
188
+ code: "cursor_api_key_missing",
189
+ level: "warn",
190
+ message: "CURSOR_API_KEY is not set. Cursor runs may fail until authentication is configured.",
191
+ hint: "Set CURSOR_API_KEY in adapter env or run `agent login`.",
192
+ });
193
+ }
194
+ }
195
+ const canRunProbe = checks.every((check) => check.code !== "cursor_cwd_invalid" && check.code !== "cursor_command_unresolvable");
196
+ if (canRunProbe) {
197
+ if (!isDefaultCursorCommand(command)) {
198
+ checks.push({
199
+ code: "cursor_hello_probe_skipped_custom_command",
200
+ level: "info",
201
+ message: "Skipped hello probe because command is not a default Cursor CLI entrypoint.",
202
+ detail: command,
203
+ hint: "Use `agent` or `cursor-agent` to run the automatic installation and auth probe.",
204
+ });
205
+ }
206
+ else {
207
+ // Cursor's `agent` binary still pays cold-start overhead in container
208
+ // sandboxes, but standard-2 probes no longer need a 120s version budget.
209
+ const versionProbeTimeoutSec = Math.max(1, asNumber(config.versionProbeTimeoutSec, targetIsSandbox ? 60 : 45));
210
+ const versionProbe = await runAdapterExecutionTargetProcess(runId, target, command, ["--version"], {
211
+ cwd,
212
+ env,
213
+ timeoutSec: versionProbeTimeoutSec,
214
+ graceSec: 5,
215
+ onLog: async () => { },
216
+ });
217
+ const versionDetail = summarizeProbeDetail(versionProbe.stdout, versionProbe.stderr, null);
218
+ if (versionProbe.timedOut) {
219
+ checks.push({
220
+ code: "cursor_version_probe_timed_out",
221
+ level: "error",
222
+ message: "Cursor version probe timed out.",
223
+ hint: "Run `agent --version` manually in this working directory to confirm the installed CLI is reachable non-interactively.",
224
+ });
225
+ }
226
+ else if ((versionProbe.exitCode ?? 1) === 0) {
227
+ checks.push({
228
+ code: "cursor_version_probe_passed",
229
+ level: "info",
230
+ message: "Cursor version probe succeeded.",
231
+ ...(versionDetail ? { detail: versionDetail } : {}),
232
+ });
233
+ }
234
+ else {
235
+ checks.push({
236
+ code: "cursor_version_probe_failed",
237
+ level: "error",
238
+ message: "Cursor version probe failed.",
239
+ ...(versionDetail ? { detail: versionDetail } : {}),
240
+ hint: "Run `agent --version` manually in this working directory to confirm the installed CLI is reachable non-interactively.",
241
+ });
242
+ }
243
+ const canRunHelloProbe = checks.every((check) => check.code !== "cursor_version_probe_failed" &&
244
+ check.code !== "cursor_version_probe_timed_out");
245
+ if (!canRunHelloProbe) {
246
+ return {
247
+ adapterType: ctx.adapterType,
248
+ status: summarizeStatus(checks),
249
+ checks,
250
+ testedAt: new Date().toISOString(),
251
+ };
252
+ }
253
+ const model = asString(config.model, DEFAULT_CURSOR_LOCAL_MODEL).trim();
254
+ const extraArgs = (() => {
255
+ const fromExtraArgs = asStringArray(config.extraArgs);
256
+ if (fromExtraArgs.length > 0)
257
+ return fromExtraArgs;
258
+ return asStringArray(config.args);
259
+ })();
260
+ const autoTrustEnabled = !hasCursorTrustBypassArg(extraArgs);
261
+ const args = ["-p", "--mode", "ask", "--output-format", "json", "--workspace", cwd];
262
+ if (model)
263
+ args.push("--model", model);
264
+ if (autoTrustEnabled)
265
+ args.push("--yolo");
266
+ if (extraArgs.length > 0)
267
+ args.push(...extraArgs);
268
+ args.push("Respond with hello.");
269
+ // Sandbox bridges still add cursor CLI cold-start overhead, but the
270
+ // standard-2 tier now completes probes fast enough that 90s is ample.
271
+ const helloProbeTimeoutSec = Math.max(1, asNumber(config.helloProbeTimeoutSec, targetIsSandbox ? 90 : 45));
272
+ const probe = await runAdapterExecutionTargetProcess(runId, target, command, args, {
273
+ cwd,
274
+ env,
275
+ timeoutSec: helloProbeTimeoutSec,
276
+ graceSec: 5,
277
+ onLog: async () => { },
278
+ });
279
+ const parsed = parseCursorJsonl(probe.stdout);
280
+ const detail = summarizeProbeDetail(probe.stdout, probe.stderr, parsed.errorMessage);
281
+ const authEvidence = `${parsed.errorMessage ?? ""}\n${probe.stdout}\n${probe.stderr}`.trim();
282
+ if (probe.timedOut) {
283
+ checks.push({
284
+ code: "cursor_hello_probe_timed_out",
285
+ level: "warn",
286
+ message: "Cursor hello probe timed out.",
287
+ hint: "Retry the probe. If this persists, verify `agent -p --mode ask --output-format json \"Respond with hello.\"` manually.",
288
+ });
289
+ }
290
+ else if ((probe.exitCode ?? 1) === 0) {
291
+ const summary = parsed.summary.trim();
292
+ const hasHello = /\bhello\b/i.test(summary);
293
+ checks.push({
294
+ code: hasHello ? "cursor_hello_probe_passed" : "cursor_hello_probe_unexpected_output",
295
+ level: hasHello ? "info" : "warn",
296
+ message: hasHello
297
+ ? "Cursor hello probe succeeded."
298
+ : "Cursor probe ran but did not return `hello` as expected.",
299
+ ...(summary ? { detail: summary.replace(/\s+/g, " ").trim().slice(0, 240) } : {}),
300
+ ...(hasHello
301
+ ? {}
302
+ : {
303
+ hint: "Try `agent -p --mode ask --output-format json \"Respond with hello.\"` manually to inspect full output.",
304
+ }),
305
+ });
306
+ }
307
+ else if (CURSOR_AUTH_REQUIRED_RE.test(authEvidence)) {
308
+ checks.push({
309
+ code: "cursor_hello_probe_auth_required",
310
+ level: "warn",
311
+ message: "Cursor CLI is installed, but authentication is not ready.",
312
+ ...(detail ? { detail } : {}),
313
+ hint: "Run `agent login` or configure CURSOR_API_KEY in adapter env/shell, then retry the probe.",
314
+ });
315
+ }
316
+ else {
317
+ checks.push({
318
+ code: "cursor_hello_probe_failed",
319
+ level: "error",
320
+ message: "Cursor hello probe failed.",
321
+ ...(detail ? { detail } : {}),
322
+ hint: "Run `agent -p --mode ask --output-format json \"Respond with hello.\"` manually in this working directory to debug.",
323
+ });
324
+ }
325
+ }
326
+ }
327
+ return {
328
+ adapterType: ctx.adapterType,
329
+ status: summarizeStatus(checks),
330
+ checks,
331
+ testedAt: new Date().toISOString(),
332
+ };
333
+ }
334
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/server/test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.test.d.ts","sourceRoot":"","sources":["../../src/server/test.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,116 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { describe, expect, it } from "vitest";
5
+ import { runChildProcess } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
6
+ import { SANDBOX_INSTALL_COMMAND } from "../index.js";
7
+ import { testEnvironment } from "./test.js";
8
+ function buildFakeAgentScript() {
9
+ return `#!/bin/sh
10
+ if [ "$1" = "--version" ]; then
11
+ printf '%s\\n' 'Cursor Agent 1.2.3'
12
+ exit 0
13
+ fi
14
+ printf '%s\\n' '{"type":"system","subtype":"init","session_id":"cursor-session-envtest-1","model":"auto"}'
15
+ printf '%s\\n' '{"type":"assistant","message":{"content":[{"type":"output_text","text":"hello"}]}}'
16
+ printf '%s\\n' '{"type":"result","subtype":"success","session_id":"cursor-session-envtest-1","result":"ok"}'
17
+ `;
18
+ }
19
+ function buildInstallSimulationCommand(commandPath) {
20
+ return [
21
+ `mkdir -p ${JSON.stringify(path.dirname(commandPath))}`,
22
+ `cat > ${JSON.stringify(commandPath)} <<'EOF'`,
23
+ buildFakeAgentScript(),
24
+ "EOF",
25
+ `chmod +x ${JSON.stringify(commandPath)}`,
26
+ ].join("\n");
27
+ }
28
+ function createSandboxRunner(options) {
29
+ let counter = 0;
30
+ const installCommands = [];
31
+ const systemPath = "/usr/bin:/bin";
32
+ return {
33
+ installCommands,
34
+ execute: async (input) => {
35
+ counter += 1;
36
+ const args = [...(input.args ?? [])];
37
+ if (args[1] === SANDBOX_INSTALL_COMMAND) {
38
+ installCommands.push(args[1]);
39
+ args[1] = buildInstallSimulationCommand(options.installCommandPath);
40
+ }
41
+ return await runChildProcess(`cursor-envtest-runner-${counter}`, input.command, args, {
42
+ cwd: input.cwd ?? process.cwd(),
43
+ env: {
44
+ ...(input.env ?? {}),
45
+ HOME: input.env?.HOME ?? options.homeDir,
46
+ PATH: input.env?.PATH ?? systemPath,
47
+ },
48
+ stdin: input.stdin,
49
+ timeoutSec: Math.max(1, Math.ceil((input.timeoutMs ?? 30_000) / 1000)),
50
+ graceSec: 5,
51
+ onLog: input.onLog ?? (async () => { }),
52
+ onSpawn: input.onSpawn
53
+ ? async (meta) => input.onSpawn?.({ pid: meta.pid, startedAt: meta.startedAt })
54
+ : undefined,
55
+ });
56
+ },
57
+ };
58
+ }
59
+ describe("cursor testEnvironment", () => {
60
+ it("re-resolves the installed agent under ~/.cursor/bin and verifies --version before the hello probe", async () => {
61
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), "paperclip-cursor-envtest-"));
62
+ const homeDir = path.join(root, "home");
63
+ const workspace = path.join(root, "workspace");
64
+ const remoteWorkspace = path.join(root, "remote-workspace");
65
+ const agentPath = path.join(homeDir, ".cursor", "bin", "agent");
66
+ await fs.mkdir(workspace, { recursive: true });
67
+ await fs.mkdir(remoteWorkspace, { recursive: true });
68
+ const runner = createSandboxRunner({
69
+ homeDir,
70
+ installCommandPath: agentPath,
71
+ });
72
+ try {
73
+ const result = await testEnvironment({
74
+ companyId: "company-1",
75
+ adapterType: "cursor",
76
+ config: {
77
+ command: "agent",
78
+ cwd: workspace,
79
+ env: {
80
+ PATH: "/usr/bin:/bin",
81
+ },
82
+ },
83
+ executionTarget: {
84
+ kind: "remote",
85
+ transport: "sandbox",
86
+ shellCommand: "bash",
87
+ remoteCwd: remoteWorkspace,
88
+ runner,
89
+ timeoutMs: 30_000,
90
+ },
91
+ });
92
+ expect(result.status).toBe("pass");
93
+ expect(runner.installCommands).toEqual([SANDBOX_INSTALL_COMMAND]);
94
+ expect(result.checks).toEqual(expect.arrayContaining([
95
+ expect.objectContaining({
96
+ code: "cursor_command_resolvable",
97
+ level: "info",
98
+ message: `Command is executable: ${agentPath}`,
99
+ }),
100
+ expect.objectContaining({
101
+ code: "cursor_version_probe_passed",
102
+ level: "info",
103
+ detail: "Cursor Agent 1.2.3",
104
+ }),
105
+ expect.objectContaining({
106
+ code: "cursor_hello_probe_passed",
107
+ level: "info",
108
+ }),
109
+ ]));
110
+ }
111
+ finally {
112
+ await fs.rm(root, { recursive: true, force: true });
113
+ }
114
+ });
115
+ });
116
+ //# sourceMappingURL=test.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.test.js","sourceRoot":"","sources":["../../src/server/test.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function normalizeCursorStreamLine(rawLine: string): {
2
+ stream: "stdout" | "stderr" | null;
3
+ line: string;
4
+ };
5
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/shared/stream.ts"],"names":[],"mappings":"AAAA,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG;IAC1D,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd,CAYA"}
@@ -0,0 +1,13 @@
1
+ export function normalizeCursorStreamLine(rawLine) {
2
+ const trimmed = rawLine.trim();
3
+ if (!trimmed)
4
+ return { stream: null, line: "" };
5
+ const prefixed = trimmed.match(/^(stdout|stderr)\s*[:=]?\s*([\[{].*)$/i);
6
+ if (!prefixed) {
7
+ return { stream: null, line: trimmed };
8
+ }
9
+ const stream = prefixed[1]?.toLowerCase() === "stderr" ? "stderr" : "stdout";
10
+ const line = (prefixed[2] ?? "").trim();
11
+ return { stream, line };
12
+ }
13
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/shared/stream.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,yBAAyB,CAAC,OAAe;IAIvD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IAEhD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACzE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7E,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function hasCursorTrustBypassArg(args: readonly string[]): boolean;
2
+ //# sourceMappingURL=trust.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../../src/shared/trust.ts"],"names":[],"mappings":"AAAA,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAQxE"}
@@ -0,0 +1,7 @@
1
+ export function hasCursorTrustBypassArg(args) {
2
+ return args.some((arg) => arg === "--trust" ||
3
+ arg === "--yolo" ||
4
+ arg === "-f" ||
5
+ arg.startsWith("--trust="));
6
+ }
7
+ //# sourceMappingURL=trust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust.js","sourceRoot":"","sources":["../../src/shared/trust.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,uBAAuB,CAAC,IAAuB;IAC7D,OAAO,IAAI,CAAC,IAAI,CACd,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,KAAK,SAAS;QACjB,GAAG,KAAK,QAAQ;QAChB,GAAG,KAAK,IAAI;QACZ,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAC7B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { type CreateConfigValues } from "@tickernelz/paperclip-pro-adapter-utils";
2
+ export declare function buildCursorLocalConfig(v: CreateConfigValues): Record<string, unknown>;
3
+ //# sourceMappingURL=build-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-config.d.ts","sourceRoot":"","sources":["../../src/ui/build-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAgBzG,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAcrF"}
@@ -0,0 +1,36 @@
1
+ import { buildAdapterEnvConfig } from "@tickernelz/paperclip-pro-adapter-utils";
2
+ import { DEFAULT_CURSOR_LOCAL_MODEL } from "../index.js";
3
+ function parseCommaArgs(value) {
4
+ return value
5
+ .split(",")
6
+ .map((item) => item.trim())
7
+ .filter(Boolean);
8
+ }
9
+ function normalizeMode(value) {
10
+ const mode = value.trim().toLowerCase();
11
+ if (mode === "plan" || mode === "ask")
12
+ return mode;
13
+ return null;
14
+ }
15
+ export function buildCursorLocalConfig(v) {
16
+ const ac = {};
17
+ if (v.cwd)
18
+ ac.cwd = v.cwd;
19
+ if (v.instructionsFilePath)
20
+ ac.instructionsFilePath = v.instructionsFilePath;
21
+ ac.model = v.model || DEFAULT_CURSOR_LOCAL_MODEL;
22
+ const mode = normalizeMode(v.thinkingEffort);
23
+ if (mode)
24
+ ac.mode = mode;
25
+ ac.timeoutSec = 0;
26
+ ac.graceSec = 15;
27
+ const env = buildAdapterEnvConfig(v.envBindings, v.envVars);
28
+ if (Object.keys(env).length > 0)
29
+ ac.env = env;
30
+ if (v.command)
31
+ ac.command = v.command;
32
+ if (v.extraArgs)
33
+ ac.extraArgs = parseCommaArgs(v.extraArgs);
34
+ return ac;
35
+ }
36
+ //# sourceMappingURL=build-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-config.js","sourceRoot":"","sources":["../../src/ui/build-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAA2B,MAAM,yCAAyC,CAAC;AACzG,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEzD,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,CAAqB;IAC1D,MAAM,EAAE,GAA4B,EAAE,CAAC;IACvC,IAAI,CAAC,CAAC,GAAG;QAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;IAC1B,IAAI,CAAC,CAAC,oBAAoB;QAAE,EAAE,CAAC,oBAAoB,GAAG,CAAC,CAAC,oBAAoB,CAAC;IAC7E,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,0BAA0B,CAAC;IACjD,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;IAC7C,IAAI,IAAI;QAAE,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC;IACzB,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC;IAClB,EAAE,CAAC,QAAQ,GAAG,EAAE,CAAC;IACjB,MAAM,GAAG,GAAG,qBAAqB,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC;IAC9C,IAAI,CAAC,CAAC,OAAO;QAAE,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;IACtC,IAAI,CAAC,CAAC,SAAS;QAAE,EAAE,CAAC,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC5D,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { parseCursorStdoutLine } from "./parse-stdout.js";
2
+ export { buildCursorLocalConfig } from "./build-config.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { parseCursorStdoutLine } from "./parse-stdout.js";
2
+ export { buildCursorLocalConfig } from "./build-config.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TranscriptEntry } from "@tickernelz/paperclip-pro-adapter-utils";
2
+ export declare function parseCursorStdoutLine(line: string, ts: string): TranscriptEntry[];
3
+ //# sourceMappingURL=parse-stdout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-stdout.d.ts","sourceRoot":"","sources":["../../src/ui/parse-stdout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAwP/E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,eAAe,EAAE,CAmKjF"}