poe-code 3.0.202 → 3.0.203
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/dist/cli/commands/experiment.js +11 -4
- package/dist/cli/commands/experiment.js.map +1 -1
- package/dist/cli/commands/ralph.js +12 -5
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/runtime-options.d.ts +10 -0
- package/dist/cli/commands/runtime-options.js +23 -0
- package/dist/cli/commands/runtime-options.js.map +1 -0
- package/dist/cli/commands/spawn.js +9 -3
- package/dist/cli/commands/spawn.js.map +1 -1
- package/dist/index.js +21873 -20138
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +2741 -1706
- package/dist/providers/claude-code.js.map +4 -4
- package/dist/providers/codex.js +2770 -1735
- package/dist/providers/codex.js.map +4 -4
- package/dist/providers/goose.js +2640 -1605
- package/dist/providers/goose.js.map +4 -4
- package/dist/providers/kimi.js +2740 -1705
- package/dist/providers/kimi.js.map +4 -4
- package/dist/providers/opencode.js +2741 -1706
- package/dist/providers/opencode.js.map +4 -4
- package/dist/providers/poe-agent.js +19451 -17229
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/providers/spawn-options.d.ts +6 -0
- package/dist/sdk/experiment.js +5 -0
- package/dist/sdk/experiment.js.map +1 -1
- package/dist/sdk/ralph.js +5 -0
- package/dist/sdk/ralph.js.map +1 -1
- package/dist/sdk/spawn.js +17 -1
- package/dist/sdk/spawn.js.map +1 -1
- package/dist/sdk/types.d.ts +11 -0
- package/package.json +1 -1
- package/packages/memory/dist/index.js +2353 -420
- package/packages/memory/dist/index.js.map +4 -4
- package/packages/superintendent/dist/commands/run.d.ts +35 -0
- package/packages/superintendent/dist/commands/run.js +49 -1
- package/packages/superintendent/dist/commands/superintendent-group.d.ts +30 -0
- package/packages/superintendent/dist/runtime/agent-runner.d.ts +30 -0
- package/packages/superintendent/dist/runtime/agent-runner.js +119 -0
- package/packages/superintendent/dist/runtime/loop.d.ts +6 -1
- package/packages/superintendent/dist/runtime/loop.js +3 -11
- package/packages/superintendent/dist/runtime/run-builder.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-builder.js +3 -25
- package/packages/superintendent/dist/runtime/run-inspector.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-inspector.js +3 -25
- package/packages/superintendent/dist/runtime/run-owner-review.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-owner-review.js +3 -25
- package/packages/superintendent/dist/runtime/run-superintendent.d.ts +1 -0
- package/packages/superintendent/dist/runtime/run-superintendent.js +3 -25
package/dist/providers/kimi.js
CHANGED
|
@@ -52,19 +52,11 @@ var require_config_toml = __commonJS({
|
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
// packages/agent-spawn/src/
|
|
56
|
-
import { spawn } from "node:child_process";
|
|
55
|
+
// packages/agent-spawn/src/register-factories.ts
|
|
56
|
+
import { spawn as spawnChildProcess2 } from "node:child_process";
|
|
57
57
|
|
|
58
|
-
// packages/agent-
|
|
59
|
-
|
|
60
|
-
if (Array.isArray(modeConfig)) {
|
|
61
|
-
return { args: modeConfig };
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
args: modeConfig.args ?? [],
|
|
65
|
-
env: modeConfig.env && Object.keys(modeConfig.env).length > 0 ? modeConfig.env : void 0
|
|
66
|
-
};
|
|
67
|
-
}
|
|
58
|
+
// packages/agent-harness-tools/src/paths.ts
|
|
59
|
+
import path from "node:path";
|
|
68
60
|
|
|
69
61
|
// packages/agent-defs/src/agents/claude-code.ts
|
|
70
62
|
var claudeCodeAgent = {
|
|
@@ -205,1925 +197,2968 @@ function resolveAgentId(input) {
|
|
|
205
197
|
return lookup.get(input.toLowerCase());
|
|
206
198
|
}
|
|
207
199
|
|
|
208
|
-
// packages/agent-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
200
|
+
// packages/agent-harness-tools/src/select-agent.ts
|
|
201
|
+
var loopAgents = allAgents.filter(
|
|
202
|
+
(agent) => agent.binaryName !== void 0 || agent.id === "poe-agent"
|
|
203
|
+
);
|
|
204
|
+
var supportedAgents = loopAgents.map((agent) => agent.id).join(", ");
|
|
205
|
+
|
|
206
|
+
// packages/file-lock/src/lock.ts
|
|
207
|
+
import * as fsPromises from "node:fs/promises";
|
|
208
|
+
import * as os from "node:os";
|
|
209
|
+
|
|
210
|
+
// packages/agent-harness-tools/src/run-logs.ts
|
|
211
|
+
import path2 from "node:path";
|
|
212
|
+
|
|
213
|
+
// packages/agent-harness-tools/src/log-stream.ts
|
|
214
|
+
import nodeFs from "node:fs";
|
|
215
|
+
|
|
216
|
+
// packages/agent-harness-tools/src/run-poe-command.ts
|
|
217
|
+
import { randomBytes } from "node:crypto";
|
|
218
|
+
|
|
219
|
+
// packages/agent-harness-tools/src/poe-command-execution.ts
|
|
220
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
221
|
+
import os3 from "node:os";
|
|
222
|
+
|
|
223
|
+
// packages/poe-code-config/src/runtime.ts
|
|
224
|
+
import { existsSync } from "node:fs";
|
|
225
|
+
import path3 from "node:path";
|
|
226
|
+
var defaultWorkspaceExclude = [
|
|
227
|
+
".git",
|
|
228
|
+
"node_modules",
|
|
229
|
+
"dist",
|
|
230
|
+
".turbo",
|
|
231
|
+
".next",
|
|
232
|
+
".poe-code/state.json"
|
|
233
|
+
];
|
|
234
|
+
var runtimeConfigScope = {
|
|
235
|
+
scope: "runtime",
|
|
236
|
+
schema: {
|
|
237
|
+
type: {
|
|
238
|
+
type: "string",
|
|
239
|
+
default: "host",
|
|
240
|
+
doc: "Runtime backend: host, docker, or e2b"
|
|
241
|
+
},
|
|
242
|
+
build_args: {
|
|
243
|
+
type: "json",
|
|
244
|
+
default: {},
|
|
245
|
+
parse: parseBuildArgs,
|
|
246
|
+
doc: "Build arguments passed to the runtime image build"
|
|
247
|
+
},
|
|
248
|
+
mounts: {
|
|
249
|
+
type: "json",
|
|
250
|
+
default: [],
|
|
251
|
+
parse: parseMounts,
|
|
252
|
+
doc: "Additional runtime mounts"
|
|
253
|
+
},
|
|
254
|
+
runner: {
|
|
255
|
+
type: "json",
|
|
256
|
+
default: createDefaultRunnerScope(),
|
|
257
|
+
parse: parseRunner,
|
|
258
|
+
doc: "Runner process and workspace transfer settings"
|
|
259
|
+
},
|
|
260
|
+
link: {
|
|
261
|
+
type: "string",
|
|
262
|
+
default: "",
|
|
263
|
+
doc: "Informational link for the runtime definition"
|
|
264
|
+
},
|
|
265
|
+
image: {
|
|
266
|
+
type: "string",
|
|
267
|
+
default: "",
|
|
268
|
+
doc: "Prebuilt Docker image"
|
|
269
|
+
},
|
|
270
|
+
dockerfile: {
|
|
271
|
+
type: "string",
|
|
272
|
+
default: "",
|
|
273
|
+
doc: "Path to the Dockerfile used for docker or e2b builds"
|
|
274
|
+
},
|
|
275
|
+
build_context: {
|
|
276
|
+
type: "string",
|
|
277
|
+
default: "",
|
|
278
|
+
doc: "Path to the Docker build context"
|
|
279
|
+
},
|
|
280
|
+
engine: {
|
|
281
|
+
type: "string",
|
|
282
|
+
default: "",
|
|
283
|
+
doc: "Container engine for Docker runtime"
|
|
284
|
+
},
|
|
285
|
+
network: {
|
|
286
|
+
type: "string",
|
|
287
|
+
default: "",
|
|
288
|
+
doc: "Docker network"
|
|
289
|
+
},
|
|
290
|
+
extra_args: {
|
|
291
|
+
type: "json",
|
|
292
|
+
default: void 0,
|
|
293
|
+
parse: parseOptionalStringArray,
|
|
294
|
+
doc: "Extra Docker runtime arguments"
|
|
295
|
+
},
|
|
296
|
+
template_id: {
|
|
297
|
+
type: "string",
|
|
298
|
+
default: "",
|
|
299
|
+
doc: "Prebuilt E2B template id"
|
|
300
|
+
},
|
|
301
|
+
cpu: {
|
|
302
|
+
type: "json",
|
|
303
|
+
default: void 0,
|
|
304
|
+
parse: parseOptionalNumber,
|
|
305
|
+
doc: "E2B CPU count"
|
|
306
|
+
},
|
|
307
|
+
memory_mb: {
|
|
308
|
+
type: "json",
|
|
309
|
+
default: void 0,
|
|
310
|
+
parse: parseOptionalNumber,
|
|
311
|
+
doc: "E2B memory in megabytes"
|
|
312
|
+
},
|
|
313
|
+
timeout_minutes: {
|
|
314
|
+
type: "json",
|
|
315
|
+
default: void 0,
|
|
316
|
+
parse: parseOptionalNumber,
|
|
317
|
+
doc: "E2B timeout in minutes"
|
|
318
|
+
},
|
|
319
|
+
preserve_after_exit_hours: {
|
|
320
|
+
type: "json",
|
|
321
|
+
default: void 0,
|
|
322
|
+
parse: parseOptionalNumber,
|
|
323
|
+
doc: "Hours to keep an E2B sandbox alive after job exit"
|
|
324
|
+
},
|
|
325
|
+
api_key_env: {
|
|
326
|
+
type: "string",
|
|
327
|
+
default: "",
|
|
328
|
+
doc: "Environment variable name containing the E2B API key"
|
|
221
329
|
}
|
|
222
|
-
out[name] = mapped;
|
|
223
330
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
331
|
+
};
|
|
332
|
+
function parseRunner(raw) {
|
|
333
|
+
if (raw === void 0) {
|
|
334
|
+
return createDefaultRunnerScope();
|
|
335
|
+
}
|
|
336
|
+
const record = asRecord(raw);
|
|
337
|
+
if (record === void 0) {
|
|
338
|
+
throw new Error("runner: expected an object.");
|
|
339
|
+
}
|
|
340
|
+
const uploadMaxFileMb = parseOptionalNumber(record.upload_max_file_mb, "runner.upload_max_file_mb") ?? 100;
|
|
341
|
+
if (uploadMaxFileMb <= 0) {
|
|
342
|
+
throw new Error("runner.upload_max_file_mb: expected a positive finite number.");
|
|
343
|
+
}
|
|
344
|
+
return omitUndefined({
|
|
345
|
+
detach: parseOptionalBoolean(record.detach, "runner.detach") ?? false,
|
|
346
|
+
upload_max_file_mb: uploadMaxFileMb,
|
|
347
|
+
download_conflict: parseDownloadConflict(record.download_conflict),
|
|
348
|
+
workspace: parseRunnerWorkspace(record.workspace)
|
|
349
|
+
});
|
|
228
350
|
}
|
|
229
|
-
function
|
|
230
|
-
|
|
231
|
-
|
|
351
|
+
function createDefaultRunnerScope() {
|
|
352
|
+
return {
|
|
353
|
+
detach: false,
|
|
354
|
+
upload_max_file_mb: 100,
|
|
355
|
+
download_conflict: "refuse",
|
|
356
|
+
workspace: {
|
|
357
|
+
exclude: [...defaultWorkspaceExclude]
|
|
358
|
+
}
|
|
359
|
+
};
|
|
232
360
|
}
|
|
233
|
-
function
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
361
|
+
function parseRunnerWorkspace(value) {
|
|
362
|
+
if (value === void 0) {
|
|
363
|
+
return {
|
|
364
|
+
exclude: [...defaultWorkspaceExclude]
|
|
365
|
+
};
|
|
237
366
|
}
|
|
238
|
-
|
|
367
|
+
const record = asRecord(value);
|
|
368
|
+
if (record === void 0) {
|
|
369
|
+
throw new Error("runner.workspace: expected an object.");
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
exclude: parseOptionalStringArray(record.exclude, "runner.workspace.exclude") ?? [
|
|
373
|
+
...defaultWorkspaceExclude
|
|
374
|
+
]
|
|
375
|
+
};
|
|
239
376
|
}
|
|
240
|
-
function
|
|
241
|
-
|
|
377
|
+
function parseDownloadConflict(value) {
|
|
378
|
+
if (value === void 0) {
|
|
379
|
+
return "refuse";
|
|
380
|
+
}
|
|
381
|
+
if (value === "refuse" || value === "overwrite") {
|
|
382
|
+
return value;
|
|
383
|
+
}
|
|
384
|
+
throw new Error('runner.download_conflict: expected "refuse" or "overwrite".');
|
|
242
385
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
386
|
+
function parseBuildArgs(value) {
|
|
387
|
+
if (value === void 0) {
|
|
388
|
+
return {};
|
|
389
|
+
}
|
|
390
|
+
const record = asRecord(value);
|
|
391
|
+
if (record === void 0) {
|
|
392
|
+
throw new Error("build_args: expected an object.");
|
|
393
|
+
}
|
|
394
|
+
const parsed = {};
|
|
395
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
396
|
+
if (typeof entry !== "string") {
|
|
397
|
+
throw new Error(`build_args.${key}: expected a string.`);
|
|
249
398
|
}
|
|
250
|
-
|
|
399
|
+
parsed[key] = entry;
|
|
251
400
|
}
|
|
252
|
-
return
|
|
401
|
+
return parsed;
|
|
253
402
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
403
|
+
function parseMounts(value) {
|
|
404
|
+
if (value === void 0) {
|
|
405
|
+
return [];
|
|
406
|
+
}
|
|
407
|
+
if (!Array.isArray(value)) {
|
|
408
|
+
throw new Error("mounts: expected an array.");
|
|
409
|
+
}
|
|
410
|
+
return value.map((entry, index) => {
|
|
411
|
+
const record = asRecord(entry);
|
|
412
|
+
if (record === void 0) {
|
|
413
|
+
throw new Error(`mounts[${index}]: expected an object.`);
|
|
261
414
|
}
|
|
262
|
-
|
|
263
|
-
|
|
415
|
+
const source = record.source;
|
|
416
|
+
const target = record.target;
|
|
417
|
+
if (typeof source !== "string") {
|
|
418
|
+
throw new Error(`mounts[${index}].source: expected a string.`);
|
|
264
419
|
}
|
|
265
|
-
if (
|
|
266
|
-
|
|
420
|
+
if (typeof target !== "string") {
|
|
421
|
+
throw new Error(`mounts[${index}].target: expected a string.`);
|
|
267
422
|
}
|
|
423
|
+
return omitUndefined({
|
|
424
|
+
source,
|
|
425
|
+
target,
|
|
426
|
+
readonly: parseOptionalBoolean(record.readonly, `mounts[${index}].readonly`)
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
function parseOptionalStringArray(value, key = "") {
|
|
431
|
+
if (value === void 0) {
|
|
432
|
+
return void 0;
|
|
268
433
|
}
|
|
269
|
-
|
|
434
|
+
if (!Array.isArray(value)) {
|
|
435
|
+
throw new Error(`${key ? `${key}: ` : ""}expected an array.`);
|
|
436
|
+
}
|
|
437
|
+
return value.map((entry, index) => {
|
|
438
|
+
if (typeof entry !== "string") {
|
|
439
|
+
throw new Error(`${key}[${index}]: expected a string.`);
|
|
440
|
+
}
|
|
441
|
+
return entry;
|
|
442
|
+
});
|
|
270
443
|
}
|
|
271
|
-
function
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
444
|
+
function parseOptionalNumber(value, key = "") {
|
|
445
|
+
if (value === void 0) {
|
|
446
|
+
return void 0;
|
|
447
|
+
}
|
|
448
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
449
|
+
throw new Error(`${key ? `${key}: ` : ""}expected a finite number.`);
|
|
450
|
+
}
|
|
451
|
+
return value;
|
|
452
|
+
}
|
|
453
|
+
function parseOptionalBoolean(value, key) {
|
|
454
|
+
if (value === void 0) {
|
|
455
|
+
return void 0;
|
|
456
|
+
}
|
|
457
|
+
if (typeof value !== "boolean") {
|
|
458
|
+
throw new Error(`${key}: expected a boolean.`);
|
|
459
|
+
}
|
|
460
|
+
return value;
|
|
461
|
+
}
|
|
462
|
+
function asRecord(value) {
|
|
463
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
464
|
+
return void 0;
|
|
465
|
+
}
|
|
466
|
+
return value;
|
|
467
|
+
}
|
|
468
|
+
function omitUndefined(value) {
|
|
469
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
276
470
|
}
|
|
277
471
|
|
|
278
|
-
// packages/
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
modelFlag: "--model",
|
|
286
|
-
modelStripProviderPrefix: true,
|
|
287
|
-
modelTransform: (model) => model.replaceAll(".", "-"),
|
|
288
|
-
defaultArgs: [
|
|
289
|
-
"--output-format",
|
|
290
|
-
"stream-json",
|
|
291
|
-
"--verbose"
|
|
292
|
-
],
|
|
293
|
-
mcpArgs: serializeJsonMcpArgs,
|
|
294
|
-
modes: {
|
|
295
|
-
yolo: ["--dangerously-skip-permissions"],
|
|
296
|
-
edit: ["--permission-mode", "acceptEdits", "--allowedTools", "Bash,Read,Write,Edit,Glob,Grep,NotebookEdit"],
|
|
297
|
-
read: ["--permission-mode", "plan"]
|
|
298
|
-
},
|
|
299
|
-
stdinMode: {
|
|
300
|
-
omitPrompt: true,
|
|
301
|
-
extraArgs: ["--input-format", "text"]
|
|
302
|
-
},
|
|
303
|
-
interactive: {
|
|
304
|
-
defaultArgs: []
|
|
305
|
-
},
|
|
306
|
-
resumeCommand: (threadId) => ["--resume", threadId]
|
|
307
|
-
};
|
|
472
|
+
// packages/poe-code-config/src/schema.ts
|
|
473
|
+
function defineScope(scope, schema) {
|
|
474
|
+
return {
|
|
475
|
+
scope,
|
|
476
|
+
schema
|
|
477
|
+
};
|
|
478
|
+
}
|
|
308
479
|
|
|
309
|
-
// packages/
|
|
310
|
-
var
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
defaultArgs: ["--skip-git-repo-check", "--json"],
|
|
319
|
-
mcpArgs: serializeCodexMcpArgs,
|
|
320
|
-
mcpArgsBeforeCommand: true,
|
|
321
|
-
modes: {
|
|
322
|
-
yolo: ["-s", "danger-full-access"],
|
|
323
|
-
edit: ["-s", "workspace-write"],
|
|
324
|
-
read: ["-s", "read-only"]
|
|
325
|
-
},
|
|
326
|
-
stdinMode: {
|
|
327
|
-
omitPrompt: true,
|
|
328
|
-
extraArgs: ["-"]
|
|
329
|
-
},
|
|
330
|
-
interactive: {
|
|
331
|
-
defaultArgs: ["-a", "never"]
|
|
332
|
-
},
|
|
333
|
-
resumeCommand: (threadId, cwd) => ["resume", "-C", cwd, threadId]
|
|
334
|
-
};
|
|
480
|
+
// packages/poe-code-config/src/plan-scope.ts
|
|
481
|
+
var planConfigScope = defineScope("plan", {
|
|
482
|
+
plan_directory: {
|
|
483
|
+
type: "string",
|
|
484
|
+
default: "docs/plans",
|
|
485
|
+
env: "POE_PLAN_DIRECTORY",
|
|
486
|
+
doc: "Directory where planning documents are stored"
|
|
487
|
+
}
|
|
488
|
+
});
|
|
335
489
|
|
|
336
|
-
// packages/
|
|
337
|
-
|
|
338
|
-
kind: "cli",
|
|
339
|
-
agentId: "opencode",
|
|
340
|
-
// ACP adapter support: yes (adapter: "opencode").
|
|
341
|
-
// OpenCode's `--format json` emits NDJSON events with `{ type, sessionID, part }`
|
|
342
|
-
// (no `{ event, ... }` field), so it needs the OpenCode adapter (not "native").
|
|
343
|
-
adapter: "opencode",
|
|
344
|
-
promptFlag: "run",
|
|
345
|
-
modelFlag: "--model",
|
|
346
|
-
modelStripProviderPrefix: false,
|
|
347
|
-
modelTransform: (model) => {
|
|
348
|
-
return model.startsWith("poe/") ? model : `poe/${model}`;
|
|
349
|
-
},
|
|
350
|
-
defaultArgs: ["--format", "json"],
|
|
351
|
-
modes: {
|
|
352
|
-
yolo: [],
|
|
353
|
-
edit: [],
|
|
354
|
-
read: ["--agent", "plan"]
|
|
355
|
-
},
|
|
356
|
-
interactive: {
|
|
357
|
-
defaultArgs: [],
|
|
358
|
-
promptFlag: "--prompt"
|
|
359
|
-
},
|
|
360
|
-
resumeCommand: (threadId, cwd) => [cwd, "--session", threadId],
|
|
361
|
-
mcpEnv: serializeOpenCodeMcpEnv
|
|
362
|
-
};
|
|
363
|
-
var openCodeAcpSpawnConfig = {
|
|
364
|
-
kind: "acp",
|
|
365
|
-
agentId: "opencode",
|
|
366
|
-
acpArgs: ["acp"],
|
|
367
|
-
skipAuth: true,
|
|
368
|
-
mcpEnv: serializeOpenCodeMcpEnv
|
|
369
|
-
};
|
|
490
|
+
// packages/poe-code-config/src/store.ts
|
|
491
|
+
import path8 from "node:path";
|
|
370
492
|
|
|
371
|
-
// packages/
|
|
372
|
-
|
|
373
|
-
kind: "cli",
|
|
374
|
-
agentId: "kimi",
|
|
375
|
-
// ACP adapter support: yes (adapter: "kimi").
|
|
376
|
-
// Kimi's `--output-format stream-json` emits OpenAI-style `{ role, content }` JSON
|
|
377
|
-
// (no `{ event, ... }` field), so it needs the Kimi adapter (not "native").
|
|
378
|
-
adapter: "kimi",
|
|
379
|
-
promptFlag: "-p",
|
|
380
|
-
modelStripProviderPrefix: true,
|
|
381
|
-
defaultArgs: ["--print", "--output-format", "stream-json"],
|
|
382
|
-
mcpArgs: serializeJsonMcpArgs,
|
|
383
|
-
modes: {
|
|
384
|
-
yolo: ["--yolo"],
|
|
385
|
-
edit: [],
|
|
386
|
-
read: []
|
|
387
|
-
},
|
|
388
|
-
stdinMode: {
|
|
389
|
-
omitPrompt: true,
|
|
390
|
-
extraArgs: ["--input-format", "stream-json"]
|
|
391
|
-
},
|
|
392
|
-
interactive: {
|
|
393
|
-
defaultArgs: [],
|
|
394
|
-
promptFlag: "-p"
|
|
395
|
-
},
|
|
396
|
-
resumeCommand: (threadId, cwd) => ["--session", threadId, "--work-dir", cwd]
|
|
397
|
-
};
|
|
398
|
-
var kimiAcpSpawnConfig = {
|
|
399
|
-
kind: "acp",
|
|
400
|
-
agentId: "kimi",
|
|
401
|
-
acpArgs: ["acp"]
|
|
402
|
-
};
|
|
493
|
+
// packages/config-extends/src/discover.ts
|
|
494
|
+
import path4 from "node:path";
|
|
403
495
|
|
|
404
|
-
// packages/
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
agentId: "goose",
|
|
409
|
-
adapter: "native",
|
|
410
|
-
promptFlag: "--text",
|
|
411
|
-
modelFlag: "--model",
|
|
412
|
-
modelStripProviderPrefix: false,
|
|
413
|
-
defaultArgs: ["run", "--output-format", "stream-json"],
|
|
414
|
-
defaultArgsPosition: "beforePrompt",
|
|
415
|
-
mcpArgs: serializeGooseMcpArgs,
|
|
416
|
-
mcpArgsPosition: "beforePrompt",
|
|
417
|
-
modes: {
|
|
418
|
-
yolo: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "auto" } },
|
|
419
|
-
edit: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "smart_approve" } },
|
|
420
|
-
read: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "chat" } }
|
|
421
|
-
},
|
|
422
|
-
stdinMode: {
|
|
423
|
-
omitPrompt: true,
|
|
424
|
-
extraArgs: ["--instructions", "-"]
|
|
425
|
-
},
|
|
426
|
-
interactive: {
|
|
427
|
-
defaultArgs: ["session"],
|
|
428
|
-
defaultArgsPosition: "beforePrompt"
|
|
429
|
-
},
|
|
430
|
-
resumeCommand: () => ["run", "--resume", "--text", "continue"]
|
|
431
|
-
};
|
|
432
|
-
var gooseAcpSpawnConfig = {
|
|
433
|
-
kind: "acp",
|
|
434
|
-
agentId: "goose",
|
|
435
|
-
acpArgs: ["acp"],
|
|
436
|
-
env: gooseFileSecretsEnv,
|
|
437
|
-
skipAuth: true
|
|
438
|
-
};
|
|
496
|
+
// packages/config-extends/src/parse.ts
|
|
497
|
+
import path5 from "node:path";
|
|
498
|
+
import matter from "gray-matter";
|
|
499
|
+
import { parse as parseYaml } from "yaml";
|
|
439
500
|
|
|
440
|
-
// packages/
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
501
|
+
// packages/config-extends/src/resolve.ts
|
|
502
|
+
import path6 from "node:path";
|
|
503
|
+
|
|
504
|
+
// packages/config-mutations/src/mutations/config-mutation.ts
|
|
505
|
+
function merge(options) {
|
|
506
|
+
return {
|
|
507
|
+
kind: "configMerge",
|
|
508
|
+
target: options.target,
|
|
509
|
+
value: options.value,
|
|
510
|
+
format: options.format,
|
|
511
|
+
pruneByPrefix: options.pruneByPrefix,
|
|
512
|
+
label: options.label
|
|
513
|
+
};
|
|
451
514
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
return lookup2.get(resolvedId);
|
|
515
|
+
function prune(options) {
|
|
516
|
+
return {
|
|
517
|
+
kind: "configPrune",
|
|
518
|
+
target: options.target,
|
|
519
|
+
shape: options.shape,
|
|
520
|
+
format: options.format,
|
|
521
|
+
onlyIf: options.onlyIf,
|
|
522
|
+
label: options.label
|
|
523
|
+
};
|
|
462
524
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
return supported;
|
|
525
|
+
function transform(options) {
|
|
526
|
+
return {
|
|
527
|
+
kind: "configTransform",
|
|
528
|
+
target: options.target,
|
|
529
|
+
format: options.format,
|
|
530
|
+
transform: options.transform,
|
|
531
|
+
label: options.label
|
|
532
|
+
};
|
|
472
533
|
}
|
|
534
|
+
var configMutation = {
|
|
535
|
+
merge,
|
|
536
|
+
prune,
|
|
537
|
+
transform
|
|
538
|
+
};
|
|
473
539
|
|
|
474
|
-
// packages/
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const resolvedAgentId = resolveAgentId(agentId);
|
|
482
|
-
if (!resolvedAgentId) {
|
|
483
|
-
throw new Error(`Unknown agent "${agentId}".`);
|
|
484
|
-
}
|
|
485
|
-
const agentDefinition = allAgents.find((agent) => agent.id === resolvedAgentId);
|
|
486
|
-
if (!agentDefinition) {
|
|
487
|
-
throw new Error(`Unknown agent "${agentId}".`);
|
|
488
|
-
}
|
|
489
|
-
const spawnConfig = getSpawnConfig(resolvedAgentId);
|
|
490
|
-
const binaryName = agentDefinition.binaryName;
|
|
491
|
-
return { agentId: resolvedAgentId, binaryName, spawnConfig };
|
|
540
|
+
// packages/config-mutations/src/mutations/file-mutation.ts
|
|
541
|
+
function ensureDirectory(options) {
|
|
542
|
+
return {
|
|
543
|
+
kind: "ensureDirectory",
|
|
544
|
+
path: options.path,
|
|
545
|
+
label: options.label
|
|
546
|
+
};
|
|
492
547
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
548
|
+
function remove(options) {
|
|
549
|
+
return {
|
|
550
|
+
kind: "removeFile",
|
|
551
|
+
target: options.target,
|
|
552
|
+
whenEmpty: options.whenEmpty,
|
|
553
|
+
whenContentMatches: options.whenContentMatches,
|
|
554
|
+
label: options.label
|
|
555
|
+
};
|
|
500
556
|
}
|
|
501
|
-
function
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
508
|
-
if (!config.mcpArgs) {
|
|
509
|
-
return [];
|
|
510
|
-
}
|
|
511
|
-
return config.mcpArgs(servers);
|
|
557
|
+
function removeDirectory(options) {
|
|
558
|
+
return {
|
|
559
|
+
kind: "removeDirectory",
|
|
560
|
+
path: options.path,
|
|
561
|
+
force: options.force,
|
|
562
|
+
label: options.label
|
|
563
|
+
};
|
|
512
564
|
}
|
|
513
|
-
function
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
565
|
+
function chmod(options) {
|
|
566
|
+
return {
|
|
567
|
+
kind: "chmod",
|
|
568
|
+
target: options.target,
|
|
569
|
+
mode: options.mode,
|
|
570
|
+
label: options.label
|
|
571
|
+
};
|
|
518
572
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
573
|
+
function backup(options) {
|
|
574
|
+
return {
|
|
575
|
+
kind: "backup",
|
|
576
|
+
target: options.target,
|
|
577
|
+
label: options.label
|
|
578
|
+
};
|
|
524
579
|
}
|
|
580
|
+
var fileMutation = {
|
|
581
|
+
ensureDirectory,
|
|
582
|
+
remove,
|
|
583
|
+
removeDirectory,
|
|
584
|
+
chmod,
|
|
585
|
+
backup
|
|
586
|
+
};
|
|
525
587
|
|
|
526
|
-
// packages/
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
588
|
+
// packages/config-mutations/src/execution/apply-mutation.ts
|
|
589
|
+
import Mustache from "mustache";
|
|
590
|
+
|
|
591
|
+
// packages/config-mutations/src/formats/json.ts
|
|
592
|
+
import * as jsonc from "jsonc-parser";
|
|
593
|
+
function isConfigObject(value) {
|
|
594
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
595
|
+
}
|
|
596
|
+
function parse2(content) {
|
|
597
|
+
if (!content || content.trim() === "") {
|
|
598
|
+
return {};
|
|
531
599
|
}
|
|
532
|
-
|
|
533
|
-
|
|
600
|
+
const errors = [];
|
|
601
|
+
const parsed = jsonc.parse(content, errors, {
|
|
602
|
+
allowTrailingComma: true,
|
|
603
|
+
disallowComments: false
|
|
604
|
+
});
|
|
605
|
+
if (errors.length > 0) {
|
|
606
|
+
throw new Error(`JSON parse error: ${jsonc.printParseErrorCode(errors[0].error)}`);
|
|
534
607
|
}
|
|
535
|
-
if (
|
|
536
|
-
|
|
608
|
+
if (parsed === null || parsed === void 0) {
|
|
609
|
+
return {};
|
|
537
610
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
};
|
|
611
|
+
if (!isConfigObject(parsed)) {
|
|
612
|
+
throw new Error("Expected JSON object.");
|
|
613
|
+
}
|
|
614
|
+
return parsed;
|
|
543
615
|
}
|
|
544
|
-
function
|
|
545
|
-
return
|
|
616
|
+
function serialize(obj) {
|
|
617
|
+
return `${JSON.stringify(obj, null, 2)}
|
|
618
|
+
`;
|
|
546
619
|
}
|
|
547
|
-
function
|
|
548
|
-
|
|
549
|
-
|
|
620
|
+
function merge2(base, patch) {
|
|
621
|
+
const result = { ...base };
|
|
622
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
623
|
+
if (value === void 0) {
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
const existing = result[key];
|
|
627
|
+
if (isConfigObject(existing) && isConfigObject(value)) {
|
|
628
|
+
result[key] = merge2(existing, value);
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
result[key] = value;
|
|
550
632
|
}
|
|
551
|
-
return
|
|
633
|
+
return result;
|
|
552
634
|
}
|
|
553
|
-
function
|
|
554
|
-
|
|
555
|
-
const
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
}
|
|
584
|
-
if (mcpArgsPosition === "afterCommand") {
|
|
585
|
-
args.push(...mcpArgs);
|
|
586
|
-
}
|
|
587
|
-
const mode = resolveModeConfig(config.modes[options.mode ?? "yolo"]);
|
|
588
|
-
args.push(...mode.args);
|
|
589
|
-
if (options.args && options.args.length > 0) {
|
|
590
|
-
args.push(...options.args);
|
|
635
|
+
function prune2(obj, shape) {
|
|
636
|
+
let changed = false;
|
|
637
|
+
const result = { ...obj };
|
|
638
|
+
for (const [key, pattern] of Object.entries(shape)) {
|
|
639
|
+
if (!(key in result)) {
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
const current = result[key];
|
|
643
|
+
if (isConfigObject(pattern) && Object.keys(pattern).length === 0) {
|
|
644
|
+
delete result[key];
|
|
645
|
+
changed = true;
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
if (isConfigObject(pattern) && isConfigObject(current)) {
|
|
649
|
+
const { changed: childChanged, result: childResult } = prune2(
|
|
650
|
+
current,
|
|
651
|
+
pattern
|
|
652
|
+
);
|
|
653
|
+
if (childChanged) {
|
|
654
|
+
changed = true;
|
|
655
|
+
}
|
|
656
|
+
if (Object.keys(childResult).length === 0) {
|
|
657
|
+
delete result[key];
|
|
658
|
+
} else {
|
|
659
|
+
result[key] = childResult;
|
|
660
|
+
}
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
delete result[key];
|
|
664
|
+
changed = true;
|
|
591
665
|
}
|
|
592
|
-
return {
|
|
593
|
-
}
|
|
594
|
-
function buildSpawnArgs(agentId, options) {
|
|
595
|
-
const { binaryName, spawnConfig } = resolveCliConfig(agentId);
|
|
596
|
-
const stdinMode = options.useStdin && spawnConfig.stdinMode ? spawnConfig.stdinMode : void 0;
|
|
597
|
-
const result = buildCliArgs(spawnConfig, options, stdinMode);
|
|
598
|
-
return { binaryName, args: result.args, env: result.env };
|
|
666
|
+
return { changed, result };
|
|
599
667
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
import chalk from "chalk";
|
|
606
|
-
var dark = {
|
|
607
|
-
header: (text4) => chalk.magentaBright.bold(text4),
|
|
608
|
-
divider: (text4) => chalk.dim(text4),
|
|
609
|
-
prompt: (text4) => chalk.cyan(text4),
|
|
610
|
-
number: (text4) => chalk.cyanBright(text4),
|
|
611
|
-
intro: (text4) => chalk.bgMagenta.white(` Poe - ${text4} `),
|
|
612
|
-
resolvedSymbol: chalk.magenta("\u25C7"),
|
|
613
|
-
errorSymbol: chalk.red("\u25A0"),
|
|
614
|
-
accent: (text4) => chalk.cyan(text4),
|
|
615
|
-
muted: (text4) => chalk.dim(text4),
|
|
616
|
-
success: (text4) => chalk.green(text4),
|
|
617
|
-
warning: (text4) => chalk.yellow(text4),
|
|
618
|
-
error: (text4) => chalk.red(text4),
|
|
619
|
-
info: (text4) => chalk.magenta(text4),
|
|
620
|
-
badge: (text4) => chalk.bgYellow.black(` ${text4} `)
|
|
621
|
-
};
|
|
622
|
-
var light = {
|
|
623
|
-
header: (text4) => chalk.hex("#a200ff").bold(text4),
|
|
624
|
-
divider: (text4) => chalk.hex("#666666")(text4),
|
|
625
|
-
prompt: (text4) => chalk.hex("#006699").bold(text4),
|
|
626
|
-
number: (text4) => chalk.hex("#0077cc").bold(text4),
|
|
627
|
-
intro: (text4) => chalk.bgHex("#a200ff").white(` Poe - ${text4} `),
|
|
628
|
-
resolvedSymbol: chalk.hex("#a200ff")("\u25C7"),
|
|
629
|
-
errorSymbol: chalk.hex("#cc0000")("\u25A0"),
|
|
630
|
-
accent: (text4) => chalk.hex("#006699").bold(text4),
|
|
631
|
-
muted: (text4) => chalk.hex("#666666")(text4),
|
|
632
|
-
success: (text4) => chalk.hex("#008800")(text4),
|
|
633
|
-
warning: (text4) => chalk.hex("#cc6600")(text4),
|
|
634
|
-
error: (text4) => chalk.hex("#cc0000")(text4),
|
|
635
|
-
info: (text4) => chalk.hex("#a200ff")(text4),
|
|
636
|
-
badge: (text4) => chalk.bgHex("#cc6600").white(` ${text4} `)
|
|
668
|
+
var jsonFormat = {
|
|
669
|
+
parse: parse2,
|
|
670
|
+
serialize,
|
|
671
|
+
merge: merge2,
|
|
672
|
+
prune: prune2
|
|
637
673
|
};
|
|
638
674
|
|
|
639
|
-
// packages/
|
|
640
|
-
import
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
|
|
648
|
-
var formatStorage = new AsyncLocalStorage();
|
|
649
|
-
var cached;
|
|
650
|
-
function resolveOutputFormat(env = process.env) {
|
|
651
|
-
const scoped = formatStorage.getStore();
|
|
652
|
-
if (scoped) {
|
|
653
|
-
return scoped;
|
|
675
|
+
// packages/config-mutations/src/formats/toml.ts
|
|
676
|
+
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
677
|
+
function isConfigObject2(value) {
|
|
678
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
679
|
+
}
|
|
680
|
+
function parse3(content) {
|
|
681
|
+
if (!content || content.trim() === "") {
|
|
682
|
+
return {};
|
|
654
683
|
}
|
|
655
|
-
|
|
656
|
-
|
|
684
|
+
const parsed = parseToml(content);
|
|
685
|
+
if (!isConfigObject2(parsed)) {
|
|
686
|
+
throw new Error("Expected TOML document to be a table.");
|
|
657
687
|
}
|
|
658
|
-
|
|
659
|
-
cached = VALID_FORMATS.has(raw) ? raw : "terminal";
|
|
660
|
-
return cached;
|
|
688
|
+
return parsed;
|
|
661
689
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
if (normalized.includes("light")) {
|
|
673
|
-
return "light";
|
|
690
|
+
function serialize2(obj) {
|
|
691
|
+
const serialized = stringifyToml(obj);
|
|
692
|
+
return serialized.endsWith("\n") ? serialized : `${serialized}
|
|
693
|
+
`;
|
|
694
|
+
}
|
|
695
|
+
function merge3(base, patch) {
|
|
696
|
+
const result = { ...base };
|
|
697
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
698
|
+
if (value === void 0) {
|
|
699
|
+
continue;
|
|
674
700
|
}
|
|
675
|
-
|
|
676
|
-
|
|
701
|
+
const existing = result[key];
|
|
702
|
+
if (isConfigObject2(existing) && isConfigObject2(value)) {
|
|
703
|
+
result[key] = merge3(existing, value);
|
|
704
|
+
continue;
|
|
677
705
|
}
|
|
706
|
+
result[key] = value;
|
|
678
707
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
708
|
+
return result;
|
|
709
|
+
}
|
|
710
|
+
function prune3(obj, shape) {
|
|
711
|
+
let changed = false;
|
|
712
|
+
const result = { ...obj };
|
|
713
|
+
for (const [key, pattern] of Object.entries(shape)) {
|
|
714
|
+
if (!(key in result)) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const current = result[key];
|
|
718
|
+
if (isConfigObject2(pattern) && Object.keys(pattern).length === 0) {
|
|
719
|
+
delete result[key];
|
|
720
|
+
changed = true;
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if (isConfigObject2(pattern) && isConfigObject2(current)) {
|
|
724
|
+
const { changed: childChanged, result: childResult } = prune3(
|
|
725
|
+
current,
|
|
726
|
+
pattern
|
|
727
|
+
);
|
|
728
|
+
if (childChanged) {
|
|
729
|
+
changed = true;
|
|
730
|
+
}
|
|
731
|
+
if (Object.keys(childResult).length === 0) {
|
|
732
|
+
delete result[key];
|
|
733
|
+
} else {
|
|
734
|
+
result[key] = childResult;
|
|
735
|
+
}
|
|
736
|
+
continue;
|
|
685
737
|
}
|
|
738
|
+
delete result[key];
|
|
739
|
+
changed = true;
|
|
686
740
|
}
|
|
687
|
-
return
|
|
741
|
+
return { changed, result };
|
|
688
742
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
743
|
+
var tomlFormat = {
|
|
744
|
+
parse: parse3,
|
|
745
|
+
serialize: serialize2,
|
|
746
|
+
merge: merge3,
|
|
747
|
+
prune: prune3
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
// packages/config-mutations/src/formats/yaml.ts
|
|
751
|
+
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
752
|
+
function isConfigObject3(value) {
|
|
753
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
754
|
+
}
|
|
755
|
+
function parse4(content) {
|
|
756
|
+
if (!content || content.trim() === "") {
|
|
757
|
+
return {};
|
|
693
758
|
}
|
|
694
|
-
const
|
|
695
|
-
if (
|
|
696
|
-
return
|
|
759
|
+
const parsed = parseYaml2(content);
|
|
760
|
+
if (parsed === null || parsed === void 0) {
|
|
761
|
+
return {};
|
|
697
762
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
var cachedTheme;
|
|
701
|
-
function getTheme(env) {
|
|
702
|
-
if (cachedTheme) {
|
|
703
|
-
return cachedTheme;
|
|
763
|
+
if (!isConfigObject3(parsed)) {
|
|
764
|
+
throw new Error("Expected YAML object.");
|
|
704
765
|
}
|
|
705
|
-
|
|
706
|
-
cachedTheme = themeName === "light" ? light : dark;
|
|
707
|
-
return cachedTheme;
|
|
766
|
+
return parsed;
|
|
708
767
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
get info() {
|
|
714
|
-
const format = resolveOutputFormat();
|
|
715
|
-
if (format === "json") return "info";
|
|
716
|
-
if (format === "markdown") return "(i)";
|
|
717
|
-
return chalk4.magenta("\u25CF");
|
|
718
|
-
},
|
|
719
|
-
get success() {
|
|
720
|
-
const format = resolveOutputFormat();
|
|
721
|
-
if (format === "json") return "success";
|
|
722
|
-
if (format === "markdown") return "[ok]";
|
|
723
|
-
return chalk4.magenta("\u25C6");
|
|
724
|
-
},
|
|
725
|
-
get resolved() {
|
|
726
|
-
const format = resolveOutputFormat();
|
|
727
|
-
if (format === "json") return "resolved";
|
|
728
|
-
if (format === "markdown") return ">";
|
|
729
|
-
return getTheme().resolvedSymbol;
|
|
730
|
-
},
|
|
731
|
-
get errorResolved() {
|
|
732
|
-
const format = resolveOutputFormat();
|
|
733
|
-
if (format === "json") return "error";
|
|
734
|
-
if (format === "markdown") return "[!]";
|
|
735
|
-
return getTheme().errorSymbol;
|
|
736
|
-
},
|
|
737
|
-
get bar() {
|
|
738
|
-
const format = resolveOutputFormat();
|
|
739
|
-
if (format === "json") return "";
|
|
740
|
-
if (format === "markdown") return "|";
|
|
741
|
-
return "\u2502";
|
|
742
|
-
},
|
|
743
|
-
cornerTopRight: "\u256E",
|
|
744
|
-
cornerBottomRight: "\u256F",
|
|
745
|
-
get warning() {
|
|
746
|
-
const format = resolveOutputFormat();
|
|
747
|
-
if (format === "json") return "warning";
|
|
748
|
-
if (format === "markdown") return "[!]";
|
|
749
|
-
return "\u25B2";
|
|
750
|
-
},
|
|
751
|
-
get active() {
|
|
752
|
-
const format = resolveOutputFormat();
|
|
753
|
-
if (format === "json") return "active";
|
|
754
|
-
if (format === "markdown") return "[x]";
|
|
755
|
-
return "\u25C6";
|
|
756
|
-
},
|
|
757
|
-
get inactive() {
|
|
758
|
-
const format = resolveOutputFormat();
|
|
759
|
-
if (format === "json") return "inactive";
|
|
760
|
-
if (format === "markdown") return "[ ]";
|
|
761
|
-
return "\u25CB";
|
|
762
|
-
}
|
|
763
|
-
};
|
|
764
|
-
|
|
765
|
-
// packages/design-system/src/components/logger.ts
|
|
766
|
-
import chalk6 from "chalk";
|
|
767
|
-
|
|
768
|
-
// packages/design-system/src/prompts/primitives/log.ts
|
|
769
|
-
import chalk5 from "chalk";
|
|
770
|
-
|
|
771
|
-
// packages/design-system/src/internal/strip-ansi.ts
|
|
772
|
-
function stripAnsi(value) {
|
|
773
|
-
return value.replace(/\u001b\[[0-9;]*m/g, "");
|
|
768
|
+
function serialize3(obj) {
|
|
769
|
+
const serialized = stringifyYaml(obj);
|
|
770
|
+
return serialized.endsWith("\n") ? serialized : `${serialized}
|
|
771
|
+
`;
|
|
774
772
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
secondarySymbol = chalk5.gray("\u2502"),
|
|
780
|
-
spacing: spacing2 = 1,
|
|
781
|
-
withGuide = true
|
|
782
|
-
} = {}) {
|
|
783
|
-
const lines = [];
|
|
784
|
-
const showGuide = withGuide !== false;
|
|
785
|
-
const contentLines = msg.split("\n");
|
|
786
|
-
const prefix = showGuide ? `${symbol} ` : "";
|
|
787
|
-
const continuationPrefix = showGuide ? `${secondarySymbol} ` : "";
|
|
788
|
-
const emptyGuide = showGuide ? secondarySymbol : "";
|
|
789
|
-
for (let index = 0; index < spacing2; index += 1) {
|
|
790
|
-
lines.push(emptyGuide);
|
|
791
|
-
}
|
|
792
|
-
if (contentLines.length === 0) {
|
|
793
|
-
process.stdout.write("\n");
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
const [firstLine = "", ...continuationLines] = contentLines;
|
|
797
|
-
if (firstLine.length > 0) {
|
|
798
|
-
lines.push(`${prefix}${firstLine}`);
|
|
799
|
-
} else {
|
|
800
|
-
lines.push(showGuide ? symbol : "");
|
|
801
|
-
}
|
|
802
|
-
for (const line of continuationLines) {
|
|
803
|
-
if (line.length > 0) {
|
|
804
|
-
lines.push(`${continuationPrefix}${line}`);
|
|
773
|
+
function merge4(base, patch) {
|
|
774
|
+
const result = { ...base };
|
|
775
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
776
|
+
if (value === void 0) {
|
|
805
777
|
continue;
|
|
806
778
|
}
|
|
807
|
-
|
|
779
|
+
const existing = result[key];
|
|
780
|
+
if (isConfigObject3(existing) && isConfigObject3(value)) {
|
|
781
|
+
result[key] = merge4(existing, value);
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
result[key] = value;
|
|
808
785
|
}
|
|
809
|
-
|
|
810
|
-
`);
|
|
786
|
+
return result;
|
|
811
787
|
}
|
|
812
|
-
function
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
788
|
+
function prune4(obj, shape) {
|
|
789
|
+
let changed = false;
|
|
790
|
+
const result = { ...obj };
|
|
791
|
+
for (const [key, pattern] of Object.entries(shape)) {
|
|
792
|
+
if (!(key in result)) {
|
|
793
|
+
continue;
|
|
794
|
+
}
|
|
795
|
+
const current = result[key];
|
|
796
|
+
if (isConfigObject3(pattern) && Object.keys(pattern).length === 0) {
|
|
797
|
+
delete result[key];
|
|
798
|
+
changed = true;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
if (isConfigObject3(pattern) && isConfigObject3(current)) {
|
|
802
|
+
const { changed: childChanged, result: childResult } = prune4(current, pattern);
|
|
803
|
+
if (childChanged) {
|
|
804
|
+
changed = true;
|
|
805
|
+
}
|
|
806
|
+
if (Object.keys(childResult).length === 0) {
|
|
807
|
+
delete result[key];
|
|
808
|
+
} else {
|
|
809
|
+
result[key] = childResult;
|
|
810
|
+
}
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
813
|
+
delete result[key];
|
|
814
|
+
changed = true;
|
|
825
815
|
}
|
|
826
|
-
|
|
816
|
+
return { changed, result };
|
|
827
817
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
818
|
+
var yamlFormat = {
|
|
819
|
+
parse: parse4,
|
|
820
|
+
serialize: serialize3,
|
|
821
|
+
merge: merge4,
|
|
822
|
+
prune: prune4
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
// packages/config-mutations/src/formats/index.ts
|
|
826
|
+
var formatRegistry = {
|
|
827
|
+
json: jsonFormat,
|
|
828
|
+
toml: tomlFormat,
|
|
829
|
+
yaml: yamlFormat
|
|
830
|
+
};
|
|
831
|
+
var extensionMap = {
|
|
832
|
+
".json": "json",
|
|
833
|
+
".toml": "toml",
|
|
834
|
+
".yaml": "yaml",
|
|
835
|
+
".yml": "yaml"
|
|
836
|
+
};
|
|
837
|
+
function getConfigFormat(pathOrFormat) {
|
|
838
|
+
if (pathOrFormat in formatRegistry) {
|
|
839
|
+
return formatRegistry[pathOrFormat];
|
|
834
840
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
841
|
+
const ext = getExtension(pathOrFormat);
|
|
842
|
+
const formatName = extensionMap[ext];
|
|
843
|
+
if (!formatName) {
|
|
844
|
+
throw new Error(
|
|
845
|
+
`Unsupported config format. Cannot detect format from "${pathOrFormat}". Supported extensions: ${Object.keys(extensionMap).join(", ")}. Supported format names: ${Object.keys(formatRegistry).join(", ")}.`
|
|
839
846
|
);
|
|
840
|
-
return;
|
|
841
847
|
}
|
|
842
|
-
|
|
848
|
+
return formatRegistry[formatName];
|
|
843
849
|
}
|
|
844
|
-
function
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
process.stdout.write(
|
|
853
|
-
`${JSON.stringify({ level: "success", message: stripAnsi(msg) })}
|
|
854
|
-
`
|
|
855
|
-
);
|
|
856
|
-
return;
|
|
850
|
+
function detectFormat(path18) {
|
|
851
|
+
const ext = getExtension(path18);
|
|
852
|
+
return extensionMap[ext];
|
|
853
|
+
}
|
|
854
|
+
function getExtension(path18) {
|
|
855
|
+
const lastDot = path18.lastIndexOf(".");
|
|
856
|
+
if (lastDot === -1) {
|
|
857
|
+
return "";
|
|
857
858
|
}
|
|
858
|
-
|
|
859
|
+
return path18.slice(lastDot).toLowerCase();
|
|
859
860
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
return;
|
|
861
|
+
|
|
862
|
+
// packages/config-mutations/src/execution/path-utils.ts
|
|
863
|
+
import path7 from "node:path";
|
|
864
|
+
function expandHome(targetPath, homeDir) {
|
|
865
|
+
if (!targetPath?.startsWith("~")) {
|
|
866
|
+
return targetPath;
|
|
866
867
|
}
|
|
867
|
-
if (
|
|
868
|
-
|
|
869
|
-
`${JSON.stringify({ level: "warn", message: stripAnsi(msg) })}
|
|
870
|
-
`
|
|
871
|
-
);
|
|
872
|
-
return;
|
|
868
|
+
if (targetPath.startsWith("~./")) {
|
|
869
|
+
targetPath = `~/.${targetPath.slice(3)}`;
|
|
873
870
|
}
|
|
874
|
-
|
|
871
|
+
let remainder = targetPath.slice(1);
|
|
872
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
873
|
+
remainder = remainder.slice(1);
|
|
874
|
+
} else if (remainder.startsWith(".")) {
|
|
875
|
+
remainder = remainder.slice(1);
|
|
876
|
+
if (remainder.startsWith("/") || remainder.startsWith("\\")) {
|
|
877
|
+
remainder = remainder.slice(1);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return remainder.length === 0 ? homeDir : path7.join(homeDir, remainder);
|
|
875
881
|
}
|
|
876
|
-
function
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
process.stdout.write(`- **error:** ${stripAnsi(msg)}
|
|
880
|
-
`);
|
|
881
|
-
return;
|
|
882
|
+
function validateHomePath(targetPath) {
|
|
883
|
+
if (typeof targetPath !== "string" || targetPath.length === 0) {
|
|
884
|
+
throw new Error("Target path must be a non-empty string.");
|
|
882
885
|
}
|
|
883
|
-
if (
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
`
|
|
886
|
+
if (!targetPath.startsWith("~")) {
|
|
887
|
+
throw new Error(
|
|
888
|
+
`All target paths must be home-relative (start with ~). Received: "${targetPath}"`
|
|
887
889
|
);
|
|
888
|
-
return;
|
|
889
890
|
}
|
|
890
|
-
message(msg, { symbol: chalk5.red("\u25A0") });
|
|
891
891
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
892
|
+
function resolvePath(rawPath, homeDir, pathMapper) {
|
|
893
|
+
validateHomePath(rawPath);
|
|
894
|
+
const expanded = expandHome(rawPath, homeDir);
|
|
895
|
+
if (!pathMapper) {
|
|
896
|
+
return expanded;
|
|
897
|
+
}
|
|
898
|
+
const rawDirectory = path7.dirname(expanded);
|
|
899
|
+
const mappedDirectory = pathMapper.mapTargetDirectory({
|
|
900
|
+
targetDirectory: rawDirectory
|
|
901
|
+
});
|
|
902
|
+
const filename = path7.basename(expanded);
|
|
903
|
+
return filename.length === 0 ? mappedDirectory : path7.join(mappedDirectory, filename);
|
|
904
|
+
}
|
|
899
905
|
|
|
900
|
-
// packages/
|
|
901
|
-
function
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
+
// packages/config-mutations/src/fs-utils.ts
|
|
907
|
+
function isNotFound(error2) {
|
|
908
|
+
return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
|
|
909
|
+
}
|
|
910
|
+
async function readFileIfExists(fs, target) {
|
|
911
|
+
try {
|
|
912
|
+
return await fs.readFile(target, "utf8");
|
|
913
|
+
} catch (error2) {
|
|
914
|
+
if (isNotFound(error2)) {
|
|
915
|
+
return null;
|
|
906
916
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
917
|
+
throw error2;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
async function pathExists(fs, target) {
|
|
921
|
+
try {
|
|
922
|
+
await fs.stat(target);
|
|
923
|
+
return true;
|
|
924
|
+
} catch (error2) {
|
|
925
|
+
if (isNotFound(error2)) {
|
|
926
|
+
return false;
|
|
910
927
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
928
|
+
throw error2;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function createTimestamp() {
|
|
932
|
+
return (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-").replaceAll(".", "-");
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// packages/config-mutations/src/execution/apply-mutation.ts
|
|
936
|
+
function resolveValue(resolver, options) {
|
|
937
|
+
if (typeof resolver === "function") {
|
|
938
|
+
return resolver(options);
|
|
939
|
+
}
|
|
940
|
+
return resolver;
|
|
941
|
+
}
|
|
942
|
+
function createInvalidDocumentBackupPath(targetPath) {
|
|
943
|
+
const ext = targetPath.includes(".") ? targetPath.split(".").pop() : "bak";
|
|
944
|
+
return `${targetPath}.invalid-${createTimestamp()}.${ext}`;
|
|
945
|
+
}
|
|
946
|
+
async function backupInvalidDocument(fs, targetPath, content) {
|
|
947
|
+
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
948
|
+
await fs.writeFile(backupPath, content, { encoding: "utf8" });
|
|
949
|
+
}
|
|
950
|
+
function describeMutation(kind, targetPath) {
|
|
951
|
+
const displayPath = targetPath ?? "target";
|
|
952
|
+
switch (kind) {
|
|
953
|
+
case "ensureDirectory":
|
|
954
|
+
return `Create ${displayPath}`;
|
|
955
|
+
case "removeDirectory":
|
|
956
|
+
return `Remove directory ${displayPath}`;
|
|
957
|
+
case "backup":
|
|
958
|
+
return `Backup ${displayPath}`;
|
|
959
|
+
case "templateWrite":
|
|
960
|
+
return `Write ${displayPath}`;
|
|
961
|
+
case "chmod":
|
|
962
|
+
return `Set permissions on ${displayPath}`;
|
|
963
|
+
case "removeFile":
|
|
964
|
+
return `Remove ${displayPath}`;
|
|
965
|
+
case "configMerge":
|
|
966
|
+
case "configPrune":
|
|
967
|
+
case "configTransform":
|
|
968
|
+
case "templateMergeToml":
|
|
969
|
+
case "templateMergeJson":
|
|
970
|
+
return `Update ${displayPath}`;
|
|
971
|
+
default:
|
|
972
|
+
return "Operation";
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
function pruneKeysByPrefix(table, prefix) {
|
|
976
|
+
const result = {};
|
|
977
|
+
for (const [key, value] of Object.entries(table)) {
|
|
978
|
+
if (!key.startsWith(prefix)) {
|
|
979
|
+
result[key] = value;
|
|
914
980
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
981
|
+
}
|
|
982
|
+
return result;
|
|
983
|
+
}
|
|
984
|
+
function isConfigObject4(value) {
|
|
985
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
986
|
+
}
|
|
987
|
+
function mergeWithPruneByPrefix(base, patch, pruneByPrefix) {
|
|
988
|
+
const result = { ...base };
|
|
989
|
+
const prefixMap = pruneByPrefix ?? {};
|
|
990
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
991
|
+
const current = result[key];
|
|
992
|
+
const prefix = prefixMap[key];
|
|
993
|
+
if (isConfigObject4(current) && isConfigObject4(value)) {
|
|
994
|
+
if (prefix) {
|
|
995
|
+
const pruned = pruneKeysByPrefix(current, prefix);
|
|
996
|
+
result[key] = { ...pruned, ...value };
|
|
997
|
+
} else {
|
|
998
|
+
result[key] = mergeWithPruneByPrefix(
|
|
999
|
+
current,
|
|
1000
|
+
value,
|
|
1001
|
+
prefixMap
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
continue;
|
|
918
1005
|
}
|
|
919
|
-
|
|
1006
|
+
result[key] = value;
|
|
1007
|
+
}
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
1010
|
+
async function applyMutation(mutation, context, options) {
|
|
1011
|
+
switch (mutation.kind) {
|
|
1012
|
+
case "ensureDirectory":
|
|
1013
|
+
return applyEnsureDirectory(mutation, context, options);
|
|
1014
|
+
case "removeDirectory":
|
|
1015
|
+
return applyRemoveDirectory(mutation, context, options);
|
|
1016
|
+
case "removeFile":
|
|
1017
|
+
return applyRemoveFile(mutation, context, options);
|
|
1018
|
+
case "chmod":
|
|
1019
|
+
return applyChmod(mutation, context, options);
|
|
1020
|
+
case "backup":
|
|
1021
|
+
return applyBackup(mutation, context, options);
|
|
1022
|
+
case "configMerge":
|
|
1023
|
+
return applyConfigMerge(mutation, context, options);
|
|
1024
|
+
case "configPrune":
|
|
1025
|
+
return applyConfigPrune(mutation, context, options);
|
|
1026
|
+
case "configTransform":
|
|
1027
|
+
return applyConfigTransform(mutation, context, options);
|
|
1028
|
+
case "templateWrite":
|
|
1029
|
+
return applyTemplateWrite(mutation, context, options);
|
|
1030
|
+
case "templateMergeToml":
|
|
1031
|
+
return applyTemplateMerge(mutation, context, options, "toml");
|
|
1032
|
+
case "templateMergeJson":
|
|
1033
|
+
return applyTemplateMerge(mutation, context, options, "json");
|
|
1034
|
+
default: {
|
|
1035
|
+
const never = mutation;
|
|
1036
|
+
throw new Error(`Unknown mutation kind: ${never.kind}`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
async function applyEnsureDirectory(mutation, context, options) {
|
|
1041
|
+
const rawPath = resolveValue(mutation.path, options);
|
|
1042
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1043
|
+
const details = {
|
|
1044
|
+
kind: mutation.kind,
|
|
1045
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1046
|
+
targetPath
|
|
920
1047
|
};
|
|
1048
|
+
const existed = await pathExists(context.fs, targetPath);
|
|
1049
|
+
if (!context.dryRun) {
|
|
1050
|
+
await context.fs.mkdir(targetPath, { recursive: true });
|
|
1051
|
+
}
|
|
921
1052
|
return {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
emit("success", message2);
|
|
927
|
-
},
|
|
928
|
-
warn(message2) {
|
|
929
|
-
emit("warn", message2);
|
|
930
|
-
},
|
|
931
|
-
error(message2) {
|
|
932
|
-
emit("error", message2);
|
|
933
|
-
},
|
|
934
|
-
resolved(label, value) {
|
|
935
|
-
if (emitter) {
|
|
936
|
-
emitter(`${label}: ${value}`);
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
log.message(`${label}
|
|
940
|
-
${value}`, { symbol: symbols.resolved });
|
|
941
|
-
},
|
|
942
|
-
errorResolved(label, value) {
|
|
943
|
-
if (emitter) {
|
|
944
|
-
emitter(`${label}: ${value}`);
|
|
945
|
-
return;
|
|
946
|
-
}
|
|
947
|
-
log.message(`${label}
|
|
948
|
-
${value}`, { symbol: symbols.errorResolved });
|
|
1053
|
+
outcome: {
|
|
1054
|
+
changed: !existed,
|
|
1055
|
+
effect: "mkdir",
|
|
1056
|
+
detail: existed ? "noop" : "create"
|
|
949
1057
|
},
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1058
|
+
details
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
async function applyRemoveDirectory(mutation, context, options) {
|
|
1062
|
+
const rawPath = resolveValue(mutation.path, options);
|
|
1063
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1064
|
+
const details = {
|
|
1065
|
+
kind: mutation.kind,
|
|
1066
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1067
|
+
targetPath
|
|
1068
|
+
};
|
|
1069
|
+
const existed = await pathExists(context.fs, targetPath);
|
|
1070
|
+
if (!existed) {
|
|
1071
|
+
return {
|
|
1072
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1073
|
+
details
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof context.fs.rm !== "function") {
|
|
1077
|
+
return {
|
|
1078
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1079
|
+
details
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
if (mutation.force) {
|
|
1083
|
+
if (!context.dryRun) {
|
|
1084
|
+
await context.fs.rm(targetPath, { recursive: true, force: true });
|
|
956
1085
|
}
|
|
1086
|
+
return {
|
|
1087
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1088
|
+
details
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
const entries = await context.fs.readdir(targetPath);
|
|
1092
|
+
if (entries.length > 0) {
|
|
1093
|
+
return {
|
|
1094
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1095
|
+
details
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
if (!context.dryRun) {
|
|
1099
|
+
await context.fs.rm(targetPath, { recursive: true, force: true });
|
|
1100
|
+
}
|
|
1101
|
+
return {
|
|
1102
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1103
|
+
details
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
async function applyRemoveFile(mutation, context, options) {
|
|
1107
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1108
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1109
|
+
const details = {
|
|
1110
|
+
kind: mutation.kind,
|
|
1111
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1112
|
+
targetPath
|
|
1113
|
+
};
|
|
1114
|
+
try {
|
|
1115
|
+
const content = await context.fs.readFile(targetPath, "utf8");
|
|
1116
|
+
const trimmed = content.trim();
|
|
1117
|
+
if (mutation.whenContentMatches && !mutation.whenContentMatches.test(trimmed)) {
|
|
1118
|
+
return {
|
|
1119
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1120
|
+
details
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
if (mutation.whenEmpty && trimmed.length > 0) {
|
|
1124
|
+
return {
|
|
1125
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1126
|
+
details
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
if (!context.dryRun) {
|
|
1130
|
+
await context.fs.unlink(targetPath);
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1134
|
+
details
|
|
1135
|
+
};
|
|
1136
|
+
} catch (error2) {
|
|
1137
|
+
if (isNotFound(error2)) {
|
|
1138
|
+
return {
|
|
1139
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1140
|
+
details
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
throw error2;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
async function applyChmod(mutation, context, options) {
|
|
1147
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1148
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1149
|
+
const details = {
|
|
1150
|
+
kind: mutation.kind,
|
|
1151
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1152
|
+
targetPath
|
|
1153
|
+
};
|
|
1154
|
+
if (typeof context.fs.chmod !== "function") {
|
|
1155
|
+
return {
|
|
1156
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1157
|
+
details
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
try {
|
|
1161
|
+
const stat2 = await context.fs.stat(targetPath);
|
|
1162
|
+
const currentMode = typeof stat2.mode === "number" ? stat2.mode & 511 : null;
|
|
1163
|
+
if (currentMode === mutation.mode) {
|
|
1164
|
+
return {
|
|
1165
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1166
|
+
details
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
if (!context.dryRun) {
|
|
1170
|
+
await context.fs.chmod(targetPath, mutation.mode);
|
|
1171
|
+
}
|
|
1172
|
+
return {
|
|
1173
|
+
outcome: { changed: true, effect: "chmod", detail: "update" },
|
|
1174
|
+
details
|
|
1175
|
+
};
|
|
1176
|
+
} catch (error2) {
|
|
1177
|
+
if (isNotFound(error2)) {
|
|
1178
|
+
return {
|
|
1179
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1180
|
+
details
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
throw error2;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
async function applyBackup(mutation, context, options) {
|
|
1187
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1188
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1189
|
+
const details = {
|
|
1190
|
+
kind: mutation.kind,
|
|
1191
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1192
|
+
targetPath
|
|
1193
|
+
};
|
|
1194
|
+
const content = await readFileIfExists(context.fs, targetPath);
|
|
1195
|
+
if (content === null) {
|
|
1196
|
+
return {
|
|
1197
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1198
|
+
details
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
if (!context.dryRun) {
|
|
1202
|
+
const backupPath = `${targetPath}.backup-${createTimestamp()}`;
|
|
1203
|
+
await context.fs.writeFile(backupPath, content, { encoding: "utf8" });
|
|
1204
|
+
}
|
|
1205
|
+
return {
|
|
1206
|
+
outcome: { changed: true, effect: "copy", detail: "backup" },
|
|
1207
|
+
details
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
async function applyConfigMerge(mutation, context, options) {
|
|
1211
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1212
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1213
|
+
const details = {
|
|
1214
|
+
kind: mutation.kind,
|
|
1215
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1216
|
+
targetPath
|
|
1217
|
+
};
|
|
1218
|
+
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
1219
|
+
if (!formatName) {
|
|
1220
|
+
throw new Error(
|
|
1221
|
+
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
const format = getConfigFormat(formatName);
|
|
1225
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
1226
|
+
let current;
|
|
1227
|
+
try {
|
|
1228
|
+
current = rawContent === null ? {} : format.parse(rawContent);
|
|
1229
|
+
} catch {
|
|
1230
|
+
if (rawContent !== null) {
|
|
1231
|
+
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
1232
|
+
}
|
|
1233
|
+
current = {};
|
|
1234
|
+
}
|
|
1235
|
+
const value = resolveValue(mutation.value, options);
|
|
1236
|
+
let merged;
|
|
1237
|
+
if (mutation.pruneByPrefix) {
|
|
1238
|
+
merged = mergeWithPruneByPrefix(current, value, mutation.pruneByPrefix);
|
|
1239
|
+
} else {
|
|
1240
|
+
merged = format.merge(current, value);
|
|
1241
|
+
}
|
|
1242
|
+
const serialized = format.serialize(merged);
|
|
1243
|
+
const changed = serialized !== rawContent;
|
|
1244
|
+
if (changed && !context.dryRun) {
|
|
1245
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
1246
|
+
}
|
|
1247
|
+
return {
|
|
1248
|
+
outcome: {
|
|
1249
|
+
changed,
|
|
1250
|
+
effect: changed ? "write" : "none",
|
|
1251
|
+
detail: changed ? rawContent === null ? "create" : "update" : "noop"
|
|
1252
|
+
},
|
|
1253
|
+
details
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
async function applyConfigPrune(mutation, context, options) {
|
|
1257
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1258
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1259
|
+
const details = {
|
|
1260
|
+
kind: mutation.kind,
|
|
1261
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1262
|
+
targetPath
|
|
1263
|
+
};
|
|
1264
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
1265
|
+
if (rawContent === null) {
|
|
1266
|
+
return {
|
|
1267
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1268
|
+
details
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
1272
|
+
if (!formatName) {
|
|
1273
|
+
throw new Error(
|
|
1274
|
+
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
1275
|
+
);
|
|
1276
|
+
}
|
|
1277
|
+
const format = getConfigFormat(formatName);
|
|
1278
|
+
let current;
|
|
1279
|
+
try {
|
|
1280
|
+
current = format.parse(rawContent);
|
|
1281
|
+
} catch {
|
|
1282
|
+
return {
|
|
1283
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1284
|
+
details
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
if (mutation.onlyIf && !mutation.onlyIf(current, options)) {
|
|
1288
|
+
return {
|
|
1289
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1290
|
+
details
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
const shape = resolveValue(mutation.shape, options);
|
|
1294
|
+
const { changed, result } = format.prune(current, shape);
|
|
1295
|
+
if (!changed) {
|
|
1296
|
+
return {
|
|
1297
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1298
|
+
details
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
if (Object.keys(result).length === 0) {
|
|
1302
|
+
if (!context.dryRun) {
|
|
1303
|
+
await context.fs.unlink(targetPath);
|
|
1304
|
+
}
|
|
1305
|
+
return {
|
|
1306
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1307
|
+
details
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
const serialized = format.serialize(result);
|
|
1311
|
+
if (!context.dryRun) {
|
|
1312
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
1313
|
+
}
|
|
1314
|
+
return {
|
|
1315
|
+
outcome: { changed: true, effect: "write", detail: "update" },
|
|
1316
|
+
details
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
async function applyConfigTransform(mutation, context, options) {
|
|
1320
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1321
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1322
|
+
const details = {
|
|
1323
|
+
kind: mutation.kind,
|
|
1324
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1325
|
+
targetPath
|
|
1326
|
+
};
|
|
1327
|
+
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
1328
|
+
if (!formatName) {
|
|
1329
|
+
throw new Error(
|
|
1330
|
+
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
const format = getConfigFormat(formatName);
|
|
1334
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
1335
|
+
let current;
|
|
1336
|
+
try {
|
|
1337
|
+
current = rawContent === null ? {} : format.parse(rawContent);
|
|
1338
|
+
} catch {
|
|
1339
|
+
if (rawContent !== null) {
|
|
1340
|
+
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
1341
|
+
}
|
|
1342
|
+
current = {};
|
|
1343
|
+
}
|
|
1344
|
+
const { content: transformed, changed } = mutation.transform(current, options);
|
|
1345
|
+
if (!changed) {
|
|
1346
|
+
return {
|
|
1347
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1348
|
+
details
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
if (transformed === null) {
|
|
1352
|
+
if (rawContent === null) {
|
|
1353
|
+
return {
|
|
1354
|
+
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1355
|
+
details
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
if (!context.dryRun) {
|
|
1359
|
+
await context.fs.unlink(targetPath);
|
|
1360
|
+
}
|
|
1361
|
+
return {
|
|
1362
|
+
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1363
|
+
details
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
const serialized = format.serialize(transformed);
|
|
1367
|
+
if (!context.dryRun) {
|
|
1368
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
1369
|
+
}
|
|
1370
|
+
return {
|
|
1371
|
+
outcome: {
|
|
1372
|
+
changed: true,
|
|
1373
|
+
effect: "write",
|
|
1374
|
+
detail: rawContent === null ? "create" : "update"
|
|
1375
|
+
},
|
|
1376
|
+
details
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
async function applyTemplateWrite(mutation, context, options) {
|
|
1380
|
+
if (!context.templates) {
|
|
1381
|
+
throw new Error(
|
|
1382
|
+
"Template mutations require a templates loader. Provide templates function to runMutations context."
|
|
1383
|
+
);
|
|
1384
|
+
}
|
|
1385
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1386
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1387
|
+
const details = {
|
|
1388
|
+
kind: mutation.kind,
|
|
1389
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1390
|
+
targetPath
|
|
1391
|
+
};
|
|
1392
|
+
const template = await context.templates(mutation.templateId);
|
|
1393
|
+
const templateContext = mutation.context ? resolveValue(mutation.context, options) : {};
|
|
1394
|
+
const rendered = Mustache.render(template, templateContext);
|
|
1395
|
+
const existed = await pathExists(context.fs, targetPath);
|
|
1396
|
+
if (!context.dryRun) {
|
|
1397
|
+
await context.fs.writeFile(targetPath, rendered, { encoding: "utf8" });
|
|
1398
|
+
}
|
|
1399
|
+
return {
|
|
1400
|
+
outcome: {
|
|
1401
|
+
changed: true,
|
|
1402
|
+
effect: "write",
|
|
1403
|
+
detail: existed ? "update" : "create"
|
|
1404
|
+
},
|
|
1405
|
+
details
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
async function applyTemplateMerge(mutation, context, options, formatName) {
|
|
1409
|
+
if (!context.templates) {
|
|
1410
|
+
throw new Error(
|
|
1411
|
+
"Template mutations require a templates loader. Provide templates function to runMutations context."
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
const rawPath = resolveValue(mutation.target, options);
|
|
1415
|
+
const targetPath = resolvePath(rawPath, context.homeDir, context.pathMapper);
|
|
1416
|
+
const details = {
|
|
1417
|
+
kind: mutation.kind,
|
|
1418
|
+
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1419
|
+
targetPath
|
|
1420
|
+
};
|
|
1421
|
+
const format = getConfigFormat(formatName);
|
|
1422
|
+
const template = await context.templates(mutation.templateId);
|
|
1423
|
+
const templateContext = mutation.context ? resolveValue(mutation.context, options) : {};
|
|
1424
|
+
const rendered = Mustache.render(template, templateContext);
|
|
1425
|
+
let templateDoc;
|
|
1426
|
+
try {
|
|
1427
|
+
templateDoc = format.parse(rendered);
|
|
1428
|
+
} catch (error2) {
|
|
1429
|
+
throw new Error(
|
|
1430
|
+
`Failed to parse rendered template "${mutation.templateId}" as ${formatName.toUpperCase()}: ${error2}`,
|
|
1431
|
+
{ cause: error2 }
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
1435
|
+
let current;
|
|
1436
|
+
try {
|
|
1437
|
+
current = rawContent === null ? {} : format.parse(rawContent);
|
|
1438
|
+
} catch {
|
|
1439
|
+
if (rawContent !== null) {
|
|
1440
|
+
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
1441
|
+
}
|
|
1442
|
+
current = {};
|
|
1443
|
+
}
|
|
1444
|
+
const merged = format.merge(current, templateDoc);
|
|
1445
|
+
const serialized = format.serialize(merged);
|
|
1446
|
+
const changed = serialized !== rawContent;
|
|
1447
|
+
if (changed && !context.dryRun) {
|
|
1448
|
+
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
1449
|
+
}
|
|
1450
|
+
return {
|
|
1451
|
+
outcome: {
|
|
1452
|
+
changed,
|
|
1453
|
+
effect: changed ? "write" : "none",
|
|
1454
|
+
detail: changed ? rawContent === null ? "create" : "update" : "noop"
|
|
1455
|
+
},
|
|
1456
|
+
details
|
|
957
1457
|
};
|
|
958
1458
|
}
|
|
959
|
-
var logger = createLogger();
|
|
960
|
-
|
|
961
|
-
// packages/design-system/src/components/table.ts
|
|
962
|
-
import { Table } from "console-table-printer";
|
|
963
|
-
|
|
964
|
-
// packages/design-system/src/acp/components.ts
|
|
965
|
-
import chalk7 from "chalk";
|
|
966
|
-
|
|
967
|
-
// packages/design-system/src/acp/writer.ts
|
|
968
|
-
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
969
|
-
var storage = new AsyncLocalStorage2();
|
|
970
|
-
|
|
971
|
-
// packages/design-system/src/acp/components.ts
|
|
972
|
-
var AGENT_PREFIX = `${chalk7.green.bold("\u2713")} agent: `;
|
|
973
|
-
|
|
974
|
-
// packages/design-system/src/dashboard/buffer.ts
|
|
975
|
-
import chalk8 from "chalk";
|
|
976
|
-
|
|
977
|
-
// packages/design-system/src/dashboard/terminal.ts
|
|
978
|
-
import readline from "node:readline";
|
|
979
|
-
import { PassThrough } from "node:stream";
|
|
980
|
-
|
|
981
|
-
// packages/design-system/src/prompts/index.ts
|
|
982
|
-
import chalk15 from "chalk";
|
|
983
|
-
import * as clack from "@clack/prompts";
|
|
984
|
-
|
|
985
|
-
// packages/design-system/src/prompts/primitives/cancel.ts
|
|
986
|
-
import chalk9 from "chalk";
|
|
987
|
-
import { isCancel } from "@clack/prompts";
|
|
988
|
-
|
|
989
|
-
// packages/design-system/src/prompts/primitives/intro.ts
|
|
990
|
-
import chalk10 from "chalk";
|
|
991
|
-
|
|
992
|
-
// packages/design-system/src/prompts/primitives/note.ts
|
|
993
|
-
import chalk11 from "chalk";
|
|
994
|
-
|
|
995
|
-
// packages/design-system/src/prompts/primitives/outro.ts
|
|
996
|
-
import chalk12 from "chalk";
|
|
997
1459
|
|
|
998
|
-
// packages/
|
|
999
|
-
|
|
1460
|
+
// packages/config-mutations/src/execution/run-mutations.ts
|
|
1461
|
+
async function runMutations(mutations, context, options) {
|
|
1462
|
+
const effects = [];
|
|
1463
|
+
let anyChanged = false;
|
|
1464
|
+
const resolverOptions = options ?? {};
|
|
1465
|
+
for (const mutation of mutations) {
|
|
1466
|
+
const { outcome } = await executeMutation(
|
|
1467
|
+
mutation,
|
|
1468
|
+
context,
|
|
1469
|
+
resolverOptions
|
|
1470
|
+
);
|
|
1471
|
+
effects.push(outcome);
|
|
1472
|
+
if (outcome.changed) {
|
|
1473
|
+
anyChanged = true;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
return {
|
|
1477
|
+
changed: anyChanged,
|
|
1478
|
+
effects
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
async function executeMutation(mutation, context, options) {
|
|
1482
|
+
context.observers?.onStart?.({
|
|
1483
|
+
kind: mutation.kind,
|
|
1484
|
+
label: mutation.label ?? mutation.kind,
|
|
1485
|
+
targetPath: void 0
|
|
1486
|
+
// Will be resolved during apply
|
|
1487
|
+
});
|
|
1488
|
+
try {
|
|
1489
|
+
const { outcome, details } = await applyMutation(mutation, context, options);
|
|
1490
|
+
context.observers?.onComplete?.(details, outcome);
|
|
1491
|
+
return { outcome, details };
|
|
1492
|
+
} catch (error2) {
|
|
1493
|
+
context.observers?.onError?.(
|
|
1494
|
+
{
|
|
1495
|
+
kind: mutation.kind,
|
|
1496
|
+
label: mutation.label ?? mutation.kind,
|
|
1497
|
+
targetPath: void 0
|
|
1498
|
+
},
|
|
1499
|
+
error2
|
|
1500
|
+
);
|
|
1501
|
+
throw error2;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1000
1504
|
|
|
1001
|
-
// packages/
|
|
1002
|
-
import
|
|
1505
|
+
// packages/config-mutations/src/template/render.ts
|
|
1506
|
+
import Mustache2 from "mustache";
|
|
1507
|
+
var originalEscape = Mustache2.escape;
|
|
1003
1508
|
|
|
1004
|
-
// packages/
|
|
1005
|
-
|
|
1509
|
+
// packages/poe-code-config/src/store.ts
|
|
1510
|
+
var EMPTY_DOCUMENT = `${JSON.stringify({}, null, 2)}
|
|
1511
|
+
`;
|
|
1006
1512
|
|
|
1007
|
-
// packages/
|
|
1008
|
-
|
|
1513
|
+
// packages/poe-code-config/src/inspect.ts
|
|
1514
|
+
import path9 from "node:path";
|
|
1515
|
+
var EMPTY_DOCUMENT2 = `${JSON.stringify({}, null, 2)}
|
|
1516
|
+
`;
|
|
1009
1517
|
|
|
1010
|
-
// packages/
|
|
1011
|
-
import
|
|
1012
|
-
import { homedir as homedir2 } from "node:os";
|
|
1013
|
-
import { open, readdir } from "node:fs/promises";
|
|
1014
|
-
import { createInterface } from "node:readline";
|
|
1518
|
+
// packages/poe-code-config/src/state/index.ts
|
|
1519
|
+
import os2 from "node:os";
|
|
1015
1520
|
|
|
1016
|
-
// packages/poe-
|
|
1017
|
-
import
|
|
1521
|
+
// packages/poe-code-config/src/state/jobs.ts
|
|
1522
|
+
import path10 from "node:path";
|
|
1018
1523
|
|
|
1019
|
-
// packages/poe-
|
|
1020
|
-
import
|
|
1021
|
-
spawn as spawnChildProcess3
|
|
1022
|
-
} from "node:child_process";
|
|
1524
|
+
// packages/poe-code-config/src/state/fs.ts
|
|
1525
|
+
import * as nodeFs2 from "node:fs/promises";
|
|
1023
1526
|
|
|
1024
|
-
// packages/poe-
|
|
1025
|
-
import
|
|
1026
|
-
import { homedir } from "node:os";
|
|
1027
|
-
import { join } from "node:path";
|
|
1527
|
+
// packages/poe-code-config/src/state/templates.ts
|
|
1528
|
+
import path11 from "node:path";
|
|
1028
1529
|
|
|
1029
|
-
// packages/agent-
|
|
1030
|
-
|
|
1530
|
+
// packages/agent-harness-tools/src/execution-env.ts
|
|
1531
|
+
var executionEnvFactories = /* @__PURE__ */ new Map();
|
|
1532
|
+
function registerExecutionEnvFactory(factory) {
|
|
1533
|
+
executionEnvFactories.set(factory.type, factory);
|
|
1534
|
+
}
|
|
1031
1535
|
|
|
1032
|
-
// packages/agent-
|
|
1033
|
-
import
|
|
1034
|
-
import {
|
|
1035
|
-
import
|
|
1536
|
+
// packages/agent-harness-tools/src/workspace-transfer.ts
|
|
1537
|
+
import { createHash } from "node:crypto";
|
|
1538
|
+
import { promises as nodeFs3 } from "node:fs";
|
|
1539
|
+
import path12 from "node:path";
|
|
1036
1540
|
|
|
1037
|
-
// src/
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
});
|
|
1053
|
-
return {
|
|
1054
|
-
id: `${agentId}-cli-health`,
|
|
1055
|
-
description: `spawn ${agentId} (expecting "${options.expectedOutput}")`,
|
|
1056
|
-
async run(context) {
|
|
1057
|
-
if (context.isDryRun) {
|
|
1058
|
-
context.logDryRun?.(
|
|
1059
|
-
`Dry run: ${[binaryName, ...args].join(" ")} (expecting "${options.expectedOutput}")`
|
|
1060
|
-
);
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
|
-
const result = modeEnv ? await context.runCommand(binaryName, args, { env: modeEnv }) : await context.runCommand(binaryName, args);
|
|
1064
|
-
if (result.exitCode !== 0) {
|
|
1065
|
-
throw new Error(
|
|
1066
|
-
`spawn ${agentId} failed with exit code ${result.exitCode}.
|
|
1067
|
-
${formatCommandRunnerResult(result)}`
|
|
1068
|
-
);
|
|
1069
|
-
}
|
|
1070
|
-
if (!result.stdout.includes(options.expectedOutput)) {
|
|
1071
|
-
throw new Error(
|
|
1072
|
-
`spawn ${agentId}: expected "${options.expectedOutput}" in stdout.
|
|
1073
|
-
${formatCommandRunnerResult(result)}`
|
|
1074
|
-
);
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
};
|
|
1078
|
-
}
|
|
1079
|
-
function createBinaryExistsCheck(binaryName, id, description) {
|
|
1080
|
-
return {
|
|
1081
|
-
id,
|
|
1082
|
-
description,
|
|
1083
|
-
async run({ runCommand: runCommand2 }) {
|
|
1084
|
-
const commonPaths = [
|
|
1085
|
-
`/usr/local/bin/${binaryName}`,
|
|
1086
|
-
`/usr/bin/${binaryName}`,
|
|
1087
|
-
`$HOME/.local/bin/${binaryName}`,
|
|
1088
|
-
`$HOME/.claude/local/bin/${binaryName}`
|
|
1089
|
-
];
|
|
1090
|
-
const detectors = [
|
|
1091
|
-
{
|
|
1092
|
-
command: "which",
|
|
1093
|
-
args: [binaryName],
|
|
1094
|
-
validate: (result) => result.exitCode === 0
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
command: "where",
|
|
1098
|
-
args: [binaryName],
|
|
1099
|
-
validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
|
|
1100
|
-
},
|
|
1101
|
-
// Check common installation paths using shell expansion for $HOME
|
|
1102
|
-
{
|
|
1103
|
-
command: "sh",
|
|
1104
|
-
args: [
|
|
1105
|
-
"-c",
|
|
1106
|
-
commonPaths.map((p) => `test -f "${p}"`).join(" || ")
|
|
1107
|
-
],
|
|
1108
|
-
validate: (result) => result.exitCode === 0
|
|
1109
|
-
}
|
|
1110
|
-
];
|
|
1111
|
-
for (const detector of detectors) {
|
|
1112
|
-
const result = await runCommand2(detector.command, detector.args);
|
|
1113
|
-
if (detector.validate(result)) {
|
|
1114
|
-
return;
|
|
1541
|
+
// packages/process-runner/src/docker/context.ts
|
|
1542
|
+
import { execSync } from "node:child_process";
|
|
1543
|
+
function detectContext() {
|
|
1544
|
+
try {
|
|
1545
|
+
const output = execSync("colima list --json", {
|
|
1546
|
+
encoding: "utf-8",
|
|
1547
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
1548
|
+
});
|
|
1549
|
+
const lines = output.trim().split("\n").filter(Boolean);
|
|
1550
|
+
for (const line of lines) {
|
|
1551
|
+
const profile = JSON.parse(line);
|
|
1552
|
+
if (profile.status === "Running" && profile.runtime === "docker") {
|
|
1553
|
+
const name = profile.name ?? profile.profile;
|
|
1554
|
+
if (!name) {
|
|
1555
|
+
continue;
|
|
1115
1556
|
}
|
|
1557
|
+
return name === "default" ? "colima" : `colima-${name}`;
|
|
1116
1558
|
}
|
|
1117
|
-
throw new Error(`${binaryName} CLI binary not found on PATH.`);
|
|
1118
1559
|
}
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
pruneByPrefix: options.pruneByPrefix,
|
|
1130
|
-
label: options.label
|
|
1131
|
-
};
|
|
1132
|
-
}
|
|
1133
|
-
function prune(options) {
|
|
1134
|
-
return {
|
|
1135
|
-
kind: "configPrune",
|
|
1136
|
-
target: options.target,
|
|
1137
|
-
shape: options.shape,
|
|
1138
|
-
format: options.format,
|
|
1139
|
-
onlyIf: options.onlyIf,
|
|
1140
|
-
label: options.label
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
function transform(options) {
|
|
1144
|
-
return {
|
|
1145
|
-
kind: "configTransform",
|
|
1146
|
-
target: options.target,
|
|
1147
|
-
format: options.format,
|
|
1148
|
-
transform: options.transform,
|
|
1149
|
-
label: options.label
|
|
1150
|
-
};
|
|
1560
|
+
} catch {
|
|
1561
|
+
return null;
|
|
1562
|
+
}
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1565
|
+
function buildContextArgs(engine, context) {
|
|
1566
|
+
if (engine === "docker" && context) {
|
|
1567
|
+
return ["--context", context];
|
|
1568
|
+
}
|
|
1569
|
+
return [];
|
|
1151
1570
|
}
|
|
1152
|
-
var configMutation = {
|
|
1153
|
-
merge,
|
|
1154
|
-
prune,
|
|
1155
|
-
transform
|
|
1156
|
-
};
|
|
1157
1571
|
|
|
1158
|
-
// packages/
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1572
|
+
// packages/process-runner/src/docker/engine.ts
|
|
1573
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
1574
|
+
function detectEngine() {
|
|
1575
|
+
if (isEngineAvailable("docker")) {
|
|
1576
|
+
return "docker";
|
|
1577
|
+
}
|
|
1578
|
+
if (isEngineAvailable("podman")) {
|
|
1579
|
+
return "podman";
|
|
1580
|
+
}
|
|
1581
|
+
throw new Error(
|
|
1582
|
+
"No container engine found. Please install Docker or Podman:\n - Docker Desktop: https://www.docker.com/products/docker-desktop\n - Colima (macOS): brew install colima && colima start\n - Podman: https://podman.io/docs/installation"
|
|
1583
|
+
);
|
|
1165
1584
|
}
|
|
1166
|
-
function
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1585
|
+
function isEngineAvailable(engine) {
|
|
1586
|
+
try {
|
|
1587
|
+
execSync2(`${engine} --version`, {
|
|
1588
|
+
stdio: "ignore"
|
|
1589
|
+
});
|
|
1590
|
+
return true;
|
|
1591
|
+
} catch {
|
|
1592
|
+
return false;
|
|
1593
|
+
}
|
|
1174
1594
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1595
|
+
|
|
1596
|
+
// packages/process-runner/src/docker/docker-runner.ts
|
|
1597
|
+
import * as childProcess from "node:child_process";
|
|
1598
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
1599
|
+
|
|
1600
|
+
// packages/process-runner/src/docker/args.ts
|
|
1601
|
+
import path13 from "node:path";
|
|
1602
|
+
function buildDockerRunArgs(input) {
|
|
1603
|
+
const args = [input.engine];
|
|
1604
|
+
if (input.engine === "docker" && input.context) {
|
|
1605
|
+
args.push("--context", input.context);
|
|
1606
|
+
}
|
|
1607
|
+
args.push("run");
|
|
1608
|
+
if (input.rm) {
|
|
1609
|
+
args.push("--rm");
|
|
1610
|
+
}
|
|
1611
|
+
if (input.detached) {
|
|
1612
|
+
args.push("-d");
|
|
1613
|
+
}
|
|
1614
|
+
if (input.interactive) {
|
|
1615
|
+
args.push("-i");
|
|
1616
|
+
}
|
|
1617
|
+
if (input.tty) {
|
|
1618
|
+
args.push("-t");
|
|
1619
|
+
}
|
|
1620
|
+
args.push("--name", input.containerName);
|
|
1621
|
+
if (input.cwd !== void 0) {
|
|
1622
|
+
args.push("-w", input.cwd);
|
|
1623
|
+
}
|
|
1624
|
+
for (const [key, value] of Object.entries(input.env ?? {})) {
|
|
1625
|
+
args.push("-e", `${key}=${value}`);
|
|
1626
|
+
}
|
|
1627
|
+
for (const mount of input.mounts) {
|
|
1628
|
+
const volume = `${path13.resolve(mount.source)}:${mount.target}${mount.readonly ? ":ro" : ""}`;
|
|
1629
|
+
args.push("-v", volume);
|
|
1630
|
+
}
|
|
1631
|
+
for (const port of input.ports) {
|
|
1632
|
+
const mapping = `${port.host}:${port.container}${port.protocol === void 0 || port.protocol === "tcp" ? "" : `/${port.protocol}`}`;
|
|
1633
|
+
args.push("-p", mapping);
|
|
1634
|
+
}
|
|
1635
|
+
if (input.network !== void 0) {
|
|
1636
|
+
args.push("--network", input.network);
|
|
1637
|
+
}
|
|
1638
|
+
args.push(...input.extraArgs, input.image, input.command, ...input.args);
|
|
1639
|
+
return args;
|
|
1182
1640
|
}
|
|
1183
|
-
|
|
1641
|
+
|
|
1642
|
+
// packages/process-runner/src/docker/docker-execution-env.ts
|
|
1643
|
+
import { createHash as createHash2, randomBytes as randomBytes3 } from "node:crypto";
|
|
1644
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
1645
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
1646
|
+
import { tmpdir } from "node:os";
|
|
1647
|
+
import path14 from "node:path";
|
|
1648
|
+
|
|
1649
|
+
// packages/process-runner/src/host/host-runner.ts
|
|
1650
|
+
import { spawn as spawnChildProcess } from "node:child_process";
|
|
1651
|
+
function createHostRunner(options = {}) {
|
|
1652
|
+
const detached = options.detached === true;
|
|
1184
1653
|
return {
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1654
|
+
name: "host",
|
|
1655
|
+
exec(spec) {
|
|
1656
|
+
const stdinMode = spec.stdin ?? "ignore";
|
|
1657
|
+
const stdoutMode = spec.stdout ?? "pipe";
|
|
1658
|
+
const stderrMode = spec.stderr ?? "pipe";
|
|
1659
|
+
const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
|
|
1660
|
+
const child = spawnChildProcess(spec.command, spec.args ?? [], {
|
|
1661
|
+
cwd: spec.cwd,
|
|
1662
|
+
env: spec.env,
|
|
1663
|
+
stdio,
|
|
1664
|
+
...detached ? { detached: true } : {}
|
|
1665
|
+
});
|
|
1666
|
+
if (detached) {
|
|
1667
|
+
child.unref();
|
|
1668
|
+
}
|
|
1669
|
+
const kill = (signal) => {
|
|
1670
|
+
if (detached && process.platform !== "win32" && child.pid !== void 0) {
|
|
1671
|
+
process.kill(-child.pid, signal);
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1674
|
+
child.kill(signal);
|
|
1675
|
+
};
|
|
1676
|
+
let settled = false;
|
|
1677
|
+
let resolveResult = null;
|
|
1678
|
+
const result = new Promise((resolve2) => {
|
|
1679
|
+
resolveResult = resolve2;
|
|
1680
|
+
});
|
|
1681
|
+
const cleanupAbort = bindAbortSignal(spec.signal, () => {
|
|
1682
|
+
kill("SIGTERM");
|
|
1683
|
+
});
|
|
1684
|
+
child.once("close", (code) => {
|
|
1685
|
+
if (settled) return;
|
|
1686
|
+
settled = true;
|
|
1687
|
+
cleanupAbort();
|
|
1688
|
+
resolveResult?.({ exitCode: code ?? 1 });
|
|
1689
|
+
});
|
|
1690
|
+
child.once("error", () => {
|
|
1691
|
+
if (settled) return;
|
|
1692
|
+
settled = true;
|
|
1693
|
+
cleanupAbort();
|
|
1694
|
+
resolveResult?.({ exitCode: 1 });
|
|
1695
|
+
});
|
|
1696
|
+
return {
|
|
1697
|
+
pid: child.pid ?? null,
|
|
1698
|
+
stdin: child.stdin,
|
|
1699
|
+
stdout: child.stdout,
|
|
1700
|
+
stderr: child.stderr,
|
|
1701
|
+
result,
|
|
1702
|
+
kill
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1189
1705
|
};
|
|
1190
1706
|
}
|
|
1191
|
-
function
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1707
|
+
function bindAbortSignal(signal, onAbort) {
|
|
1708
|
+
if (signal === void 0) {
|
|
1709
|
+
return () => {
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
if (signal.aborted) {
|
|
1713
|
+
onAbort();
|
|
1714
|
+
return () => {
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1718
|
+
return () => {
|
|
1719
|
+
signal.removeEventListener("abort", onAbort);
|
|
1196
1720
|
};
|
|
1197
1721
|
}
|
|
1198
|
-
var fileMutation = {
|
|
1199
|
-
ensureDirectory,
|
|
1200
|
-
remove,
|
|
1201
|
-
removeDirectory,
|
|
1202
|
-
chmod,
|
|
1203
|
-
backup
|
|
1204
|
-
};
|
|
1205
|
-
|
|
1206
|
-
// packages/config-mutations/src/execution/apply-mutation.ts
|
|
1207
|
-
import Mustache from "mustache";
|
|
1208
1722
|
|
|
1209
|
-
// packages/
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1723
|
+
// packages/process-runner/src/docker/docker-execution-env.ts
|
|
1724
|
+
var containerCommand = ["sh", "-c", "while :; do sleep 3600; done"];
|
|
1725
|
+
var dockerExecutionEnvFactory = {
|
|
1726
|
+
type: "docker",
|
|
1727
|
+
supportsDetach: true,
|
|
1728
|
+
async open(spec) {
|
|
1729
|
+
const runtime = parseDockerRuntime(spec.runtime);
|
|
1730
|
+
const runner = spec.hostRunner ?? createHostRunner();
|
|
1731
|
+
const engine = runtime.engine ?? detectEngine();
|
|
1732
|
+
const context = detectContext();
|
|
1733
|
+
const image = await resolveImage({
|
|
1734
|
+
spec,
|
|
1735
|
+
runtime,
|
|
1736
|
+
runner,
|
|
1737
|
+
engine,
|
|
1738
|
+
context
|
|
1739
|
+
});
|
|
1740
|
+
const containerName = createContainerName();
|
|
1741
|
+
const runArgs = buildDockerRunArgs({
|
|
1742
|
+
engine,
|
|
1743
|
+
context,
|
|
1744
|
+
image,
|
|
1745
|
+
command: containerCommand[0],
|
|
1746
|
+
args: containerCommand.slice(1),
|
|
1747
|
+
cwd: void 0,
|
|
1748
|
+
env: void 0,
|
|
1749
|
+
mounts: runtime.mounts ?? [],
|
|
1750
|
+
ports: [],
|
|
1751
|
+
network: runtime.network,
|
|
1752
|
+
containerName,
|
|
1753
|
+
detached: true,
|
|
1754
|
+
interactive: true,
|
|
1755
|
+
tty: false,
|
|
1756
|
+
rm: false,
|
|
1757
|
+
extraArgs: runtime.extra_args ?? []
|
|
1758
|
+
});
|
|
1759
|
+
const [command, ...args] = runArgs;
|
|
1760
|
+
const id = (await runAndRead(runner, { command, args, stdout: "pipe", stderr: "pipe" })).trim();
|
|
1761
|
+
return createDockerEnv({
|
|
1762
|
+
id,
|
|
1763
|
+
spec,
|
|
1764
|
+
runner,
|
|
1765
|
+
engine,
|
|
1766
|
+
context
|
|
1767
|
+
});
|
|
1768
|
+
},
|
|
1769
|
+
async attach(envId) {
|
|
1770
|
+
const engine = detectEngine();
|
|
1771
|
+
return createDockerEnv({
|
|
1772
|
+
id: envId,
|
|
1773
|
+
spec: createAttachedSpec(),
|
|
1774
|
+
runner: createHostRunner(),
|
|
1775
|
+
engine,
|
|
1776
|
+
context: detectContext()
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
function createDockerEnv(input) {
|
|
1781
|
+
const containerRef = input.id;
|
|
1782
|
+
return {
|
|
1783
|
+
id: containerRef,
|
|
1784
|
+
job: null,
|
|
1785
|
+
async uploadWorkspace() {
|
|
1786
|
+
const tempDir = mkdtempSync(path14.join(tmpdir(), "poe-docker-upload-"));
|
|
1787
|
+
const archivePath = path14.join(tempDir, "workspace.tar");
|
|
1788
|
+
try {
|
|
1789
|
+
const excludeArgs = input.spec.uploadIgnoreFiles.flatMap((ignored) => [
|
|
1790
|
+
"--exclude",
|
|
1791
|
+
ignored
|
|
1792
|
+
]);
|
|
1793
|
+
const tarArgs = [...excludeArgs, "-cf", archivePath, "-C", input.spec.cwd, "."];
|
|
1794
|
+
await runOrThrow(input.runner, {
|
|
1795
|
+
command: "tar",
|
|
1796
|
+
args: tarArgs,
|
|
1797
|
+
stdout: "pipe",
|
|
1798
|
+
stderr: "pipe"
|
|
1799
|
+
});
|
|
1800
|
+
await runOrThrow(input.runner, {
|
|
1801
|
+
command: input.engine,
|
|
1802
|
+
args: [
|
|
1803
|
+
...buildContextArgs(input.engine, input.context),
|
|
1804
|
+
"cp",
|
|
1805
|
+
archivePath,
|
|
1806
|
+
`${containerRef}:/tmp/poe-workspace-upload.tar`
|
|
1807
|
+
],
|
|
1808
|
+
stdout: "pipe",
|
|
1809
|
+
stderr: "pipe"
|
|
1810
|
+
});
|
|
1811
|
+
await runOrThrow(input.runner, {
|
|
1812
|
+
command: input.engine,
|
|
1813
|
+
args: [
|
|
1814
|
+
...buildContextArgs(input.engine, input.context),
|
|
1815
|
+
"exec",
|
|
1816
|
+
containerRef,
|
|
1817
|
+
"sh",
|
|
1818
|
+
"-c",
|
|
1819
|
+
`mkdir -p ${shellQuote(input.spec.cwd)} && tar -xf /tmp/poe-workspace-upload.tar -C ${shellQuote(input.spec.cwd)}`
|
|
1820
|
+
],
|
|
1821
|
+
stdout: "pipe",
|
|
1822
|
+
stderr: "pipe"
|
|
1823
|
+
});
|
|
1824
|
+
return { files: 0, bytes: 0, skipped: [] };
|
|
1825
|
+
} finally {
|
|
1826
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1827
|
+
}
|
|
1828
|
+
},
|
|
1829
|
+
async downloadWorkspace(opts) {
|
|
1830
|
+
const tempDir = mkdtempSync(path14.join(tmpdir(), "poe-docker-download-"));
|
|
1831
|
+
const archivePath = path14.join(tempDir, "workspace.tar");
|
|
1832
|
+
try {
|
|
1833
|
+
await runOrThrow(input.runner, {
|
|
1834
|
+
command: input.engine,
|
|
1835
|
+
args: [
|
|
1836
|
+
...buildContextArgs(input.engine, input.context),
|
|
1837
|
+
"exec",
|
|
1838
|
+
containerRef,
|
|
1839
|
+
"sh",
|
|
1840
|
+
"-c",
|
|
1841
|
+
`tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote(input.spec.cwd)} .`
|
|
1842
|
+
],
|
|
1843
|
+
stdout: "pipe",
|
|
1844
|
+
stderr: "pipe"
|
|
1845
|
+
});
|
|
1846
|
+
await runOrThrow(input.runner, {
|
|
1847
|
+
command: input.engine,
|
|
1848
|
+
args: [
|
|
1849
|
+
...buildContextArgs(input.engine, input.context),
|
|
1850
|
+
"cp",
|
|
1851
|
+
`${containerRef}:/tmp/poe-workspace-download.tar`,
|
|
1852
|
+
archivePath
|
|
1853
|
+
],
|
|
1854
|
+
stdout: "pipe",
|
|
1855
|
+
stderr: "pipe"
|
|
1856
|
+
});
|
|
1857
|
+
const extractMode = opts.conflictPolicy === "refuse" ? "-xkf" : "-xf";
|
|
1858
|
+
await runOrThrow(input.runner, {
|
|
1859
|
+
command: "tar",
|
|
1860
|
+
args: [extractMode, archivePath, "-C", input.spec.cwd],
|
|
1861
|
+
stdout: "pipe",
|
|
1862
|
+
stderr: "pipe"
|
|
1863
|
+
});
|
|
1864
|
+
return { files: 0, bytes: 0, conflicts: [] };
|
|
1865
|
+
} finally {
|
|
1866
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1867
|
+
}
|
|
1868
|
+
},
|
|
1869
|
+
exec(spec) {
|
|
1870
|
+
return input.runner.exec({
|
|
1871
|
+
command: input.engine,
|
|
1872
|
+
args: [
|
|
1873
|
+
...buildContextArgs(input.engine, input.context),
|
|
1874
|
+
"exec",
|
|
1875
|
+
...spec.stdin === "pipe" || spec.stdin === "inherit" ? ["-i"] : [],
|
|
1876
|
+
...spec.tty === true ? ["-t"] : [],
|
|
1877
|
+
...spec.cwd !== void 0 ? ["-w", spec.cwd] : [],
|
|
1878
|
+
...buildEnvArgs(spec.env),
|
|
1879
|
+
containerRef,
|
|
1880
|
+
spec.command,
|
|
1881
|
+
...spec.args ?? []
|
|
1882
|
+
],
|
|
1883
|
+
stdin: spec.stdin,
|
|
1884
|
+
stdout: spec.stdout,
|
|
1885
|
+
stderr: spec.stderr,
|
|
1886
|
+
tty: spec.tty
|
|
1887
|
+
});
|
|
1888
|
+
},
|
|
1889
|
+
async detach() {
|
|
1890
|
+
return createContainerJob(containerRef, input.runner, input.engine, input.context);
|
|
1891
|
+
},
|
|
1892
|
+
shell() {
|
|
1893
|
+
const shellSpec = input.spec.shellSpec;
|
|
1894
|
+
return this.exec({
|
|
1895
|
+
command: shellSpec?.command ?? input.spec.env.SHELL ?? "sh",
|
|
1896
|
+
...shellSpec?.args ? { args: shellSpec.args } : {},
|
|
1897
|
+
cwd: input.spec.cwd,
|
|
1898
|
+
env: shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env,
|
|
1899
|
+
stdin: "inherit",
|
|
1900
|
+
stdout: "inherit",
|
|
1901
|
+
stderr: "inherit",
|
|
1902
|
+
tty: true
|
|
1903
|
+
});
|
|
1904
|
+
},
|
|
1905
|
+
async close() {
|
|
1906
|
+
await runOrThrow(input.runner, {
|
|
1907
|
+
command: input.engine,
|
|
1908
|
+
args: [...buildContextArgs(input.engine, input.context), "rm", "-f", containerRef],
|
|
1909
|
+
stdout: "pipe",
|
|
1910
|
+
stderr: "pipe"
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1213
1914
|
}
|
|
1214
|
-
function
|
|
1215
|
-
if (
|
|
1216
|
-
return
|
|
1915
|
+
async function resolveImage(input) {
|
|
1916
|
+
if (input.runtime.image !== void 0) {
|
|
1917
|
+
return input.runtime.image;
|
|
1217
1918
|
}
|
|
1218
|
-
const
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1919
|
+
const dockerfilePath = path14.resolve(
|
|
1920
|
+
input.spec.cwd,
|
|
1921
|
+
input.runtime.dockerfile ?? path14.join(".poe-code", "Dockerfile")
|
|
1922
|
+
);
|
|
1923
|
+
const buildContext = path14.resolve(input.spec.cwd, input.runtime.build_context ?? ".");
|
|
1924
|
+
const dockerfileBytes = await readFile2(dockerfilePath);
|
|
1925
|
+
const hash = hashDockerTemplate(dockerfileBytes, input.runtime.build_args ?? {});
|
|
1926
|
+
const cached2 = await input.spec.state?.templates.get("docker", hash);
|
|
1927
|
+
if (cached2?.image !== void 0) {
|
|
1928
|
+
return cached2.image;
|
|
1929
|
+
}
|
|
1930
|
+
const image = `poe-code/local:${hash}`;
|
|
1931
|
+
await buildImage({
|
|
1932
|
+
runner: input.runner,
|
|
1933
|
+
engine: input.engine,
|
|
1934
|
+
context: input.context,
|
|
1935
|
+
image,
|
|
1936
|
+
dockerfilePath,
|
|
1937
|
+
buildContext,
|
|
1938
|
+
buildArgs: input.runtime.build_args ?? {}
|
|
1222
1939
|
});
|
|
1223
|
-
|
|
1224
|
-
|
|
1940
|
+
await input.spec.state?.templates.put("docker", {
|
|
1941
|
+
hash,
|
|
1942
|
+
image,
|
|
1943
|
+
runtime_type: "docker",
|
|
1944
|
+
dockerfile_path: dockerfilePath,
|
|
1945
|
+
built_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1946
|
+
});
|
|
1947
|
+
return image;
|
|
1948
|
+
}
|
|
1949
|
+
function hashDockerTemplate(dockerfileBytes, buildArgs) {
|
|
1950
|
+
const hash = createHash2("sha256");
|
|
1951
|
+
hash.update(dockerfileBytes);
|
|
1952
|
+
hash.update("\0");
|
|
1953
|
+
for (const [key, value] of sortedBuildArgs(buildArgs)) {
|
|
1954
|
+
hash.update(key);
|
|
1955
|
+
hash.update("=");
|
|
1956
|
+
hash.update(value);
|
|
1957
|
+
hash.update("\0");
|
|
1958
|
+
}
|
|
1959
|
+
return hash.digest("hex");
|
|
1960
|
+
}
|
|
1961
|
+
async function buildImage(input) {
|
|
1962
|
+
await runOrThrow(input.runner, {
|
|
1963
|
+
command: input.engine,
|
|
1964
|
+
args: [
|
|
1965
|
+
...buildContextArgs(input.engine, input.context),
|
|
1966
|
+
"build",
|
|
1967
|
+
"--tag",
|
|
1968
|
+
input.image,
|
|
1969
|
+
"-f",
|
|
1970
|
+
input.dockerfilePath,
|
|
1971
|
+
...sortedBuildArgs(input.buildArgs).flatMap(([key, value]) => [
|
|
1972
|
+
"--build-arg",
|
|
1973
|
+
`${key}=${value}`
|
|
1974
|
+
]),
|
|
1975
|
+
input.buildContext
|
|
1976
|
+
],
|
|
1977
|
+
stdout: "pipe",
|
|
1978
|
+
stderr: "pipe"
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
function parseDockerRuntime(runtime) {
|
|
1982
|
+
if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
|
|
1983
|
+
throw new Error("docker runtime must be an object");
|
|
1225
1984
|
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1985
|
+
const record = runtime;
|
|
1986
|
+
if (record.type !== "docker") {
|
|
1987
|
+
throw new Error('docker runtime type must be "docker"');
|
|
1228
1988
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1989
|
+
return record;
|
|
1990
|
+
}
|
|
1991
|
+
async function runAndRead(runner, spec) {
|
|
1992
|
+
const handle = runner.exec(spec);
|
|
1993
|
+
const stdout = readStream(handle.stdout);
|
|
1994
|
+
const stderr = readStream(handle.stderr);
|
|
1995
|
+
const result = await handle.result;
|
|
1996
|
+
const output = await stdout;
|
|
1997
|
+
if (result.exitCode !== 0) {
|
|
1998
|
+
const errorOutput = await stderr;
|
|
1999
|
+
throw new Error(
|
|
2000
|
+
`Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}${errorOutput ? `
|
|
2001
|
+
${errorOutput}` : ""}`
|
|
2002
|
+
);
|
|
1231
2003
|
}
|
|
1232
|
-
return
|
|
2004
|
+
return output;
|
|
1233
2005
|
}
|
|
1234
|
-
function
|
|
1235
|
-
|
|
1236
|
-
`;
|
|
2006
|
+
async function runOrThrow(runner, spec) {
|
|
2007
|
+
await runAndRead(runner, spec);
|
|
1237
2008
|
}
|
|
1238
|
-
function
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
if (value === void 0) {
|
|
1242
|
-
continue;
|
|
1243
|
-
}
|
|
1244
|
-
const existing = result[key];
|
|
1245
|
-
if (isConfigObject(existing) && isConfigObject(value)) {
|
|
1246
|
-
result[key] = merge2(existing, value);
|
|
1247
|
-
continue;
|
|
1248
|
-
}
|
|
1249
|
-
result[key] = value;
|
|
2009
|
+
async function readStream(stream) {
|
|
2010
|
+
if (stream === null) {
|
|
2011
|
+
return "";
|
|
1250
2012
|
}
|
|
1251
|
-
|
|
2013
|
+
stream.setEncoding("utf8");
|
|
2014
|
+
const chunks = [];
|
|
2015
|
+
for await (const chunk of stream) {
|
|
2016
|
+
chunks.push(String(chunk));
|
|
2017
|
+
}
|
|
2018
|
+
return chunks.join("");
|
|
1252
2019
|
}
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
2020
|
+
function sortedBuildArgs(buildArgs) {
|
|
2021
|
+
return Object.entries(buildArgs).sort(([left], [right]) => left.localeCompare(right));
|
|
2022
|
+
}
|
|
2023
|
+
function buildEnvArgs(env) {
|
|
2024
|
+
if (env === void 0) {
|
|
2025
|
+
return [];
|
|
2026
|
+
}
|
|
2027
|
+
return Object.entries(env).flatMap(([key, value]) => ["-e", `${key}=${value}`]);
|
|
2028
|
+
}
|
|
2029
|
+
function createContainerName() {
|
|
2030
|
+
return `poe-env-${randomBytes3(6).toString("hex")}`;
|
|
2031
|
+
}
|
|
2032
|
+
async function createContainerJob(containerId, runner, engine, context) {
|
|
2033
|
+
return {
|
|
2034
|
+
id: containerId,
|
|
2035
|
+
envId: containerId,
|
|
2036
|
+
tool: "docker",
|
|
2037
|
+
argv: ["attach", containerId],
|
|
2038
|
+
async status() {
|
|
2039
|
+
const handle = runner.exec({
|
|
2040
|
+
command: engine,
|
|
2041
|
+
args: [
|
|
2042
|
+
...buildContextArgs(engine, context),
|
|
2043
|
+
"inspect",
|
|
2044
|
+
"-f",
|
|
2045
|
+
"{{.State.Status}}",
|
|
2046
|
+
containerId
|
|
2047
|
+
],
|
|
2048
|
+
stdout: "pipe",
|
|
2049
|
+
stderr: "pipe"
|
|
2050
|
+
});
|
|
2051
|
+
const stdout = await readStream(handle.stdout);
|
|
2052
|
+
const result = await handle.result;
|
|
2053
|
+
if (result.exitCode !== 0) {
|
|
2054
|
+
return "lost";
|
|
2055
|
+
}
|
|
2056
|
+
return stdout.trim() === "running" ? "running" : "exited";
|
|
2057
|
+
},
|
|
2058
|
+
async *stream() {
|
|
2059
|
+
},
|
|
2060
|
+
async wait() {
|
|
2061
|
+
const handle = runner.exec({
|
|
2062
|
+
command: engine,
|
|
2063
|
+
args: [...buildContextArgs(engine, context), "wait", containerId],
|
|
2064
|
+
stdout: "pipe",
|
|
2065
|
+
stderr: "pipe"
|
|
2066
|
+
});
|
|
2067
|
+
const stdout = await readStream(handle.stdout);
|
|
2068
|
+
const result = await handle.result;
|
|
2069
|
+
return { exitCode: Number.parseInt(stdout.trim(), 10) || result.exitCode };
|
|
2070
|
+
},
|
|
2071
|
+
async kill(signal) {
|
|
2072
|
+
const args = signal === void 0 || signal === "SIGTERM" ? ["stop", containerId] : ["kill", ...signal === "SIGKILL" ? [] : [`--signal=${signal}`], containerId];
|
|
2073
|
+
await runOrThrow(runner, {
|
|
2074
|
+
command: engine,
|
|
2075
|
+
args: [...buildContextArgs(engine, context), ...args],
|
|
2076
|
+
stdout: "pipe",
|
|
2077
|
+
stderr: "pipe"
|
|
2078
|
+
});
|
|
1259
2079
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
function createAttachedSpec() {
|
|
2083
|
+
return {
|
|
2084
|
+
cwd: "/workspace",
|
|
2085
|
+
runtime: {
|
|
2086
|
+
type: "docker",
|
|
2087
|
+
image: "attached",
|
|
2088
|
+
build_args: {},
|
|
2089
|
+
mounts: []
|
|
2090
|
+
},
|
|
2091
|
+
env: {},
|
|
2092
|
+
uploadIgnoreFiles: [],
|
|
2093
|
+
jobLabel: {
|
|
2094
|
+
tool: "docker",
|
|
2095
|
+
argv: []
|
|
1265
2096
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
function shellQuote(value) {
|
|
2100
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
// packages/process-runner/src/host/host-execution-env.ts
|
|
2104
|
+
var hostExecutionEnvFactory = {
|
|
2105
|
+
type: "host",
|
|
2106
|
+
supportsDetach: false,
|
|
2107
|
+
async open(openSpec) {
|
|
2108
|
+
return {
|
|
2109
|
+
id: "host",
|
|
2110
|
+
job: null,
|
|
2111
|
+
async uploadWorkspace() {
|
|
2112
|
+
return {
|
|
2113
|
+
files: 0,
|
|
2114
|
+
bytes: 0,
|
|
2115
|
+
skipped: []
|
|
2116
|
+
};
|
|
2117
|
+
},
|
|
2118
|
+
async downloadWorkspace() {
|
|
2119
|
+
return {
|
|
2120
|
+
files: 0,
|
|
2121
|
+
bytes: 0,
|
|
2122
|
+
conflicts: []
|
|
2123
|
+
};
|
|
2124
|
+
},
|
|
2125
|
+
exec(spec) {
|
|
2126
|
+
return createHostRunner().exec(spec);
|
|
2127
|
+
},
|
|
2128
|
+
async detach() {
|
|
2129
|
+
throw new Error("host runtime does not support detach because host has no addressable env");
|
|
2130
|
+
},
|
|
2131
|
+
shell() {
|
|
2132
|
+
const shellSpec = openSpec.shellSpec;
|
|
2133
|
+
return createHostRunner().exec({
|
|
2134
|
+
command: shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
|
|
2135
|
+
...shellSpec?.args ? { args: shellSpec.args } : {},
|
|
2136
|
+
cwd: openSpec.cwd,
|
|
2137
|
+
env: shellSpec && "env" in shellSpec ? shellSpec.env : openSpec.env,
|
|
2138
|
+
stdin: "inherit",
|
|
2139
|
+
stdout: "inherit",
|
|
2140
|
+
stderr: "inherit",
|
|
2141
|
+
tty: true
|
|
2142
|
+
});
|
|
2143
|
+
},
|
|
2144
|
+
async close() {
|
|
1278
2145
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
2146
|
+
};
|
|
2147
|
+
},
|
|
2148
|
+
async attach() {
|
|
2149
|
+
throw new Error("host runtime does not support reattach");
|
|
1283
2150
|
}
|
|
1284
|
-
return { changed, result };
|
|
1285
|
-
}
|
|
1286
|
-
var jsonFormat = {
|
|
1287
|
-
parse: parse3,
|
|
1288
|
-
serialize,
|
|
1289
|
-
merge: merge2,
|
|
1290
|
-
prune: prune2
|
|
1291
2151
|
};
|
|
1292
2152
|
|
|
1293
|
-
// packages/
|
|
1294
|
-
import {
|
|
1295
|
-
|
|
1296
|
-
|
|
2153
|
+
// packages/process-runner/src/testing/mock-runner.ts
|
|
2154
|
+
import { Readable, Writable } from "node:stream";
|
|
2155
|
+
|
|
2156
|
+
// packages/agent-spawn/src/register-factories.ts
|
|
2157
|
+
registerExecutionEnvFactory(hostExecutionEnvFactory);
|
|
2158
|
+
registerExecutionEnvFactory(dockerExecutionEnvFactory);
|
|
2159
|
+
if (process.env.VITEST === "true") {
|
|
2160
|
+
registerExecutionEnvFactory(createTestHostExecutionEnvFactory());
|
|
1297
2161
|
}
|
|
1298
|
-
function
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
2162
|
+
function createTestHostExecutionEnvFactory() {
|
|
2163
|
+
return {
|
|
2164
|
+
type: "host",
|
|
2165
|
+
supportsDetach: false,
|
|
2166
|
+
open: ((openSpec) => {
|
|
2167
|
+
return {
|
|
2168
|
+
id: "host",
|
|
2169
|
+
job: null,
|
|
2170
|
+
async uploadWorkspace() {
|
|
2171
|
+
return { files: 0, bytes: 0, skipped: [] };
|
|
2172
|
+
},
|
|
2173
|
+
async downloadWorkspace() {
|
|
2174
|
+
return { files: 0, bytes: 0, conflicts: [] };
|
|
2175
|
+
},
|
|
2176
|
+
exec(spec) {
|
|
2177
|
+
return runHost(spawnChildProcess2, spec);
|
|
2178
|
+
},
|
|
2179
|
+
async detach() {
|
|
2180
|
+
throw new Error(
|
|
2181
|
+
"host runtime does not support detach because host has no addressable env"
|
|
2182
|
+
);
|
|
2183
|
+
},
|
|
2184
|
+
shell() {
|
|
2185
|
+
return runHost(spawnChildProcess2, {
|
|
2186
|
+
command: openSpec.shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
|
|
2187
|
+
args: openSpec.shellSpec?.args,
|
|
2188
|
+
cwd: openSpec.cwd,
|
|
2189
|
+
env: openSpec.shellSpec && "env" in openSpec.shellSpec ? openSpec.shellSpec.env : openSpec.env,
|
|
2190
|
+
stdin: "inherit",
|
|
2191
|
+
stdout: "inherit",
|
|
2192
|
+
stderr: "inherit",
|
|
2193
|
+
tty: true
|
|
2194
|
+
});
|
|
2195
|
+
},
|
|
2196
|
+
async close() {
|
|
2197
|
+
}
|
|
2198
|
+
};
|
|
2199
|
+
}),
|
|
2200
|
+
async attach() {
|
|
2201
|
+
throw new Error("host runtime does not support reattach");
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
function runHost(spawnProcess, spec) {
|
|
2206
|
+
const stdin = spec.stdin ?? "ignore";
|
|
2207
|
+
const stdout = spec.stdout ?? "pipe";
|
|
2208
|
+
const stderr = spec.stderr ?? "pipe";
|
|
2209
|
+
const stdio = stdin === "inherit" && stdout === "inherit" && stderr === "inherit" ? "inherit" : [stdin, stdout, stderr];
|
|
2210
|
+
const child = spawnProcess(spec.command, spec.args ?? [], {
|
|
2211
|
+
cwd: spec.cwd,
|
|
2212
|
+
env: spec.env,
|
|
2213
|
+
stdio
|
|
2214
|
+
});
|
|
2215
|
+
const result = new Promise((resolve2) => {
|
|
2216
|
+
child.once("close", (code) => {
|
|
2217
|
+
resolve2({ exitCode: code ?? 1 });
|
|
2218
|
+
});
|
|
2219
|
+
child.once("error", () => {
|
|
2220
|
+
resolve2({ exitCode: 1 });
|
|
2221
|
+
});
|
|
2222
|
+
});
|
|
2223
|
+
const kill = (signal) => {
|
|
2224
|
+
child.kill(signal);
|
|
2225
|
+
};
|
|
2226
|
+
if (spec.signal?.aborted) {
|
|
2227
|
+
kill("SIGTERM");
|
|
2228
|
+
} else {
|
|
2229
|
+
spec.signal?.addEventListener("abort", () => kill("SIGTERM"), { once: true });
|
|
1305
2230
|
}
|
|
1306
|
-
return
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
2231
|
+
return {
|
|
2232
|
+
pid: child.pid ?? null,
|
|
2233
|
+
stdin: child.stdin,
|
|
2234
|
+
stdout: child.stdout,
|
|
2235
|
+
stderr: child.stderr,
|
|
2236
|
+
result,
|
|
2237
|
+
kill
|
|
2238
|
+
};
|
|
1312
2239
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
result[key] = merge3(existing, value);
|
|
1322
|
-
continue;
|
|
1323
|
-
}
|
|
1324
|
-
result[key] = value;
|
|
2240
|
+
|
|
2241
|
+
// packages/agent-spawn/src/run-command.ts
|
|
2242
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
2243
|
+
|
|
2244
|
+
// packages/agent-spawn/src/types.ts
|
|
2245
|
+
function resolveModeConfig(modeConfig) {
|
|
2246
|
+
if (Array.isArray(modeConfig)) {
|
|
2247
|
+
return { args: modeConfig };
|
|
1325
2248
|
}
|
|
1326
|
-
return
|
|
2249
|
+
return {
|
|
2250
|
+
args: modeConfig.args ?? [],
|
|
2251
|
+
env: modeConfig.env && Object.keys(modeConfig.env).length > 0 ? modeConfig.env : void 0
|
|
2252
|
+
};
|
|
1327
2253
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
2254
|
+
|
|
2255
|
+
// packages/agent-spawn/src/configs/mcp.ts
|
|
2256
|
+
function toJsonMcpServers(servers) {
|
|
2257
|
+
const out = {};
|
|
2258
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
2259
|
+
const mapped = { command: server.command };
|
|
2260
|
+
if (server.args && server.args.length > 0) {
|
|
2261
|
+
mapped.args = server.args;
|
|
1334
2262
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
delete result[key];
|
|
1338
|
-
changed = true;
|
|
1339
|
-
continue;
|
|
2263
|
+
if (server.env && Object.keys(server.env).length > 0) {
|
|
2264
|
+
mapped.env = server.env;
|
|
1340
2265
|
}
|
|
1341
|
-
if (
|
|
1342
|
-
|
|
1343
|
-
current,
|
|
1344
|
-
pattern
|
|
1345
|
-
);
|
|
1346
|
-
if (childChanged) {
|
|
1347
|
-
changed = true;
|
|
1348
|
-
}
|
|
1349
|
-
if (Object.keys(childResult).length === 0) {
|
|
1350
|
-
delete result[key];
|
|
1351
|
-
} else {
|
|
1352
|
-
result[key] = childResult;
|
|
1353
|
-
}
|
|
1354
|
-
continue;
|
|
2266
|
+
if (server.timeout !== void 0) {
|
|
2267
|
+
mapped.timeout = server.timeout;
|
|
1355
2268
|
}
|
|
1356
|
-
|
|
1357
|
-
changed = true;
|
|
2269
|
+
out[name] = mapped;
|
|
1358
2270
|
}
|
|
1359
|
-
return
|
|
2271
|
+
return out;
|
|
1360
2272
|
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
serialize: serialize2,
|
|
1364
|
-
merge: merge3,
|
|
1365
|
-
prune: prune3
|
|
1366
|
-
};
|
|
1367
|
-
|
|
1368
|
-
// packages/config-mutations/src/formats/yaml.ts
|
|
1369
|
-
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
1370
|
-
function isConfigObject3(value) {
|
|
1371
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2273
|
+
function toTomlString(value) {
|
|
2274
|
+
return JSON.stringify(value);
|
|
1372
2275
|
}
|
|
1373
|
-
function
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
if (!isConfigObject3(parsed)) {
|
|
1382
|
-
throw new Error("Expected YAML object.");
|
|
2276
|
+
function toTomlArray(values) {
|
|
2277
|
+
const serialized = values.map((value) => toTomlString(value));
|
|
2278
|
+
return `[${serialized.join(", ")}]`;
|
|
2279
|
+
}
|
|
2280
|
+
function toTomlInlineTable(values) {
|
|
2281
|
+
const parts = [];
|
|
2282
|
+
for (const [key, value] of Object.entries(values)) {
|
|
2283
|
+
parts.push(`${JSON.stringify(key)}=${toTomlString(value)}`);
|
|
1383
2284
|
}
|
|
1384
|
-
return
|
|
2285
|
+
return `{${parts.join(", ")}}`;
|
|
1385
2286
|
}
|
|
1386
|
-
function
|
|
1387
|
-
|
|
1388
|
-
return serialized.endsWith("\n") ? serialized : `${serialized}
|
|
1389
|
-
`;
|
|
2287
|
+
function serializeJsonMcpArgs(servers) {
|
|
2288
|
+
return ["--mcp-config", JSON.stringify({ mcpServers: toJsonMcpServers(servers) })];
|
|
1390
2289
|
}
|
|
1391
|
-
function
|
|
1392
|
-
const
|
|
1393
|
-
for (const [
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
const existing = result[key];
|
|
1398
|
-
if (isConfigObject3(existing) && isConfigObject3(value)) {
|
|
1399
|
-
result[key] = merge4(existing, value);
|
|
1400
|
-
continue;
|
|
2290
|
+
function serializeOpenCodeMcpEnv(servers) {
|
|
2291
|
+
const mcp = {};
|
|
2292
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
2293
|
+
const entry = { type: "local", command: [server.command, ...server.args ?? []] };
|
|
2294
|
+
if (server.env && Object.keys(server.env).length > 0) {
|
|
2295
|
+
entry.environment = server.env;
|
|
1401
2296
|
}
|
|
1402
|
-
|
|
2297
|
+
mcp[name] = entry;
|
|
1403
2298
|
}
|
|
1404
|
-
return
|
|
2299
|
+
return { OPENCODE_CONFIG_CONTENT: JSON.stringify({ mcp }) };
|
|
1405
2300
|
}
|
|
1406
|
-
function
|
|
1407
|
-
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
2301
|
+
function serializeCodexMcpArgs(servers) {
|
|
2302
|
+
const args = [];
|
|
2303
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
2304
|
+
const prefix = `mcp_servers.${name}`;
|
|
2305
|
+
args.push("-c", `${prefix}.command=${toTomlString(server.command)}`);
|
|
2306
|
+
if (server.args && server.args.length > 0) {
|
|
2307
|
+
args.push("-c", `${prefix}.args=${toTomlArray(server.args)}`);
|
|
1412
2308
|
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
delete result[key];
|
|
1416
|
-
changed = true;
|
|
1417
|
-
continue;
|
|
2309
|
+
if (server.env && Object.keys(server.env).length > 0) {
|
|
2310
|
+
args.push("-c", `${prefix}.env=${toTomlInlineTable(server.env)}`);
|
|
1418
2311
|
}
|
|
1419
|
-
if (
|
|
1420
|
-
|
|
1421
|
-
if (childChanged) {
|
|
1422
|
-
changed = true;
|
|
1423
|
-
}
|
|
1424
|
-
if (Object.keys(childResult).length === 0) {
|
|
1425
|
-
delete result[key];
|
|
1426
|
-
} else {
|
|
1427
|
-
result[key] = childResult;
|
|
1428
|
-
}
|
|
1429
|
-
continue;
|
|
2312
|
+
if (server.timeout !== void 0) {
|
|
2313
|
+
args.push("-c", `${prefix}.timeout=${server.timeout}`);
|
|
1430
2314
|
}
|
|
1431
|
-
delete result[key];
|
|
1432
|
-
changed = true;
|
|
1433
2315
|
}
|
|
1434
|
-
return
|
|
2316
|
+
return args;
|
|
1435
2317
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
2318
|
+
function serializeGooseMcpArgs(servers) {
|
|
2319
|
+
return Object.values(servers).flatMap((server) => [
|
|
2320
|
+
"--with-extension",
|
|
2321
|
+
[server.command, ...server.args ?? []].join(" ")
|
|
2322
|
+
]);
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
// packages/agent-spawn/src/configs/claude-code.ts
|
|
2326
|
+
var claudeCodeSpawnConfig = {
|
|
2327
|
+
kind: "cli",
|
|
2328
|
+
agentId: "claude-code",
|
|
2329
|
+
// ACP adapter support: yes (adapter: "claude")
|
|
2330
|
+
adapter: "claude",
|
|
2331
|
+
promptFlag: "-p",
|
|
2332
|
+
modelFlag: "--model",
|
|
2333
|
+
modelStripProviderPrefix: true,
|
|
2334
|
+
modelTransform: (model) => model.replaceAll(".", "-"),
|
|
2335
|
+
defaultArgs: [
|
|
2336
|
+
"--output-format",
|
|
2337
|
+
"stream-json",
|
|
2338
|
+
"--verbose"
|
|
2339
|
+
],
|
|
2340
|
+
mcpArgs: serializeJsonMcpArgs,
|
|
2341
|
+
modes: {
|
|
2342
|
+
yolo: ["--dangerously-skip-permissions"],
|
|
2343
|
+
edit: ["--permission-mode", "acceptEdits", "--allowedTools", "Bash,Read,Write,Edit,Glob,Grep,NotebookEdit"],
|
|
2344
|
+
read: ["--permission-mode", "plan"]
|
|
2345
|
+
},
|
|
2346
|
+
stdinMode: {
|
|
2347
|
+
omitPrompt: true,
|
|
2348
|
+
extraArgs: ["--input-format", "text"]
|
|
2349
|
+
},
|
|
2350
|
+
interactive: {
|
|
2351
|
+
defaultArgs: []
|
|
2352
|
+
},
|
|
2353
|
+
resumeCommand: (threadId) => ["--resume", threadId]
|
|
2354
|
+
};
|
|
2355
|
+
|
|
2356
|
+
// packages/agent-spawn/src/configs/codex.ts
|
|
2357
|
+
var codexSpawnConfig = {
|
|
2358
|
+
kind: "cli",
|
|
2359
|
+
agentId: "codex",
|
|
2360
|
+
// ACP adapter support: yes (adapter: "codex")
|
|
2361
|
+
adapter: "codex",
|
|
2362
|
+
promptFlag: "exec",
|
|
2363
|
+
modelFlag: "--model",
|
|
2364
|
+
modelStripProviderPrefix: true,
|
|
2365
|
+
defaultArgs: ["--skip-git-repo-check", "--json"],
|
|
2366
|
+
mcpArgs: serializeCodexMcpArgs,
|
|
2367
|
+
mcpArgsBeforeCommand: true,
|
|
2368
|
+
modes: {
|
|
2369
|
+
yolo: ["-s", "danger-full-access"],
|
|
2370
|
+
edit: ["-s", "workspace-write"],
|
|
2371
|
+
read: ["-s", "read-only"]
|
|
2372
|
+
},
|
|
2373
|
+
stdinMode: {
|
|
2374
|
+
omitPrompt: true,
|
|
2375
|
+
extraArgs: ["-"]
|
|
2376
|
+
},
|
|
2377
|
+
interactive: {
|
|
2378
|
+
defaultArgs: ["-a", "never"]
|
|
2379
|
+
},
|
|
2380
|
+
resumeCommand: (threadId, cwd) => ["resume", "-C", cwd, threadId]
|
|
2381
|
+
};
|
|
2382
|
+
|
|
2383
|
+
// packages/agent-spawn/src/configs/opencode.ts
|
|
2384
|
+
var openCodeSpawnConfig = {
|
|
2385
|
+
kind: "cli",
|
|
2386
|
+
agentId: "opencode",
|
|
2387
|
+
// ACP adapter support: yes (adapter: "opencode").
|
|
2388
|
+
// OpenCode's `--format json` emits NDJSON events with `{ type, sessionID, part }`
|
|
2389
|
+
// (no `{ event, ... }` field), so it needs the OpenCode adapter (not "native").
|
|
2390
|
+
adapter: "opencode",
|
|
2391
|
+
promptFlag: "run",
|
|
2392
|
+
modelFlag: "--model",
|
|
2393
|
+
modelStripProviderPrefix: false,
|
|
2394
|
+
modelTransform: (model) => {
|
|
2395
|
+
return model.startsWith("poe/") ? model : `poe/${model}`;
|
|
2396
|
+
},
|
|
2397
|
+
defaultArgs: ["--format", "json"],
|
|
2398
|
+
modes: {
|
|
2399
|
+
yolo: [],
|
|
2400
|
+
edit: [],
|
|
2401
|
+
read: ["--agent", "plan"]
|
|
2402
|
+
},
|
|
2403
|
+
interactive: {
|
|
2404
|
+
defaultArgs: [],
|
|
2405
|
+
promptFlag: "--prompt"
|
|
2406
|
+
},
|
|
2407
|
+
resumeCommand: (threadId, cwd) => [cwd, "--session", threadId],
|
|
2408
|
+
mcpEnv: serializeOpenCodeMcpEnv
|
|
2409
|
+
};
|
|
2410
|
+
var openCodeAcpSpawnConfig = {
|
|
2411
|
+
kind: "acp",
|
|
2412
|
+
agentId: "opencode",
|
|
2413
|
+
acpArgs: ["acp"],
|
|
2414
|
+
skipAuth: true,
|
|
2415
|
+
mcpEnv: serializeOpenCodeMcpEnv
|
|
1441
2416
|
};
|
|
1442
2417
|
|
|
1443
|
-
// packages/
|
|
1444
|
-
var
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
2418
|
+
// packages/agent-spawn/src/configs/kimi.ts
|
|
2419
|
+
var kimiSpawnConfig = {
|
|
2420
|
+
kind: "cli",
|
|
2421
|
+
agentId: "kimi",
|
|
2422
|
+
// ACP adapter support: yes (adapter: "kimi").
|
|
2423
|
+
// Kimi's `--output-format stream-json` emits OpenAI-style `{ role, content }` JSON
|
|
2424
|
+
// (no `{ event, ... }` field), so it needs the Kimi adapter (not "native").
|
|
2425
|
+
adapter: "kimi",
|
|
2426
|
+
promptFlag: "-p",
|
|
2427
|
+
modelStripProviderPrefix: true,
|
|
2428
|
+
defaultArgs: ["--print", "--output-format", "stream-json"],
|
|
2429
|
+
mcpArgs: serializeJsonMcpArgs,
|
|
2430
|
+
modes: {
|
|
2431
|
+
yolo: ["--yolo"],
|
|
2432
|
+
edit: [],
|
|
2433
|
+
read: []
|
|
2434
|
+
},
|
|
2435
|
+
stdinMode: {
|
|
2436
|
+
omitPrompt: true,
|
|
2437
|
+
extraArgs: ["--input-format", "stream-json"]
|
|
2438
|
+
},
|
|
2439
|
+
interactive: {
|
|
2440
|
+
defaultArgs: [],
|
|
2441
|
+
promptFlag: "-p"
|
|
2442
|
+
},
|
|
2443
|
+
resumeCommand: (threadId, cwd) => ["--session", threadId, "--work-dir", cwd]
|
|
1448
2444
|
};
|
|
1449
|
-
var
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
".yml": "yaml"
|
|
2445
|
+
var kimiAcpSpawnConfig = {
|
|
2446
|
+
kind: "acp",
|
|
2447
|
+
agentId: "kimi",
|
|
2448
|
+
acpArgs: ["acp"]
|
|
1454
2449
|
};
|
|
1455
|
-
function getConfigFormat(pathOrFormat) {
|
|
1456
|
-
if (pathOrFormat in formatRegistry) {
|
|
1457
|
-
return formatRegistry[pathOrFormat];
|
|
1458
|
-
}
|
|
1459
|
-
const ext = getExtension(pathOrFormat);
|
|
1460
|
-
const formatName = extensionMap[ext];
|
|
1461
|
-
if (!formatName) {
|
|
1462
|
-
throw new Error(
|
|
1463
|
-
`Unsupported config format. Cannot detect format from "${pathOrFormat}". Supported extensions: ${Object.keys(extensionMap).join(", ")}. Supported format names: ${Object.keys(formatRegistry).join(", ")}.`
|
|
1464
|
-
);
|
|
1465
|
-
}
|
|
1466
|
-
return formatRegistry[formatName];
|
|
1467
|
-
}
|
|
1468
|
-
function detectFormat(path5) {
|
|
1469
|
-
const ext = getExtension(path5);
|
|
1470
|
-
return extensionMap[ext];
|
|
1471
|
-
}
|
|
1472
|
-
function getExtension(path5) {
|
|
1473
|
-
const lastDot = path5.lastIndexOf(".");
|
|
1474
|
-
if (lastDot === -1) {
|
|
1475
|
-
return "";
|
|
1476
|
-
}
|
|
1477
|
-
return path5.slice(lastDot).toLowerCase();
|
|
1478
|
-
}
|
|
1479
2450
|
|
|
1480
|
-
// packages/
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
}
|
|
1516
|
-
const rawDirectory = path4.dirname(expanded);
|
|
1517
|
-
const mappedDirectory = pathMapper.mapTargetDirectory({
|
|
1518
|
-
targetDirectory: rawDirectory
|
|
1519
|
-
});
|
|
1520
|
-
const filename = path4.basename(expanded);
|
|
1521
|
-
return filename.length === 0 ? mappedDirectory : path4.join(mappedDirectory, filename);
|
|
1522
|
-
}
|
|
2451
|
+
// packages/agent-spawn/src/configs/goose.ts
|
|
2452
|
+
var gooseFileSecretsEnv = { GOOSE_DISABLE_KEYRING: "1" };
|
|
2453
|
+
var gooseSpawnConfig = {
|
|
2454
|
+
kind: "cli",
|
|
2455
|
+
agentId: "goose",
|
|
2456
|
+
adapter: "native",
|
|
2457
|
+
promptFlag: "--text",
|
|
2458
|
+
modelFlag: "--model",
|
|
2459
|
+
modelStripProviderPrefix: false,
|
|
2460
|
+
defaultArgs: ["run", "--output-format", "stream-json"],
|
|
2461
|
+
defaultArgsPosition: "beforePrompt",
|
|
2462
|
+
mcpArgs: serializeGooseMcpArgs,
|
|
2463
|
+
mcpArgsPosition: "beforePrompt",
|
|
2464
|
+
modes: {
|
|
2465
|
+
yolo: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "auto" } },
|
|
2466
|
+
edit: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "smart_approve" } },
|
|
2467
|
+
read: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "chat" } }
|
|
2468
|
+
},
|
|
2469
|
+
stdinMode: {
|
|
2470
|
+
omitPrompt: true,
|
|
2471
|
+
extraArgs: ["--instructions", "-"]
|
|
2472
|
+
},
|
|
2473
|
+
interactive: {
|
|
2474
|
+
defaultArgs: ["session"],
|
|
2475
|
+
defaultArgsPosition: "beforePrompt"
|
|
2476
|
+
},
|
|
2477
|
+
resumeCommand: () => ["run", "--resume", "--text", "continue"]
|
|
2478
|
+
};
|
|
2479
|
+
var gooseAcpSpawnConfig = {
|
|
2480
|
+
kind: "acp",
|
|
2481
|
+
agentId: "goose",
|
|
2482
|
+
acpArgs: ["acp"],
|
|
2483
|
+
env: gooseFileSecretsEnv,
|
|
2484
|
+
skipAuth: true
|
|
2485
|
+
};
|
|
1523
2486
|
|
|
1524
|
-
// packages/
|
|
1525
|
-
|
|
1526
|
-
|
|
2487
|
+
// packages/agent-spawn/src/configs/index.ts
|
|
2488
|
+
var allSpawnConfigs = [
|
|
2489
|
+
claudeCodeSpawnConfig,
|
|
2490
|
+
codexSpawnConfig,
|
|
2491
|
+
openCodeSpawnConfig,
|
|
2492
|
+
kimiSpawnConfig,
|
|
2493
|
+
gooseSpawnConfig
|
|
2494
|
+
];
|
|
2495
|
+
var lookup2 = /* @__PURE__ */ new Map();
|
|
2496
|
+
for (const config of allSpawnConfigs) {
|
|
2497
|
+
lookup2.set(config.agentId, config);
|
|
1527
2498
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
2499
|
+
var acpLookup = /* @__PURE__ */ new Map();
|
|
2500
|
+
acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
|
|
2501
|
+
acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
|
|
2502
|
+
acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
|
|
2503
|
+
function getSpawnConfig(input) {
|
|
2504
|
+
const resolvedId = resolveAgentId(input);
|
|
2505
|
+
if (!resolvedId) {
|
|
2506
|
+
return void 0;
|
|
1536
2507
|
}
|
|
2508
|
+
return lookup2.get(resolvedId);
|
|
1537
2509
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
if (isNotFound(error2)) {
|
|
1544
|
-
return false;
|
|
2510
|
+
function listMcpSupportedAgents() {
|
|
2511
|
+
const supported = [];
|
|
2512
|
+
for (const config of allSpawnConfigs) {
|
|
2513
|
+
if (config.kind !== "cli" || typeof config.mcpArgs !== "function" && typeof config.mcpEnv !== "function") {
|
|
2514
|
+
continue;
|
|
1545
2515
|
}
|
|
1546
|
-
|
|
2516
|
+
supported.push(config.agentId);
|
|
1547
2517
|
}
|
|
1548
|
-
|
|
1549
|
-
function createTimestamp() {
|
|
1550
|
-
return (/* @__PURE__ */ new Date()).toISOString().replaceAll(":", "-").replaceAll(".", "-");
|
|
2518
|
+
return supported;
|
|
1551
2519
|
}
|
|
1552
2520
|
|
|
1553
|
-
// packages/
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
2521
|
+
// packages/agent-spawn/src/spawn.ts
|
|
2522
|
+
import { mkdirSync, openSync, writeSync, closeSync } from "node:fs";
|
|
2523
|
+
import path15 from "node:path";
|
|
2524
|
+
|
|
2525
|
+
// packages/agent-spawn/src/configs/resolve-config.ts
|
|
2526
|
+
function resolveConfig(agentId) {
|
|
2527
|
+
const resolvedAgentId = resolveAgentId(agentId);
|
|
2528
|
+
if (!resolvedAgentId) {
|
|
2529
|
+
throw new Error(`Unknown agent "${agentId}".`);
|
|
1557
2530
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
const backupPath = createInvalidDocumentBackupPath(targetPath);
|
|
1566
|
-
await fs.writeFile(backupPath, content, { encoding: "utf8" });
|
|
2531
|
+
const agentDefinition = allAgents.find((agent) => agent.id === resolvedAgentId);
|
|
2532
|
+
if (!agentDefinition) {
|
|
2533
|
+
throw new Error(`Unknown agent "${agentId}".`);
|
|
2534
|
+
}
|
|
2535
|
+
const spawnConfig = getSpawnConfig(resolvedAgentId);
|
|
2536
|
+
const binaryName = agentDefinition.binaryName;
|
|
2537
|
+
return { agentId: resolvedAgentId, binaryName, spawnConfig };
|
|
1567
2538
|
}
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
case "removeDirectory":
|
|
1574
|
-
return `Remove directory ${displayPath}`;
|
|
1575
|
-
case "backup":
|
|
1576
|
-
return `Backup ${displayPath}`;
|
|
1577
|
-
case "templateWrite":
|
|
1578
|
-
return `Write ${displayPath}`;
|
|
1579
|
-
case "chmod":
|
|
1580
|
-
return `Set permissions on ${displayPath}`;
|
|
1581
|
-
case "removeFile":
|
|
1582
|
-
return `Remove ${displayPath}`;
|
|
1583
|
-
case "configMerge":
|
|
1584
|
-
case "configPrune":
|
|
1585
|
-
case "configTransform":
|
|
1586
|
-
case "templateMergeToml":
|
|
1587
|
-
case "templateMergeJson":
|
|
1588
|
-
return `Update ${displayPath}`;
|
|
1589
|
-
default:
|
|
1590
|
-
return "Operation";
|
|
2539
|
+
|
|
2540
|
+
// packages/agent-spawn/src/mcp-args.ts
|
|
2541
|
+
function hasMcpServers(servers) {
|
|
2542
|
+
if (!servers) {
|
|
2543
|
+
return false;
|
|
1591
2544
|
}
|
|
2545
|
+
return Object.keys(servers).length > 0;
|
|
1592
2546
|
}
|
|
1593
|
-
function
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
if (!key.startsWith(prefix)) {
|
|
1597
|
-
result[key] = value;
|
|
1598
|
-
}
|
|
2547
|
+
function getMcpArgs(config, servers) {
|
|
2548
|
+
if (!hasMcpServers(servers)) {
|
|
2549
|
+
return [];
|
|
1599
2550
|
}
|
|
1600
|
-
|
|
2551
|
+
if (!config.mcpArgs && !config.mcpEnv) {
|
|
2552
|
+
throw new Error(formatUnsupportedMcpSpawnMessage(config.agentId));
|
|
2553
|
+
}
|
|
2554
|
+
if (!config.mcpArgs) {
|
|
2555
|
+
return [];
|
|
2556
|
+
}
|
|
2557
|
+
return config.mcpArgs(servers);
|
|
1601
2558
|
}
|
|
1602
|
-
function
|
|
1603
|
-
|
|
2559
|
+
function formatUnsupportedMcpSpawnMessage(agentId) {
|
|
2560
|
+
const supported = listMcpSupportedAgents();
|
|
2561
|
+
const supportedText = supported.length > 0 ? supported.join(", ") : "(none)";
|
|
2562
|
+
return `Agent "${agentId}" does not support MCP servers at spawn time.
|
|
2563
|
+
Agents with spawn-time MCP support: ${supportedText}`;
|
|
1604
2564
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
const prefix = prefixMap[key];
|
|
1611
|
-
if (isConfigObject4(current) && isConfigObject4(value)) {
|
|
1612
|
-
if (prefix) {
|
|
1613
|
-
const pruned = pruneKeysByPrefix(current, prefix);
|
|
1614
|
-
result[key] = { ...pruned, ...value };
|
|
1615
|
-
} else {
|
|
1616
|
-
result[key] = mergeWithPruneByPrefix(
|
|
1617
|
-
current,
|
|
1618
|
-
value,
|
|
1619
|
-
prefixMap
|
|
1620
|
-
);
|
|
1621
|
-
}
|
|
1622
|
-
continue;
|
|
1623
|
-
}
|
|
1624
|
-
result[key] = value;
|
|
1625
|
-
}
|
|
1626
|
-
return result;
|
|
2565
|
+
|
|
2566
|
+
// packages/agent-spawn/src/model-utils.ts
|
|
2567
|
+
function stripModelNamespace(model) {
|
|
2568
|
+
const slashIndex = model.indexOf("/");
|
|
2569
|
+
return slashIndex === -1 ? model : model.slice(slashIndex + 1);
|
|
1627
2570
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
case "removeFile":
|
|
1635
|
-
return applyRemoveFile(mutation, context, options);
|
|
1636
|
-
case "chmod":
|
|
1637
|
-
return applyChmod(mutation, context, options);
|
|
1638
|
-
case "backup":
|
|
1639
|
-
return applyBackup(mutation, context, options);
|
|
1640
|
-
case "configMerge":
|
|
1641
|
-
return applyConfigMerge(mutation, context, options);
|
|
1642
|
-
case "configPrune":
|
|
1643
|
-
return applyConfigPrune(mutation, context, options);
|
|
1644
|
-
case "configTransform":
|
|
1645
|
-
return applyConfigTransform(mutation, context, options);
|
|
1646
|
-
case "templateWrite":
|
|
1647
|
-
return applyTemplateWrite(mutation, context, options);
|
|
1648
|
-
case "templateMergeToml":
|
|
1649
|
-
return applyTemplateMerge(mutation, context, options, "toml");
|
|
1650
|
-
case "templateMergeJson":
|
|
1651
|
-
return applyTemplateMerge(mutation, context, options, "json");
|
|
1652
|
-
default: {
|
|
1653
|
-
const never = mutation;
|
|
1654
|
-
throw new Error(`Unknown mutation kind: ${never.kind}`);
|
|
1655
|
-
}
|
|
2571
|
+
|
|
2572
|
+
// packages/agent-spawn/src/spawn.ts
|
|
2573
|
+
function resolveCliConfig(agentId) {
|
|
2574
|
+
const resolved = resolveConfig(agentId);
|
|
2575
|
+
if (!resolved.spawnConfig) {
|
|
2576
|
+
throw new Error(`Agent "${resolved.agentId}" has no spawn config.`);
|
|
1656
2577
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
kind: mutation.kind,
|
|
1663
|
-
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1664
|
-
targetPath
|
|
1665
|
-
};
|
|
1666
|
-
const existed = await pathExists(context.fs, targetPath);
|
|
1667
|
-
if (!context.dryRun) {
|
|
1668
|
-
await context.fs.mkdir(targetPath, { recursive: true });
|
|
2578
|
+
if (resolved.spawnConfig.kind !== "cli") {
|
|
2579
|
+
throw new Error(`Agent "${resolved.agentId}" does not support CLI spawn.`);
|
|
2580
|
+
}
|
|
2581
|
+
if (!resolved.binaryName) {
|
|
2582
|
+
throw new Error(`Agent "${resolved.agentId}" has no binaryName.`);
|
|
1669
2583
|
}
|
|
1670
2584
|
return {
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
detail: existed ? "noop" : "create"
|
|
1675
|
-
},
|
|
1676
|
-
details
|
|
2585
|
+
agentId: resolved.agentId,
|
|
2586
|
+
binaryName: resolved.binaryName,
|
|
2587
|
+
spawnConfig: resolved.spawnConfig
|
|
1677
2588
|
};
|
|
1678
2589
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
targetPath
|
|
1686
|
-
};
|
|
1687
|
-
const existed = await pathExists(context.fs, targetPath);
|
|
1688
|
-
if (!existed) {
|
|
1689
|
-
return {
|
|
1690
|
-
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1691
|
-
details
|
|
1692
|
-
};
|
|
2590
|
+
function getDefaultArgsPosition(config) {
|
|
2591
|
+
return config.defaultArgsPosition ?? "afterPrompt";
|
|
2592
|
+
}
|
|
2593
|
+
function getMcpArgsPosition(config) {
|
|
2594
|
+
if (config.mcpArgsPosition) {
|
|
2595
|
+
return config.mcpArgsPosition;
|
|
1693
2596
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
2597
|
+
return config.mcpArgsBeforeCommand ? "beforeCommand" : "afterCommand";
|
|
2598
|
+
}
|
|
2599
|
+
function buildCliArgs(config, options, stdinMode) {
|
|
2600
|
+
const mcpArgs = getMcpArgs(config, options.mcpServers);
|
|
2601
|
+
const defaultArgsPosition = getDefaultArgsPosition(config);
|
|
2602
|
+
const mcpArgsPosition = getMcpArgsPosition(config);
|
|
2603
|
+
const args = [];
|
|
2604
|
+
if (mcpArgsPosition === "beforeCommand") {
|
|
2605
|
+
args.push(...mcpArgs);
|
|
1699
2606
|
}
|
|
1700
|
-
if (
|
|
1701
|
-
|
|
1702
|
-
await context.fs.rm(targetPath, { recursive: true, force: true });
|
|
1703
|
-
}
|
|
1704
|
-
return {
|
|
1705
|
-
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1706
|
-
details
|
|
1707
|
-
};
|
|
2607
|
+
if (defaultArgsPosition === "beforePrompt") {
|
|
2608
|
+
args.push(...config.defaultArgs);
|
|
1708
2609
|
}
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
return {
|
|
1712
|
-
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1713
|
-
details
|
|
1714
|
-
};
|
|
2610
|
+
if (mcpArgsPosition === "beforePrompt") {
|
|
2611
|
+
args.push(...mcpArgs);
|
|
1715
2612
|
}
|
|
1716
|
-
if (
|
|
1717
|
-
|
|
2613
|
+
if (stdinMode) {
|
|
2614
|
+
args.push(
|
|
2615
|
+
config.promptFlag,
|
|
2616
|
+
...stdinMode.omitPrompt ? [] : [options.prompt],
|
|
2617
|
+
...stdinMode.extraArgs
|
|
2618
|
+
);
|
|
2619
|
+
} else {
|
|
2620
|
+
args.push(config.promptFlag, options.prompt);
|
|
1718
2621
|
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
2622
|
+
if (options.model && config.modelFlag) {
|
|
2623
|
+
let model = config.modelStripProviderPrefix ? stripModelNamespace(options.model) : options.model;
|
|
2624
|
+
if (config.modelTransform) model = config.modelTransform(model);
|
|
2625
|
+
args.push(config.modelFlag, model);
|
|
2626
|
+
}
|
|
2627
|
+
if (defaultArgsPosition === "afterPrompt") {
|
|
2628
|
+
args.push(...config.defaultArgs);
|
|
2629
|
+
}
|
|
2630
|
+
if (mcpArgsPosition === "afterCommand") {
|
|
2631
|
+
args.push(...mcpArgs);
|
|
2632
|
+
}
|
|
2633
|
+
const mode = resolveModeConfig(config.modes[options.mode ?? "yolo"]);
|
|
2634
|
+
args.push(...mode.args);
|
|
2635
|
+
if (options.args && options.args.length > 0) {
|
|
2636
|
+
args.push(...options.args);
|
|
2637
|
+
}
|
|
2638
|
+
return { args, env: mode.env };
|
|
1723
2639
|
}
|
|
1724
|
-
|
|
1725
|
-
const
|
|
1726
|
-
const
|
|
1727
|
-
const
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
2640
|
+
function buildSpawnArgs(agentId, options) {
|
|
2641
|
+
const { binaryName, spawnConfig } = resolveCliConfig(agentId);
|
|
2642
|
+
const stdinMode = options.useStdin && spawnConfig.stdinMode ? spawnConfig.stdinMode : void 0;
|
|
2643
|
+
const result = buildCliArgs(spawnConfig, options, stdinMode);
|
|
2644
|
+
return { binaryName, args: result.args, env: result.env };
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
// packages/design-system/src/tokens/colors.ts
|
|
2648
|
+
import chalk from "chalk";
|
|
2649
|
+
var dark = {
|
|
2650
|
+
header: (text4) => chalk.magentaBright.bold(text4),
|
|
2651
|
+
divider: (text4) => chalk.dim(text4),
|
|
2652
|
+
prompt: (text4) => chalk.cyan(text4),
|
|
2653
|
+
number: (text4) => chalk.cyanBright(text4),
|
|
2654
|
+
intro: (text4) => chalk.bgMagenta.white(` Poe - ${text4} `),
|
|
2655
|
+
resolvedSymbol: chalk.magenta("\u25C7"),
|
|
2656
|
+
errorSymbol: chalk.red("\u25A0"),
|
|
2657
|
+
accent: (text4) => chalk.cyan(text4),
|
|
2658
|
+
muted: (text4) => chalk.dim(text4),
|
|
2659
|
+
success: (text4) => chalk.green(text4),
|
|
2660
|
+
warning: (text4) => chalk.yellow(text4),
|
|
2661
|
+
error: (text4) => chalk.red(text4),
|
|
2662
|
+
info: (text4) => chalk.magenta(text4),
|
|
2663
|
+
badge: (text4) => chalk.bgYellow.black(` ${text4} `)
|
|
2664
|
+
};
|
|
2665
|
+
var light = {
|
|
2666
|
+
header: (text4) => chalk.hex("#a200ff").bold(text4),
|
|
2667
|
+
divider: (text4) => chalk.hex("#666666")(text4),
|
|
2668
|
+
prompt: (text4) => chalk.hex("#006699").bold(text4),
|
|
2669
|
+
number: (text4) => chalk.hex("#0077cc").bold(text4),
|
|
2670
|
+
intro: (text4) => chalk.bgHex("#a200ff").white(` Poe - ${text4} `),
|
|
2671
|
+
resolvedSymbol: chalk.hex("#a200ff")("\u25C7"),
|
|
2672
|
+
errorSymbol: chalk.hex("#cc0000")("\u25A0"),
|
|
2673
|
+
accent: (text4) => chalk.hex("#006699").bold(text4),
|
|
2674
|
+
muted: (text4) => chalk.hex("#666666")(text4),
|
|
2675
|
+
success: (text4) => chalk.hex("#008800")(text4),
|
|
2676
|
+
warning: (text4) => chalk.hex("#cc6600")(text4),
|
|
2677
|
+
error: (text4) => chalk.hex("#cc0000")(text4),
|
|
2678
|
+
info: (text4) => chalk.hex("#a200ff")(text4),
|
|
2679
|
+
badge: (text4) => chalk.bgHex("#cc6600").white(` ${text4} `)
|
|
2680
|
+
};
|
|
2681
|
+
|
|
2682
|
+
// packages/design-system/src/tokens/typography.ts
|
|
2683
|
+
import chalk2 from "chalk";
|
|
2684
|
+
|
|
2685
|
+
// packages/design-system/src/components/text.ts
|
|
2686
|
+
import chalk3 from "chalk";
|
|
2687
|
+
|
|
2688
|
+
// packages/design-system/src/internal/output-format.ts
|
|
2689
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2690
|
+
var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
|
|
2691
|
+
var formatStorage = new AsyncLocalStorage();
|
|
2692
|
+
var cached;
|
|
2693
|
+
function resolveOutputFormat(env = process.env) {
|
|
2694
|
+
const scoped = formatStorage.getStore();
|
|
2695
|
+
if (scoped) {
|
|
2696
|
+
return scoped;
|
|
2697
|
+
}
|
|
2698
|
+
if (cached) {
|
|
2699
|
+
return cached;
|
|
1762
2700
|
}
|
|
2701
|
+
const raw = env.OUTPUT_FORMAT?.toLowerCase();
|
|
2702
|
+
cached = VALID_FORMATS.has(raw) ? raw : "terminal";
|
|
2703
|
+
return cached;
|
|
1763
2704
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
targetPath
|
|
1771
|
-
};
|
|
1772
|
-
if (typeof context.fs.chmod !== "function") {
|
|
1773
|
-
return {
|
|
1774
|
-
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1775
|
-
details
|
|
1776
|
-
};
|
|
2705
|
+
|
|
2706
|
+
// packages/design-system/src/internal/theme-detect.ts
|
|
2707
|
+
function detectThemeFromEnv(env) {
|
|
2708
|
+
const apple = env.APPLE_INTERFACE_STYLE;
|
|
2709
|
+
if (typeof apple === "string") {
|
|
2710
|
+
return apple.toLowerCase() === "dark" ? "dark" : "light";
|
|
1777
2711
|
}
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
const
|
|
1781
|
-
if (
|
|
1782
|
-
return
|
|
1783
|
-
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1784
|
-
details
|
|
1785
|
-
};
|
|
2712
|
+
const vscodeKind = env.VSCODE_COLOR_THEME_KIND;
|
|
2713
|
+
if (typeof vscodeKind === "string") {
|
|
2714
|
+
const normalized = vscodeKind.toLowerCase();
|
|
2715
|
+
if (normalized.includes("light")) {
|
|
2716
|
+
return "light";
|
|
1786
2717
|
}
|
|
1787
|
-
if (
|
|
1788
|
-
|
|
2718
|
+
if (normalized.includes("dark")) {
|
|
2719
|
+
return "dark";
|
|
1789
2720
|
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
if (
|
|
1796
|
-
return
|
|
1797
|
-
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1798
|
-
details
|
|
1799
|
-
};
|
|
2721
|
+
}
|
|
2722
|
+
const colorFGBG = env.COLORFGBG;
|
|
2723
|
+
if (typeof colorFGBG === "string") {
|
|
2724
|
+
const parts = colorFGBG.split(";").map((part) => Number.parseInt(part, 10));
|
|
2725
|
+
const background = parts.at(-1);
|
|
2726
|
+
if (Number.isFinite(background)) {
|
|
2727
|
+
return background >= 8 ? "light" : "dark";
|
|
1800
2728
|
}
|
|
1801
|
-
throw error2;
|
|
1802
2729
|
}
|
|
2730
|
+
return void 0;
|
|
1803
2731
|
}
|
|
1804
|
-
|
|
1805
|
-
const
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
kind: mutation.kind,
|
|
1809
|
-
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1810
|
-
targetPath
|
|
1811
|
-
};
|
|
1812
|
-
const content = await readFileIfExists(context.fs, targetPath);
|
|
1813
|
-
if (content === null) {
|
|
1814
|
-
return {
|
|
1815
|
-
outcome: { changed: false, effect: "none", detail: "noop" },
|
|
1816
|
-
details
|
|
1817
|
-
};
|
|
2732
|
+
function resolveThemeName(env = process.env) {
|
|
2733
|
+
const raw = (env.POE_CODE_THEME ?? env.POE_THEME)?.toLowerCase();
|
|
2734
|
+
if (raw === "light" || raw === "dark") {
|
|
2735
|
+
return raw;
|
|
1818
2736
|
}
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
2737
|
+
const detected = detectThemeFromEnv(env);
|
|
2738
|
+
if (detected) {
|
|
2739
|
+
return detected;
|
|
1822
2740
|
}
|
|
1823
|
-
return
|
|
1824
|
-
outcome: { changed: true, effect: "copy", detail: "backup" },
|
|
1825
|
-
details
|
|
1826
|
-
};
|
|
2741
|
+
return "dark";
|
|
1827
2742
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
kind: mutation.kind,
|
|
1833
|
-
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
1834
|
-
targetPath
|
|
1835
|
-
};
|
|
1836
|
-
const formatName = mutation.format ?? detectFormat(rawPath);
|
|
1837
|
-
if (!formatName) {
|
|
1838
|
-
throw new Error(
|
|
1839
|
-
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
1840
|
-
);
|
|
1841
|
-
}
|
|
1842
|
-
const format = getConfigFormat(formatName);
|
|
1843
|
-
const rawContent = await readFileIfExists(context.fs, targetPath);
|
|
1844
|
-
let current;
|
|
1845
|
-
try {
|
|
1846
|
-
current = rawContent === null ? {} : format.parse(rawContent);
|
|
1847
|
-
} catch {
|
|
1848
|
-
if (rawContent !== null) {
|
|
1849
|
-
await backupInvalidDocument(context.fs, targetPath, rawContent);
|
|
1850
|
-
}
|
|
1851
|
-
current = {};
|
|
1852
|
-
}
|
|
1853
|
-
const value = resolveValue(mutation.value, options);
|
|
1854
|
-
let merged;
|
|
1855
|
-
if (mutation.pruneByPrefix) {
|
|
1856
|
-
merged = mergeWithPruneByPrefix(current, value, mutation.pruneByPrefix);
|
|
1857
|
-
} else {
|
|
1858
|
-
merged = format.merge(current, value);
|
|
1859
|
-
}
|
|
1860
|
-
const serialized = format.serialize(merged);
|
|
1861
|
-
const changed = serialized !== rawContent;
|
|
1862
|
-
if (changed && !context.dryRun) {
|
|
1863
|
-
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
2743
|
+
var cachedTheme;
|
|
2744
|
+
function getTheme(env) {
|
|
2745
|
+
if (cachedTheme) {
|
|
2746
|
+
return cachedTheme;
|
|
1864
2747
|
}
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
effect: changed ? "write" : "none",
|
|
1869
|
-
detail: changed ? rawContent === null ? "create" : "update" : "noop"
|
|
1870
|
-
},
|
|
1871
|
-
details
|
|
1872
|
-
};
|
|
2748
|
+
const themeName = resolveThemeName(env);
|
|
2749
|
+
cachedTheme = themeName === "light" ? light : dark;
|
|
2750
|
+
return cachedTheme;
|
|
1873
2751
|
}
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
);
|
|
2752
|
+
|
|
2753
|
+
// packages/design-system/src/components/symbols.ts
|
|
2754
|
+
import chalk4 from "chalk";
|
|
2755
|
+
var symbols = {
|
|
2756
|
+
get info() {
|
|
2757
|
+
const format = resolveOutputFormat();
|
|
2758
|
+
if (format === "json") return "info";
|
|
2759
|
+
if (format === "markdown") return "(i)";
|
|
2760
|
+
return chalk4.magenta("\u25CF");
|
|
2761
|
+
},
|
|
2762
|
+
get success() {
|
|
2763
|
+
const format = resolveOutputFormat();
|
|
2764
|
+
if (format === "json") return "success";
|
|
2765
|
+
if (format === "markdown") return "[ok]";
|
|
2766
|
+
return chalk4.magenta("\u25C6");
|
|
2767
|
+
},
|
|
2768
|
+
get resolved() {
|
|
2769
|
+
const format = resolveOutputFormat();
|
|
2770
|
+
if (format === "json") return "resolved";
|
|
2771
|
+
if (format === "markdown") return ">";
|
|
2772
|
+
return getTheme().resolvedSymbol;
|
|
2773
|
+
},
|
|
2774
|
+
get errorResolved() {
|
|
2775
|
+
const format = resolveOutputFormat();
|
|
2776
|
+
if (format === "json") return "error";
|
|
2777
|
+
if (format === "markdown") return "[!]";
|
|
2778
|
+
return getTheme().errorSymbol;
|
|
2779
|
+
},
|
|
2780
|
+
get bar() {
|
|
2781
|
+
const format = resolveOutputFormat();
|
|
2782
|
+
if (format === "json") return "";
|
|
2783
|
+
if (format === "markdown") return "|";
|
|
2784
|
+
return "\u2502";
|
|
2785
|
+
},
|
|
2786
|
+
cornerTopRight: "\u256E",
|
|
2787
|
+
cornerBottomRight: "\u256F",
|
|
2788
|
+
get warning() {
|
|
2789
|
+
const format = resolveOutputFormat();
|
|
2790
|
+
if (format === "json") return "warning";
|
|
2791
|
+
if (format === "markdown") return "[!]";
|
|
2792
|
+
return "\u25B2";
|
|
2793
|
+
},
|
|
2794
|
+
get active() {
|
|
2795
|
+
const format = resolveOutputFormat();
|
|
2796
|
+
if (format === "json") return "active";
|
|
2797
|
+
if (format === "markdown") return "[x]";
|
|
2798
|
+
return "\u25C6";
|
|
2799
|
+
},
|
|
2800
|
+
get inactive() {
|
|
2801
|
+
const format = resolveOutputFormat();
|
|
2802
|
+
if (format === "json") return "inactive";
|
|
2803
|
+
if (format === "markdown") return "[ ]";
|
|
2804
|
+
return "\u25CB";
|
|
1894
2805
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2806
|
+
};
|
|
2807
|
+
|
|
2808
|
+
// packages/design-system/src/components/logger.ts
|
|
2809
|
+
import chalk6 from "chalk";
|
|
2810
|
+
|
|
2811
|
+
// packages/design-system/src/prompts/primitives/log.ts
|
|
2812
|
+
import chalk5 from "chalk";
|
|
2813
|
+
|
|
2814
|
+
// packages/design-system/src/internal/strip-ansi.ts
|
|
2815
|
+
function stripAnsi(value) {
|
|
2816
|
+
return value.replace(/\u001b\[[0-9;]*m/g, "");
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
// packages/design-system/src/prompts/primitives/log.ts
|
|
2820
|
+
function writeTerminalMessage(msg, {
|
|
2821
|
+
symbol = chalk5.gray("\u2502"),
|
|
2822
|
+
secondarySymbol = chalk5.gray("\u2502"),
|
|
2823
|
+
spacing: spacing2 = 1,
|
|
2824
|
+
withGuide = true
|
|
2825
|
+
} = {}) {
|
|
2826
|
+
const lines = [];
|
|
2827
|
+
const showGuide = withGuide !== false;
|
|
2828
|
+
const contentLines = msg.split("\n");
|
|
2829
|
+
const prefix = showGuide ? `${symbol} ` : "";
|
|
2830
|
+
const continuationPrefix = showGuide ? `${secondarySymbol} ` : "";
|
|
2831
|
+
const emptyGuide = showGuide ? secondarySymbol : "";
|
|
2832
|
+
for (let index = 0; index < spacing2; index += 1) {
|
|
2833
|
+
lines.push(emptyGuide);
|
|
1904
2834
|
}
|
|
1905
|
-
if (
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
details
|
|
1909
|
-
};
|
|
2835
|
+
if (contentLines.length === 0) {
|
|
2836
|
+
process.stdout.write("\n");
|
|
2837
|
+
return;
|
|
1910
2838
|
}
|
|
1911
|
-
const
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
details
|
|
1917
|
-
};
|
|
2839
|
+
const [firstLine = "", ...continuationLines] = contentLines;
|
|
2840
|
+
if (firstLine.length > 0) {
|
|
2841
|
+
lines.push(`${prefix}${firstLine}`);
|
|
2842
|
+
} else {
|
|
2843
|
+
lines.push(showGuide ? symbol : "");
|
|
1918
2844
|
}
|
|
1919
|
-
|
|
1920
|
-
if (
|
|
1921
|
-
|
|
2845
|
+
for (const line of continuationLines) {
|
|
2846
|
+
if (line.length > 0) {
|
|
2847
|
+
lines.push(`${continuationPrefix}${line}`);
|
|
2848
|
+
continue;
|
|
1922
2849
|
}
|
|
1923
|
-
|
|
1924
|
-
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1925
|
-
details
|
|
1926
|
-
};
|
|
1927
|
-
}
|
|
1928
|
-
const serialized = format.serialize(result);
|
|
1929
|
-
if (!context.dryRun) {
|
|
1930
|
-
await context.fs.writeFile(targetPath, serialized, { encoding: "utf8" });
|
|
2850
|
+
lines.push(emptyGuide);
|
|
1931
2851
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
details
|
|
1935
|
-
};
|
|
2852
|
+
process.stdout.write(`${lines.join("\n")}
|
|
2853
|
+
`);
|
|
1936
2854
|
}
|
|
1937
|
-
|
|
1938
|
-
const
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
`Cannot detect config format for "${rawPath}". Provide explicit format option.`
|
|
2855
|
+
function message(msg, options) {
|
|
2856
|
+
const format = resolveOutputFormat();
|
|
2857
|
+
if (format === "markdown") {
|
|
2858
|
+
process.stdout.write(`- ${stripAnsi(msg)}
|
|
2859
|
+
`);
|
|
2860
|
+
return;
|
|
2861
|
+
}
|
|
2862
|
+
if (format === "json") {
|
|
2863
|
+
process.stdout.write(
|
|
2864
|
+
`${JSON.stringify({ level: "message", message: stripAnsi(msg) })}
|
|
2865
|
+
`
|
|
1949
2866
|
);
|
|
2867
|
+
return;
|
|
1950
2868
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
}
|
|
1960
|
-
current = {};
|
|
2869
|
+
writeTerminalMessage(msg, options);
|
|
2870
|
+
}
|
|
2871
|
+
function info(msg) {
|
|
2872
|
+
const format = resolveOutputFormat();
|
|
2873
|
+
if (format === "markdown") {
|
|
2874
|
+
process.stdout.write(`- **info:** ${stripAnsi(msg)}
|
|
2875
|
+
`);
|
|
2876
|
+
return;
|
|
1961
2877
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2878
|
+
if (format === "json") {
|
|
2879
|
+
process.stdout.write(
|
|
2880
|
+
`${JSON.stringify({ level: "info", message: stripAnsi(msg) })}
|
|
2881
|
+
`
|
|
2882
|
+
);
|
|
2883
|
+
return;
|
|
1968
2884
|
}
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
await context.fs.unlink(targetPath);
|
|
1978
|
-
}
|
|
1979
|
-
return {
|
|
1980
|
-
outcome: { changed: true, effect: "delete", detail: "delete" },
|
|
1981
|
-
details
|
|
1982
|
-
};
|
|
2885
|
+
message(msg, { symbol: symbols.info });
|
|
2886
|
+
}
|
|
2887
|
+
function success(msg) {
|
|
2888
|
+
const format = resolveOutputFormat();
|
|
2889
|
+
if (format === "markdown") {
|
|
2890
|
+
process.stdout.write(`- **success:** ${stripAnsi(msg)}
|
|
2891
|
+
`);
|
|
2892
|
+
return;
|
|
1983
2893
|
}
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2894
|
+
if (format === "json") {
|
|
2895
|
+
process.stdout.write(
|
|
2896
|
+
`${JSON.stringify({ level: "success", message: stripAnsi(msg) })}
|
|
2897
|
+
`
|
|
2898
|
+
);
|
|
2899
|
+
return;
|
|
1987
2900
|
}
|
|
1988
|
-
|
|
1989
|
-
outcome: {
|
|
1990
|
-
changed: true,
|
|
1991
|
-
effect: "write",
|
|
1992
|
-
detail: rawContent === null ? "create" : "update"
|
|
1993
|
-
},
|
|
1994
|
-
details
|
|
1995
|
-
};
|
|
2901
|
+
message(msg, { symbol: symbols.success });
|
|
1996
2902
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2903
|
+
function warn(msg) {
|
|
2904
|
+
const format = resolveOutputFormat();
|
|
2905
|
+
if (format === "markdown") {
|
|
2906
|
+
process.stdout.write(`- **warning:** ${stripAnsi(msg)}
|
|
2907
|
+
`);
|
|
2908
|
+
return;
|
|
2002
2909
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
};
|
|
2010
|
-
const template = await context.templates(mutation.templateId);
|
|
2011
|
-
const templateContext = mutation.context ? resolveValue(mutation.context, options) : {};
|
|
2012
|
-
const rendered = Mustache.render(template, templateContext);
|
|
2013
|
-
const existed = await pathExists(context.fs, targetPath);
|
|
2014
|
-
if (!context.dryRun) {
|
|
2015
|
-
await context.fs.writeFile(targetPath, rendered, { encoding: "utf8" });
|
|
2910
|
+
if (format === "json") {
|
|
2911
|
+
process.stdout.write(
|
|
2912
|
+
`${JSON.stringify({ level: "warn", message: stripAnsi(msg) })}
|
|
2913
|
+
`
|
|
2914
|
+
);
|
|
2915
|
+
return;
|
|
2016
2916
|
}
|
|
2017
|
-
|
|
2018
|
-
outcome: {
|
|
2019
|
-
changed: true,
|
|
2020
|
-
effect: "write",
|
|
2021
|
-
detail: existed ? "update" : "create"
|
|
2022
|
-
},
|
|
2023
|
-
details
|
|
2024
|
-
};
|
|
2917
|
+
message(msg, { symbol: chalk5.yellow("\u25B2") });
|
|
2025
2918
|
}
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2919
|
+
function error(msg) {
|
|
2920
|
+
const format = resolveOutputFormat();
|
|
2921
|
+
if (format === "markdown") {
|
|
2922
|
+
process.stdout.write(`- **error:** ${stripAnsi(msg)}
|
|
2923
|
+
`);
|
|
2924
|
+
return;
|
|
2031
2925
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
label: mutation.label ?? describeMutation(mutation.kind, targetPath),
|
|
2037
|
-
targetPath
|
|
2038
|
-
};
|
|
2039
|
-
const format = getConfigFormat(formatName);
|
|
2040
|
-
const template = await context.templates(mutation.templateId);
|
|
2041
|
-
const templateContext = mutation.context ? resolveValue(mutation.context, options) : {};
|
|
2042
|
-
const rendered = Mustache.render(template, templateContext);
|
|
2043
|
-
let templateDoc;
|
|
2044
|
-
try {
|
|
2045
|
-
templateDoc = format.parse(rendered);
|
|
2046
|
-
} catch (error2) {
|
|
2047
|
-
throw new Error(
|
|
2048
|
-
`Failed to parse rendered template "${mutation.templateId}" as ${formatName.toUpperCase()}: ${error2}`,
|
|
2049
|
-
{ cause: error2 }
|
|
2926
|
+
if (format === "json") {
|
|
2927
|
+
process.stdout.write(
|
|
2928
|
+
`${JSON.stringify({ level: "error", message: stripAnsi(msg) })}
|
|
2929
|
+
`
|
|
2050
2930
|
);
|
|
2931
|
+
return;
|
|
2051
2932
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2933
|
+
message(msg, { symbol: chalk5.red("\u25A0") });
|
|
2934
|
+
}
|
|
2935
|
+
var log = {
|
|
2936
|
+
info,
|
|
2937
|
+
success,
|
|
2938
|
+
message,
|
|
2939
|
+
warn,
|
|
2940
|
+
error
|
|
2941
|
+
};
|
|
2942
|
+
|
|
2943
|
+
// packages/design-system/src/components/logger.ts
|
|
2944
|
+
function createLogger(emitter) {
|
|
2945
|
+
const emit = (level, message2) => {
|
|
2946
|
+
if (emitter) {
|
|
2947
|
+
emitter(message2);
|
|
2948
|
+
return;
|
|
2059
2949
|
}
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2950
|
+
if (level === "success") {
|
|
2951
|
+
log.success(message2);
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
if (level === "warn") {
|
|
2955
|
+
log.warn(message2);
|
|
2956
|
+
return;
|
|
2957
|
+
}
|
|
2958
|
+
if (level === "error") {
|
|
2959
|
+
log.error(message2);
|
|
2960
|
+
return;
|
|
2961
|
+
}
|
|
2962
|
+
log.info(message2);
|
|
2963
|
+
};
|
|
2068
2964
|
return {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
effect: changed ? "write" : "none",
|
|
2072
|
-
detail: changed ? rawContent === null ? "create" : "update" : "noop"
|
|
2965
|
+
info(message2) {
|
|
2966
|
+
emit("info", message2);
|
|
2073
2967
|
},
|
|
2074
|
-
|
|
2968
|
+
success(message2) {
|
|
2969
|
+
emit("success", message2);
|
|
2970
|
+
},
|
|
2971
|
+
warn(message2) {
|
|
2972
|
+
emit("warn", message2);
|
|
2973
|
+
},
|
|
2974
|
+
error(message2) {
|
|
2975
|
+
emit("error", message2);
|
|
2976
|
+
},
|
|
2977
|
+
resolved(label, value) {
|
|
2978
|
+
if (emitter) {
|
|
2979
|
+
emitter(`${label}: ${value}`);
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
log.message(`${label}
|
|
2983
|
+
${value}`, { symbol: symbols.resolved });
|
|
2984
|
+
},
|
|
2985
|
+
errorResolved(label, value) {
|
|
2986
|
+
if (emitter) {
|
|
2987
|
+
emitter(`${label}: ${value}`);
|
|
2988
|
+
return;
|
|
2989
|
+
}
|
|
2990
|
+
log.message(`${label}
|
|
2991
|
+
${value}`, { symbol: symbols.errorResolved });
|
|
2992
|
+
},
|
|
2993
|
+
message(message2, symbol) {
|
|
2994
|
+
if (emitter) {
|
|
2995
|
+
emitter(message2);
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
log.message(message2, { symbol: symbol ?? chalk6.gray("\u2502") });
|
|
2999
|
+
}
|
|
2075
3000
|
};
|
|
2076
3001
|
}
|
|
3002
|
+
var logger = createLogger();
|
|
2077
3003
|
|
|
2078
|
-
// packages/
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
3004
|
+
// packages/design-system/src/components/table.ts
|
|
3005
|
+
import { Table } from "console-table-printer";
|
|
3006
|
+
|
|
3007
|
+
// packages/design-system/src/acp/components.ts
|
|
3008
|
+
import chalk7 from "chalk";
|
|
3009
|
+
|
|
3010
|
+
// packages/design-system/src/acp/writer.ts
|
|
3011
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
3012
|
+
var storage = new AsyncLocalStorage2();
|
|
3013
|
+
|
|
3014
|
+
// packages/design-system/src/acp/components.ts
|
|
3015
|
+
var AGENT_PREFIX = `${chalk7.green.bold("\u2713")} agent: `;
|
|
3016
|
+
|
|
3017
|
+
// packages/design-system/src/dashboard/buffer.ts
|
|
3018
|
+
import chalk8 from "chalk";
|
|
3019
|
+
|
|
3020
|
+
// packages/design-system/src/dashboard/terminal.ts
|
|
3021
|
+
import readline from "node:readline";
|
|
3022
|
+
import { PassThrough } from "node:stream";
|
|
3023
|
+
|
|
3024
|
+
// packages/design-system/src/prompts/index.ts
|
|
3025
|
+
import chalk15 from "chalk";
|
|
3026
|
+
import * as clack from "@clack/prompts";
|
|
3027
|
+
|
|
3028
|
+
// packages/design-system/src/prompts/primitives/cancel.ts
|
|
3029
|
+
import chalk9 from "chalk";
|
|
3030
|
+
import { isCancel } from "@clack/prompts";
|
|
3031
|
+
|
|
3032
|
+
// packages/design-system/src/prompts/primitives/intro.ts
|
|
3033
|
+
import chalk10 from "chalk";
|
|
3034
|
+
|
|
3035
|
+
// packages/design-system/src/prompts/primitives/note.ts
|
|
3036
|
+
import chalk11 from "chalk";
|
|
3037
|
+
|
|
3038
|
+
// packages/design-system/src/prompts/primitives/outro.ts
|
|
3039
|
+
import chalk12 from "chalk";
|
|
3040
|
+
|
|
3041
|
+
// packages/design-system/src/prompts/primitives/spinner.ts
|
|
3042
|
+
import chalk14 from "chalk";
|
|
3043
|
+
|
|
3044
|
+
// packages/design-system/src/static/spinner.ts
|
|
3045
|
+
import chalk13 from "chalk";
|
|
3046
|
+
|
|
3047
|
+
// packages/design-system/src/static/menu.ts
|
|
3048
|
+
import chalk16 from "chalk";
|
|
3049
|
+
|
|
3050
|
+
// packages/agent-spawn/src/autonomous.ts
|
|
3051
|
+
var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
3052
|
+
|
|
3053
|
+
// packages/agent-spawn/src/acp/replay.ts
|
|
3054
|
+
import path16 from "node:path";
|
|
3055
|
+
import { homedir as homedir2 } from "node:os";
|
|
3056
|
+
import { open as open2, readdir } from "node:fs/promises";
|
|
3057
|
+
import { createInterface } from "node:readline";
|
|
3058
|
+
|
|
3059
|
+
// packages/poe-acp-client/src/acp-client.ts
|
|
3060
|
+
import { isAbsolute } from "node:path";
|
|
3061
|
+
|
|
3062
|
+
// packages/poe-acp-client/src/acp-transport.ts
|
|
3063
|
+
import {
|
|
3064
|
+
spawn as spawnChildProcess3
|
|
3065
|
+
} from "node:child_process";
|
|
3066
|
+
|
|
3067
|
+
// packages/poe-acp-client/src/run-report.ts
|
|
3068
|
+
import * as fsPromises2 from "node:fs/promises";
|
|
3069
|
+
import { homedir } from "node:os";
|
|
3070
|
+
import { join } from "node:path";
|
|
3071
|
+
|
|
3072
|
+
// packages/agent-spawn/src/acp/middlewares/spawn-log.ts
|
|
3073
|
+
import path17 from "node:path";
|
|
3074
|
+
import { homedir as homedir3 } from "node:os";
|
|
3075
|
+
import { mkdir, open as open3 } from "node:fs/promises";
|
|
3076
|
+
|
|
3077
|
+
// src/utils/command-checks.ts
|
|
3078
|
+
function formatCommandRunnerResult(result) {
|
|
3079
|
+
const stdout = result.stdout.length > 0 ? result.stdout : "<empty>";
|
|
3080
|
+
const stderr = result.stderr.length > 0 ? result.stderr : "<empty>";
|
|
3081
|
+
return `stdout:
|
|
3082
|
+
${stdout}
|
|
3083
|
+
stderr:
|
|
3084
|
+
${stderr}`;
|
|
3085
|
+
}
|
|
3086
|
+
function createSpawnHealthCheck(agentId, options) {
|
|
3087
|
+
const prompt = `Output exactly: ${options.expectedOutput}`;
|
|
3088
|
+
const { binaryName, args, env: modeEnv } = buildSpawnArgs(agentId, {
|
|
3089
|
+
prompt,
|
|
3090
|
+
model: options.model,
|
|
3091
|
+
mode: "yolo"
|
|
3092
|
+
});
|
|
2094
3093
|
return {
|
|
2095
|
-
|
|
2096
|
-
|
|
3094
|
+
id: `${agentId}-cli-health`,
|
|
3095
|
+
description: `spawn ${agentId} (expecting "${options.expectedOutput}")`,
|
|
3096
|
+
async run(context) {
|
|
3097
|
+
if (context.isDryRun) {
|
|
3098
|
+
context.logDryRun?.(
|
|
3099
|
+
`Dry run: ${[binaryName, ...args].join(" ")} (expecting "${options.expectedOutput}")`
|
|
3100
|
+
);
|
|
3101
|
+
return;
|
|
3102
|
+
}
|
|
3103
|
+
const result = modeEnv ? await context.runCommand(binaryName, args, { env: modeEnv }) : await context.runCommand(binaryName, args);
|
|
3104
|
+
if (result.exitCode !== 0) {
|
|
3105
|
+
throw new Error(
|
|
3106
|
+
`spawn ${agentId} failed with exit code ${result.exitCode}.
|
|
3107
|
+
${formatCommandRunnerResult(result)}`
|
|
3108
|
+
);
|
|
3109
|
+
}
|
|
3110
|
+
if (!result.stdout.includes(options.expectedOutput)) {
|
|
3111
|
+
throw new Error(
|
|
3112
|
+
`spawn ${agentId}: expected "${options.expectedOutput}" in stdout.
|
|
3113
|
+
${formatCommandRunnerResult(result)}`
|
|
3114
|
+
);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
2097
3117
|
};
|
|
2098
3118
|
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
3119
|
+
function createBinaryExistsCheck(binaryName, id, description) {
|
|
3120
|
+
return {
|
|
3121
|
+
id,
|
|
3122
|
+
description,
|
|
3123
|
+
async run({ runCommand: runCommand2 }) {
|
|
3124
|
+
const commonPaths = [
|
|
3125
|
+
`/usr/local/bin/${binaryName}`,
|
|
3126
|
+
`/usr/bin/${binaryName}`,
|
|
3127
|
+
`$HOME/.local/bin/${binaryName}`,
|
|
3128
|
+
`$HOME/.claude/local/bin/${binaryName}`
|
|
3129
|
+
];
|
|
3130
|
+
const detectors = [
|
|
3131
|
+
{
|
|
3132
|
+
command: "which",
|
|
3133
|
+
args: [binaryName],
|
|
3134
|
+
validate: (result) => result.exitCode === 0
|
|
3135
|
+
},
|
|
3136
|
+
{
|
|
3137
|
+
command: "where",
|
|
3138
|
+
args: [binaryName],
|
|
3139
|
+
validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
|
|
3140
|
+
},
|
|
3141
|
+
// Check common installation paths using shell expansion for $HOME
|
|
3142
|
+
{
|
|
3143
|
+
command: "sh",
|
|
3144
|
+
args: [
|
|
3145
|
+
"-c",
|
|
3146
|
+
commonPaths.map((p) => `test -f "${p}"`).join(" || ")
|
|
3147
|
+
],
|
|
3148
|
+
validate: (result) => result.exitCode === 0
|
|
3149
|
+
}
|
|
3150
|
+
];
|
|
3151
|
+
for (const detector of detectors) {
|
|
3152
|
+
const result = await runCommand2(detector.command, detector.args);
|
|
3153
|
+
if (detector.validate(result)) {
|
|
3154
|
+
return;
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
throw new Error(`${binaryName} CLI binary not found on PATH.`);
|
|
3158
|
+
}
|
|
3159
|
+
};
|
|
2121
3160
|
}
|
|
2122
3161
|
|
|
2123
|
-
// packages/config-mutations/src/template/render.ts
|
|
2124
|
-
import Mustache2 from "mustache";
|
|
2125
|
-
var originalEscape = Mustache2.escape;
|
|
2126
|
-
|
|
2127
3162
|
// src/cli/constants.ts
|
|
2128
3163
|
var CLAUDE_CODE_VARIANTS = {
|
|
2129
3164
|
haiku: "anthropic/claude-haiku-4.5",
|