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