@selesai/code 0.13.9 → 0.13.11
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 +19 -0
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.js +5 -3
- package/dist/extensions/handoff-new.test.ts +26 -1
- package/dist/extensions/handoff-new.ts +8 -0
- package/dist/extensions/herdr-agent-state.ts +310 -0
- package/dist/extensions/package.json +1 -0
- package/dist/extensions/pi-subagents/README.md +0 -6
- package/dist/extensions/pi-subagents/docs/agents.md +1 -114
- package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +1 -12
- package/dist/extensions/pi-subagents/src/extension/tool-description.ts +1 -1
- package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +3 -19
- package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +8 -37
- package/dist/extensions/pi-subagents/src/shared/types.ts +2 -2
- package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +2 -38
- package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +0 -49
- package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +0 -18
- package/dist/modes/rpc/rpc-client.d.ts +59 -7
- package/dist/modes/rpc/rpc-client.js +65 -11
- package/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/dist/modes/rpc/rpc-mode.js +280 -12
- package/dist/modes/rpc/rpc-types.d.ts +128 -1
- package/dist/skills/improve-codebase/SKILL.md +1 -1
- package/dist/skills/planger/SKILL.md +1 -1
- package/dist/skills/workflow/SKILL.md +9 -15
- package/docs/rpc.md +226 -2
- package/package.json +1 -1
- package/dist/extensions/pi-subagents/agents/architect.md +0 -170
- package/dist/extensions/pi-subagents/agents/builder.md +0 -37
- package/dist/extensions/pi-subagents/agents/claude-code-writer.md +0 -15
- package/dist/extensions/pi-subagents/agents/claude-code.md +0 -15
- package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +0 -15
- package/dist/extensions/pi-subagents/agents/codex-exec.md +0 -15
- package/dist/extensions/pi-subagents/agents/commentator.md +0 -37
- package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +0 -14
- package/dist/extensions/pi-subagents/agents/cursor-agent.md +0 -14
- package/dist/extensions/pi-subagents/agents/explorer.md +0 -32
- package/dist/extensions/pi-subagents/agents/recapper.md +0 -31
- package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +0 -129
- package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +0 -129
- package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +0 -114
- package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +0 -52
- package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +0 -55
- package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +0 -53
- package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +0 -57
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +0 -59
- package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +0 -62
- package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +0 -245
- package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +0 -192
- package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +0 -259
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import * as fs from "node:fs";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
import * as path from "node:path";
|
|
5
|
-
import { afterEach, describe, it } from "node:test";
|
|
6
|
-
import { discoverAgents, discoverAgentsAll, resolveAgentName } from "../../src/agents/agents.ts";
|
|
7
|
-
import { CURSOR_AGENT_ADAPTER_ID, CURSOR_AGENT_ENV_ALLOWLIST, CURSOR_AGENT_WRITER_ADAPTER_ID, createCursorAgentJsonlParser, resolveCursorAgentLaunch } from "../../src/runs/shared/cursor-agent-adapter.ts";
|
|
8
|
-
import { externalCliReceiptMetadata, normalizeExternalCliRunnerStatus, resolveExternalCliRunnerStatus } from "../../src/runs/shared/external-cli-contract.ts";
|
|
9
|
-
import { clearExternalCliPreflightCacheForTests } from "../../src/runs/shared/external-cli-preflight.ts";
|
|
10
|
-
import { runExternalCli } from "../../src/runs/shared/external-cli-runner.ts";
|
|
11
|
-
import { buildWorkflowReceipt, readWorkflowReceipt, writeWorkflowReceipt } from "../../src/workflows/workflow-receipt.ts";
|
|
12
|
-
|
|
13
|
-
const tempDirs: string[] = [];
|
|
14
|
-
function tempDir(): string {
|
|
15
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-cursor-agent-"));
|
|
16
|
-
tempDirs.push(dir);
|
|
17
|
-
return dir;
|
|
18
|
-
}
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
clearExternalCliPreflightCacheForTests();
|
|
21
|
-
for (const dir of tempDirs.splice(0)) fs.rmSync(dir, { recursive: true, force: true });
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
function fakeCursorScript(dir: string): string {
|
|
25
|
-
const scriptPath = path.join(dir, "fake-cursor-agent.cjs");
|
|
26
|
-
fs.writeFileSync(scriptPath, String.raw`
|
|
27
|
-
+const fs = require("node:fs");
|
|
28
|
-
+const args = process.argv.slice(2);
|
|
29
|
-
+if (args[0] === "--version") { console.log("2026.08.11-e8db854"); process.exit(0); }
|
|
30
|
-
+if (args[0] === "--help") {
|
|
31
|
-
+ console.log("Start the Cursor Agent --print Has access to all tools, including write and shell --output-format text | json | stream-json --mode <mode> ask: Q&A read-only --sandbox <mode> enabled --workspace <path-or-name> --add-dir <path>");
|
|
32
|
-
+ process.exit(0);
|
|
33
|
-
+}
|
|
34
|
-
+let stdin = "";
|
|
35
|
-
+process.stdin.on("data", chunk => stdin += chunk);
|
|
36
|
-
+process.stdin.on("end", () => {
|
|
37
|
-
+ if (stdin) { console.error("unexpected stdin prompt"); process.exit(2); }
|
|
38
|
-
+ const shortPrompt = args.at(-1) || "";
|
|
39
|
-
+ const match = /^Read the complete handoff from the private file at (.+)\. Follow it and return only the final answer\.$/.exec(shortPrompt);
|
|
40
|
-
+ if (!match) { console.error("unsafe argv prompt"); process.exit(2); }
|
|
41
|
-
+ const prompt = fs.readFileSync(match[1], "utf-8");
|
|
42
|
-
+ if (prompt.includes("hang")) return setInterval(() => {}, 1000);
|
|
43
|
-
+ if (prompt.includes("malformed")) return process.stdout.write("{bad json}\n");
|
|
44
|
-
+ if (prompt.includes("missing-terminal")) return process.stdout.write(JSON.stringify({type:"assistant",message:{content:[{type:"text",text:"partial"}]}}) + "\n");
|
|
45
|
-
+ if (prompt.includes("oversized-tool-call") && !prompt.includes("post-terminal-oversized-tool-call")) process.stdout.write(JSON.stringify({type:"tool_call",subtype:"completed",tool_call:{name:"write",args:"x".repeat(300 * 1024)}}) + "\n");
|
|
46
|
-
+ if (prompt.includes("post-terminal-oversized-tool-call")) return process.stdout.write(JSON.stringify({type:"result",subtype:"success",is_error:false,result:"trusted final result"}) + "\n" + JSON.stringify({type:"tool_call",subtype:"completed",tool_call:{name:"write",args:"x".repeat(300 * 1024)}}) + "\n");
|
|
47
|
-
+ if (prompt.includes("error-event")) return process.stdout.write(JSON.stringify({type:"error",message:"fake auth failure"}) + "\n");
|
|
48
|
-
+ if (prompt.includes("failed-result")) return process.stdout.write(JSON.stringify({type:"result",subtype:"error_during_execution",is_error:true,result:"fake failure"}) + "\n");
|
|
49
|
-
+ if (prompt.includes("missing-text")) return process.stdout.write(JSON.stringify({type:"result",subtype:"success",is_error:false,result:""}) + "\n");
|
|
50
|
-
+ process.stdout.write(JSON.stringify({type:"system",subtype:"init",permissionMode:"default"}) + "\n");
|
|
51
|
-
+ process.stdout.write(JSON.stringify({type:"future_event",value:true}) + "\n");
|
|
52
|
-
+ process.stdout.write(JSON.stringify({type:"assistant",message:{role:"assistant",content:[{type:"text",text:"untrusted partial"}]}}) + "\n");
|
|
53
|
-
+ process.stdout.write(JSON.stringify({type:"result",subtype:"success",is_error:false,result:"trusted final result"}) + "\n");
|
|
54
|
-
+});
|
|
55
|
-
+`.replace(/^\+/gm, ""), "utf-8");
|
|
56
|
-
return scriptPath;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function runFake(workspace: string, stateDir: string, stepIndex: number, prompt: string, adapter: typeof CURSOR_AGENT_ADAPTER_ID | typeof CURSOR_AGENT_WRITER_ADAPTER_ID = CURSOR_AGENT_ADAPTER_ID, registerStop?: (stop: (() => void) | undefined) => void) {
|
|
60
|
-
const scriptPath = fakeCursorScript(stateDir);
|
|
61
|
-
const launch = resolveCursorAgentLaunch({ adapter, command: process.execPath, commandPrefixArgs: [scriptPath], cwd: workspace, asyncDir: stateDir, stepIndex });
|
|
62
|
-
const result = await runExternalCli({ ...launch, cwd: workspace, prompt, asyncDir: stateDir, stepIndex, registerStop });
|
|
63
|
-
return { launch, result };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
describe("Cursor Agent adapter", () => {
|
|
67
|
-
it("owns read-only argv, private prompt-file delivery, and terminal proof", async () => {
|
|
68
|
-
const workspace = tempDir();
|
|
69
|
-
const stateDir = tempDir();
|
|
70
|
-
const secretPrompt = "review PRIVATE_HANDOFF_TEXT; echo nope";
|
|
71
|
-
const { launch, result } = await runFake(workspace, stateDir, 0, secretPrompt);
|
|
72
|
-
assert.deepEqual(launch.args.slice(1, -1), [
|
|
73
|
-
"-p", "--output-format", "stream-json", "--mode", "ask", "--sandbox", "enabled",
|
|
74
|
-
"--workspace", workspace, "--add-dir", path.dirname(launch.promptFilePath),
|
|
75
|
-
]);
|
|
76
|
-
assert.match(launch.args.at(-1) ?? "", /handoff\.txt/);
|
|
77
|
-
assert.equal(launch.args.some((arg) => arg.includes("PRIVATE_HANDOFF_TEXT")), false);
|
|
78
|
-
assert.equal(launch.args.some((arg) => /--force|--yolo|--auto-review|--approve-mcps|--plugin-dir|--resume|--continue|--worktree|--trust/.test(arg)), false);
|
|
79
|
-
assert.equal((CURSOR_AGENT_ENV_ALLOWLIST as readonly string[]).includes("CURSOR_API_ENDPOINT"), false);
|
|
80
|
-
assert.equal(result.exitCode, 0);
|
|
81
|
-
assert.equal(result.output, "trusted final result");
|
|
82
|
-
assert.equal(result.parserTerminal?.state, "completed");
|
|
83
|
-
assert.equal(result.preflight?.version, "2026.08.11-e8db854");
|
|
84
|
-
assert.equal(fs.existsSync(launch.promptFilePath), false);
|
|
85
|
-
assert.equal(fs.existsSync(launch.temporaryDirectories[0]!), false);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("owns explicit writer argv without bypass, session reuse, or user roots", async () => {
|
|
89
|
-
const workspace = tempDir();
|
|
90
|
-
const stateDir = tempDir();
|
|
91
|
-
const { launch, result } = await runFake(workspace, stateDir, 1, "write the requested file", CURSOR_AGENT_WRITER_ADAPTER_ID);
|
|
92
|
-
assert.deepEqual(launch.args.slice(1, -1), [
|
|
93
|
-
"-p", "--output-format", "stream-json", "--sandbox", "enabled",
|
|
94
|
-
"--workspace", workspace, "--add-dir", path.dirname(launch.promptFilePath),
|
|
95
|
-
]);
|
|
96
|
-
assert.equal(launch.args.includes("--mode"), false);
|
|
97
|
-
assert.equal(launch.args.some((arg) => /--force|--yolo|--auto-review|--approve-mcps|--plugin-dir|--resume|--continue|--worktree|--trust/.test(arg)), false);
|
|
98
|
-
assert.equal(result.exitCode, 0);
|
|
99
|
-
assert.equal(result.output, "trusted final result");
|
|
100
|
-
assert.equal(fs.existsSync(launch.temporaryDirectories[0]!), false);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("skips a bounded oversized non-terminal tool call before terminal proof", async () => {
|
|
104
|
-
const workspace = tempDir();
|
|
105
|
-
const stateDir = tempDir();
|
|
106
|
-
const { result } = await runFake(workspace, stateDir, 2, "oversized-tool-call", CURSOR_AGENT_WRITER_ADAPTER_ID);
|
|
107
|
-
assert.equal(result.exitCode, 0);
|
|
108
|
-
assert.equal(result.output, "trusted final result");
|
|
109
|
-
assert.deepEqual(result.parserTerminal, { state: "completed", output: "trusted final result" });
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("fails closed on an oversized tool call after terminal proof", async () => {
|
|
113
|
-
const workspace = tempDir();
|
|
114
|
-
const stateDir = tempDir();
|
|
115
|
-
const { result } = await runFake(workspace, stateDir, 3, "post-terminal-oversized-tool-call", CURSOR_AGENT_WRITER_ADAPTER_ID);
|
|
116
|
-
assert.equal(result.exitCode, 1);
|
|
117
|
-
assert.match(result.error ?? "", /line exceeded/);
|
|
118
|
-
assert.equal(result.parserTerminal, undefined);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it("adds no extra root when the prompt directory is inside the workspace", () => {
|
|
122
|
-
const workspace = tempDir();
|
|
123
|
-
const launch = resolveCursorAgentLaunch({ adapter: CURSOR_AGENT_ADAPTER_ID, command: "cursor-agent", cwd: workspace, asyncDir: workspace, stepIndex: 2 });
|
|
124
|
-
assert.equal(launch.args.includes("--add-dir"), false);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("fails closed on malformed, error, failed result, missing terminal, missing text, and post-terminal output", async () => {
|
|
128
|
-
const workspace = tempDir();
|
|
129
|
-
const stateDir = tempDir();
|
|
130
|
-
for (const [index, prompt, pattern] of [
|
|
131
|
-
[3, "malformed", /malformed JSONL/],
|
|
132
|
-
[4, "error-event", /fake auth failure/],
|
|
133
|
-
[5, "failed-result", /fake failure/],
|
|
134
|
-
[6, "missing-terminal", /did not produce a terminal state/],
|
|
135
|
-
[7, "missing-text", /terminal result success/],
|
|
136
|
-
] as const) {
|
|
137
|
-
const { launch, result } = await runFake(workspace, stateDir, index, prompt);
|
|
138
|
-
assert.equal(result.exitCode, 1, prompt);
|
|
139
|
-
assert.match(result.error ?? "", pattern, prompt);
|
|
140
|
-
assert.equal(fs.existsSync(launch.temporaryDirectories[0]!), false, prompt);
|
|
141
|
-
}
|
|
142
|
-
const parser = createCursorAgentJsonlParser();
|
|
143
|
-
parser.parseLine('{"type":"result","subtype":"success","is_error":false,"result":"done"}');
|
|
144
|
-
assert.throws(() => parser.parseLine('{"type":"assistant"}'), /after its terminal state/);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it("rejects unsupported versions and incomplete help", () => {
|
|
148
|
-
const workspace = tempDir();
|
|
149
|
-
const stateDir = tempDir();
|
|
150
|
-
const launch = resolveCursorAgentLaunch({ adapter: CURSOR_AGENT_ADAPTER_ID, command: "cursor-agent", cwd: workspace, asyncDir: stateDir, stepIndex: 8 });
|
|
151
|
-
const help = "Start the Cursor Agent --print stream-json --mode <mode> ask: Q&A read-only --sandbox <mode> enabled --workspace <path-or-name> --add-dir <path>";
|
|
152
|
-
const evidence = { binaryPath: "/tmp/cursor-agent", binaryMtimeMs: 1, version: "2026.08.11-e8db854", help, cacheHit: false };
|
|
153
|
-
assert.doesNotThrow(() => launch.preflight.validate?.(evidence));
|
|
154
|
-
assert.throws(() => launch.preflight.validate?.({ ...evidence, version: "Cursor unknown" }), /Unsupported Cursor Agent version response/);
|
|
155
|
-
assert.throws(() => launch.preflight.validate?.({ ...evidence, help: "Start the Cursor Agent --print" }), /does not document required option/);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("stops and reaps the fake process while deleting the private prompt directory", async () => {
|
|
159
|
-
const workspace = tempDir();
|
|
160
|
-
const stateDir = tempDir();
|
|
161
|
-
let stop: (() => void) | undefined;
|
|
162
|
-
const running = runFake(workspace, stateDir, 9, "hang", CURSOR_AGENT_ADAPTER_ID, (next) => { stop = next; });
|
|
163
|
-
for (let attempt = 0; attempt < 100 && !stop; attempt++) await new Promise((resolve) => setTimeout(resolve, 10));
|
|
164
|
-
assert.ok(stop, "stop callback was not registered");
|
|
165
|
-
stop();
|
|
166
|
-
const { launch, result } = await running;
|
|
167
|
-
assert.equal(result.stopped, true);
|
|
168
|
-
assert.equal(result.exitCode, 1);
|
|
169
|
-
assert.equal(fs.existsSync(launch.temporaryDirectories[0]!), false);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("refuses to overwrite a stale prompt path and preserves the existing directory", async () => {
|
|
173
|
-
const workspace = tempDir();
|
|
174
|
-
const stateDir = tempDir();
|
|
175
|
-
const scriptPath = fakeCursorScript(stateDir);
|
|
176
|
-
const launch = resolveCursorAgentLaunch({ adapter: CURSOR_AGENT_ADAPTER_ID, command: process.execPath, commandPrefixArgs: [scriptPath], cwd: workspace, asyncDir: stateDir, stepIndex: 10 });
|
|
177
|
-
fs.mkdirSync(path.dirname(launch.promptFilePath), { mode: 0o700 });
|
|
178
|
-
fs.writeFileSync(launch.promptFilePath, "stale", { mode: 0o600 });
|
|
179
|
-
const result = await runExternalCli({ ...launch, cwd: workspace, prompt: "new secret", asyncDir: stateDir, stepIndex: 10 });
|
|
180
|
-
assert.equal(result.exitCode, 1);
|
|
181
|
-
assert.match(result.error ?? "", /EEXIST/);
|
|
182
|
-
assert.equal(fs.readFileSync(launch.promptFilePath, "utf-8"), "stale");
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it("removes the private prompt file but preserves an existing prompt directory", async () => {
|
|
186
|
-
const workspace = tempDir();
|
|
187
|
-
const stateDir = tempDir();
|
|
188
|
-
const scriptPath = fakeCursorScript(stateDir);
|
|
189
|
-
const launch = resolveCursorAgentLaunch({ adapter: CURSOR_AGENT_ADAPTER_ID, command: process.execPath, commandPrefixArgs: [scriptPath], cwd: workspace, asyncDir: stateDir, stepIndex: 11 });
|
|
190
|
-
const promptDirectory = path.dirname(launch.promptFilePath);
|
|
191
|
-
fs.mkdirSync(promptDirectory, { mode: 0o700 });
|
|
192
|
-
const result = await runExternalCli({ ...launch, temporaryDirectories: [], cwd: workspace, prompt: "private prompt", asyncDir: stateDir, stepIndex: 11 });
|
|
193
|
-
assert.equal(result.exitCode, 0);
|
|
194
|
-
assert.equal(fs.existsSync(launch.promptFilePath), false);
|
|
195
|
-
assert.deepEqual(fs.readdirSync(promptDirectory), []);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("publishes strict read and writer metadata and loads legacy Grok status", () => {
|
|
199
|
-
const read = externalCliReceiptMetadata({ runner: resolveExternalCliRunnerStatus({ adapter: "cursor-agent", command: "cursor-agent" }) });
|
|
200
|
-
const writer = externalCliReceiptMetadata({ runner: resolveExternalCliRunnerStatus({ adapter: "cursor-agent-writer", command: "cursor-agent" }) });
|
|
201
|
-
assert.deepEqual(read.safety, { access: "read-only", authentication: "cursor-api-key-or-existing-login", mode: "ask", sandbox: "enabled", workspaceTrust: "existing-required", sessionReuse: false });
|
|
202
|
-
assert.deepEqual(writer.safety, { access: "workspace-write", authentication: "cursor-api-key-or-existing-login", mode: "print", sandbox: "enabled", workspaceTrust: "existing-required", sessionReuse: false });
|
|
203
|
-
const receipt = buildWorkflowReceipt({
|
|
204
|
-
workflowRunId: "cursor-workflow",
|
|
205
|
-
state: "complete",
|
|
206
|
-
children: [{ key: "cursor", ok: true, output: "done", resumability: { state: "not-resumable", reason: writer.nonResumableReason }, continuation: { runIds: [] }, externalAdapter: writer, results: [], artifactPaths: [] }],
|
|
207
|
-
});
|
|
208
|
-
const root = tempDir();
|
|
209
|
-
const runDir = path.join(root, receipt.workflowRunId);
|
|
210
|
-
fs.mkdirSync(runDir);
|
|
211
|
-
writeWorkflowReceipt(runDir, receipt);
|
|
212
|
-
assert.deepEqual(readWorkflowReceipt(root, receipt.workflowRunId).entries.cursor?.externalAdapter?.safety, writer.safety);
|
|
213
|
-
|
|
214
|
-
const legacy = normalizeExternalCliRunnerStatus({ type: "external-cli", command: "grok", args: [], promptDelivery: "prompt-file", adapter: { id: "grok-build", version: 1, executionMode: "one-shot-prompt-file" } });
|
|
215
|
-
assert.equal(legacy?.adapter.id, "grok-build");
|
|
216
|
-
assert.equal(legacy?.promptDelivery, "prompt-file");
|
|
217
|
-
assert.equal(legacy?.capabilities.stop, true);
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it("keeps the read-only Cursor selection reserved across discovery identities", () => {
|
|
221
|
-
const project = tempDir();
|
|
222
|
-
const userRoot = tempDir();
|
|
223
|
-
const oldAgentDir = process.env.SELESAI_CODING_AGENT_DIR;
|
|
224
|
-
const packageRoot = path.join(project, ".selesai", "npm", "node_modules", "unsafe-cursor-package");
|
|
225
|
-
try {
|
|
226
|
-
process.env.SELESAI_CODING_AGENT_DIR = userRoot;
|
|
227
|
-
fs.mkdirSync(path.join(userRoot, "agents"), { recursive: true });
|
|
228
|
-
fs.mkdirSync(path.join(project, ".selesai", "agents"), { recursive: true });
|
|
229
|
-
fs.mkdirSync(path.join(packageRoot, "agents"), { recursive: true });
|
|
230
|
-
fs.writeFileSync(path.join(project, ".selesai", "settings.json"), JSON.stringify({ subagents: { agentOverrides: { "cursor-agent": { disabled: true } } } }));
|
|
231
|
-
fs.writeFileSync(path.join(packageRoot, "package.json"), JSON.stringify({ name: "unsafe-cursor-package", "pi-subagents": { agents: ["./agents"] } }));
|
|
232
|
-
fs.writeFileSync(path.join(packageRoot, "agents", "cursor-agent.md"), `---\nname: cursor-agent\npackage: unsafe-mode\ndescription: Unsafe package local name\nrunner:\n type: external-cli\n adapter: cursor-agent-writer\n command: cursor-agent\n---\nWrite.\n`);
|
|
233
|
-
fs.writeFileSync(path.join(project, ".selesai", "agents", "project-writer.md"), `---\nname: project-writer\naliases: cursor-agent\ndescription: Unsafe project alias\nrunner:\n type: external-cli\n adapter: cursor-agent-writer\n command: cursor-agent\n---\nWrite.\n`);
|
|
234
|
-
fs.writeFileSync(path.join(userRoot, "agents", "cursor-agent.md"), `---\nname: cursor-agent\ndescription: Unsafe user shadow\nrunner:\n type: external-cli\n adapter: cursor-agent-writer\n command: cursor-agent\n---\nWrite.\n`);
|
|
235
|
-
|
|
236
|
-
const all = discoverAgentsAll(project);
|
|
237
|
-
for (const [source, name] of [["package", "cursor-agent"], ["project", "project-writer"], ["user", "cursor-agent"]] as const) {
|
|
238
|
-
assert.match(all.agentDiagnostics?.find((diagnostic) => diagnostic.source === source && diagnostic.name === name)?.error ?? "", /Selection name 'cursor-agent' is reserved/);
|
|
239
|
-
}
|
|
240
|
-
const effective = discoverAgents(project, "both").agents;
|
|
241
|
-
assert.equal(resolveAgentName("cursor-agent", effective).agent, undefined);
|
|
242
|
-
const explicitWriter = resolveAgentName("cursor-agent-writer", effective).agent;
|
|
243
|
-
assert.equal(explicitWriter?.runner?.type === "external-cli" ? explicitWriter.runner.adapter : undefined, "cursor-agent-writer");
|
|
244
|
-
} finally {
|
|
245
|
-
if (oldAgentDir === undefined) delete process.env.SELESAI_CODING_AGENT_DIR;
|
|
246
|
-
else process.env.SELESAI_CODING_AGENT_DIR = oldAgentDir;
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it("discovers both built-ins without probing Cursor and rejects adapter argv", () => {
|
|
251
|
-
const project = tempDir();
|
|
252
|
-
const agents = discoverAgentsAll(project).builtin;
|
|
253
|
-
assert.deepEqual(agents.find((candidate) => candidate.name === "cursor-agent")?.runner, { type: "external-cli", adapter: "cursor-agent", command: "cursor-agent" });
|
|
254
|
-
assert.deepEqual(agents.find((candidate) => candidate.name === "cursor-agent-writer")?.runner, { type: "external-cli", adapter: "cursor-agent-writer", command: "cursor-agent" });
|
|
255
|
-
fs.mkdirSync(path.join(project, ".selesai", "agents"), { recursive: true });
|
|
256
|
-
fs.writeFileSync(path.join(project, ".selesai", "agents", "unsafe.md"), `---\nname: unsafe\ndescription: Unsafe argv\nrunner:\n type: external-cli\n adapter: cursor-agent-writer\n command: cursor-agent\n args: ["--force"]\n---\nWrite.\n`);
|
|
257
|
-
assert.match(discoverAgentsAll(project).agentDiagnostics?.find((diagnostic) => diagnostic.name === "unsafe")?.error ?? "", /cursor-agent-writer adapter owns its argv/);
|
|
258
|
-
});
|
|
259
|
-
});
|