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