poe-code 3.0.202 → 3.0.204

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/cli/commands/braintrust.d.ts +3 -0
  2. package/dist/cli/commands/braintrust.js +77 -0
  3. package/dist/cli/commands/braintrust.js.map +1 -0
  4. package/dist/cli/commands/configure.d.ts +1 -0
  5. package/dist/cli/commands/configure.js +197 -0
  6. package/dist/cli/commands/configure.js.map +1 -1
  7. package/dist/cli/commands/experiment.js +51 -7
  8. package/dist/cli/commands/experiment.js.map +1 -1
  9. package/dist/cli/commands/harness.d.ts +3 -0
  10. package/dist/cli/commands/harness.js +260 -0
  11. package/dist/cli/commands/harness.js.map +1 -0
  12. package/dist/cli/commands/pipeline.js +58 -24
  13. package/dist/cli/commands/pipeline.js.map +1 -1
  14. package/dist/cli/commands/ralph.js +19 -7
  15. package/dist/cli/commands/ralph.js.map +1 -1
  16. package/dist/cli/commands/runtime/build.d.ts +7 -0
  17. package/dist/cli/commands/runtime/build.js +128 -0
  18. package/dist/cli/commands/runtime/build.js.map +1 -0
  19. package/dist/cli/commands/runtime/index.d.ts +3 -0
  20. package/dist/cli/commands/runtime/index.js +14 -0
  21. package/dist/cli/commands/runtime/index.js.map +1 -0
  22. package/dist/cli/commands/runtime/init.d.ts +7 -0
  23. package/dist/cli/commands/runtime/init.js +39 -0
  24. package/dist/cli/commands/runtime/init.js.map +1 -0
  25. package/dist/cli/commands/runtime/jobs/attach.d.ts +3 -0
  26. package/dist/cli/commands/runtime/jobs/attach.js +35 -0
  27. package/dist/cli/commands/runtime/jobs/attach.js.map +1 -0
  28. package/dist/cli/commands/runtime/jobs/index.d.ts +3 -0
  29. package/dist/cli/commands/runtime/jobs/index.js +16 -0
  30. package/dist/cli/commands/runtime/jobs/index.js.map +1 -0
  31. package/dist/cli/commands/runtime/jobs/logs.d.ts +3 -0
  32. package/dist/cli/commands/runtime/jobs/logs.js +27 -0
  33. package/dist/cli/commands/runtime/jobs/logs.js.map +1 -0
  34. package/dist/cli/commands/runtime/jobs/ls.d.ts +3 -0
  35. package/dist/cli/commands/runtime/jobs/ls.js +60 -0
  36. package/dist/cli/commands/runtime/jobs/ls.js.map +1 -0
  37. package/dist/cli/commands/runtime/jobs/sandbox.d.ts +3 -0
  38. package/dist/cli/commands/runtime/jobs/sandbox.js +15 -0
  39. package/dist/cli/commands/runtime/jobs/sandbox.js.map +1 -0
  40. package/dist/cli/commands/runtime/jobs/shared.d.ts +22 -0
  41. package/dist/cli/commands/runtime/jobs/shared.js +124 -0
  42. package/dist/cli/commands/runtime/jobs/shared.js.map +1 -0
  43. package/dist/cli/commands/runtime/jobs/stop.d.ts +3 -0
  44. package/dist/cli/commands/runtime/jobs/stop.js +31 -0
  45. package/dist/cli/commands/runtime/jobs/stop.js.map +1 -0
  46. package/dist/cli/commands/runtime/jobs/sync.d.ts +3 -0
  47. package/dist/cli/commands/runtime/jobs/sync.js +25 -0
  48. package/dist/cli/commands/runtime/jobs/sync.js.map +1 -0
  49. package/dist/cli/commands/runtime/shared.d.ts +20 -0
  50. package/dist/cli/commands/runtime/shared.js +69 -0
  51. package/dist/cli/commands/runtime/shared.js.map +1 -0
  52. package/dist/cli/commands/runtime/templates/clear.d.ts +3 -0
  53. package/dist/cli/commands/runtime/templates/clear.js +53 -0
  54. package/dist/cli/commands/runtime/templates/clear.js.map +1 -0
  55. package/dist/cli/commands/runtime/templates/index.d.ts +3 -0
  56. package/dist/cli/commands/runtime/templates/index.js +10 -0
  57. package/dist/cli/commands/runtime/templates/index.js.map +1 -0
  58. package/dist/cli/commands/runtime/templates/ls.d.ts +3 -0
  59. package/dist/cli/commands/runtime/templates/ls.js +52 -0
  60. package/dist/cli/commands/runtime/templates/ls.js.map +1 -0
  61. package/dist/cli/commands/runtime-options.d.ts +11 -0
  62. package/dist/cli/commands/runtime-options.js +26 -0
  63. package/dist/cli/commands/runtime-options.js.map +1 -0
  64. package/dist/cli/commands/spawn.js +36 -7
  65. package/dist/cli/commands/spawn.js.map +1 -1
  66. package/dist/cli/program.js +17 -1
  67. package/dist/cli/program.js.map +1 -1
  68. package/dist/index.js +70879 -47381
  69. package/dist/index.js.map +4 -4
  70. package/dist/providers/claude-code.js +3486 -852
  71. package/dist/providers/claude-code.js.map +4 -4
  72. package/dist/providers/codex.js +3486 -852
  73. package/dist/providers/codex.js.map +4 -4
  74. package/dist/providers/goose.js +3432 -798
  75. package/dist/providers/goose.js.map +4 -4
  76. package/dist/providers/kimi.js +3486 -852
  77. package/dist/providers/kimi.js.map +4 -4
  78. package/dist/providers/opencode.js +3486 -852
  79. package/dist/providers/opencode.js.map +4 -4
  80. package/dist/providers/poe-agent.js +20641 -17147
  81. package/dist/providers/poe-agent.js.map +4 -4
  82. package/dist/providers/spawn-options.d.ts +10 -1
  83. package/dist/sdk/experiment.js +6 -0
  84. package/dist/sdk/experiment.js.map +1 -1
  85. package/dist/sdk/ralph.js +108 -11
  86. package/dist/sdk/ralph.js.map +1 -1
  87. package/dist/sdk/spawn.js +27 -4
  88. package/dist/sdk/spawn.js.map +1 -1
  89. package/dist/sdk/types.d.ts +23 -1
  90. package/dist/utils/command-checks.js +2 -29
  91. package/dist/utils/command-checks.js.map +1 -1
  92. package/package.json +12 -7
  93. package/packages/design-system/dist/components/help-formatter-plain.d.ts +4 -0
  94. package/packages/design-system/dist/components/help-formatter-plain.js +132 -0
  95. package/packages/design-system/dist/components/help-formatter.d.ts +13 -0
  96. package/packages/design-system/dist/components/help-formatter.js +116 -7
  97. package/packages/design-system/dist/components/index.d.ts +2 -2
  98. package/packages/design-system/dist/components/index.js +1 -1
  99. package/packages/design-system/dist/components/text.d.ts +1 -0
  100. package/packages/design-system/dist/components/text.js +8 -0
  101. package/packages/design-system/dist/index.d.ts +3 -2
  102. package/packages/design-system/dist/index.js +2 -1
  103. package/packages/memory/dist/index.js +3406 -387
  104. package/packages/memory/dist/index.js.map +4 -4
  105. package/packages/superintendent/dist/commands/run.d.ts +45 -0
  106. package/packages/superintendent/dist/commands/run.js +133 -38
  107. package/packages/superintendent/dist/commands/superintendent-group.d.ts +36 -0
  108. package/packages/superintendent/dist/runtime/agent-runner.d.ts +31 -0
  109. package/packages/superintendent/dist/runtime/agent-runner.js +121 -0
  110. package/packages/superintendent/dist/runtime/loop.d.ts +7 -1
  111. package/packages/superintendent/dist/runtime/loop.js +3 -11
  112. package/packages/superintendent/dist/runtime/run-builder.d.ts +1 -0
  113. package/packages/superintendent/dist/runtime/run-builder.js +3 -25
  114. package/packages/superintendent/dist/runtime/run-inspector.d.ts +1 -0
  115. package/packages/superintendent/dist/runtime/run-inspector.js +3 -25
  116. package/packages/superintendent/dist/runtime/run-owner-review.d.ts +1 -0
  117. package/packages/superintendent/dist/runtime/run-owner-review.js +3 -25
  118. package/packages/superintendent/dist/runtime/run-superintendent.d.ts +1 -0
  119. package/packages/superintendent/dist/runtime/run-superintendent.js +3 -25
@@ -52,8 +52,11 @@ var require_config_toml = __commonJS({
52
52
  }
53
53
  });
54
54
 
55
- // packages/agent-spawn/src/run-command.ts
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
+
58
+ // packages/agent-harness-tools/src/paths.ts
59
+ import path from "node:path";
57
60
 
58
61
  // packages/agent-defs/src/agents/claude-code.ts
59
62
  var claudeCodeAgent = {
@@ -188,841 +191,949 @@ for (const agent of allAgents) {
188
191
  }
189
192
  }
190
193
 
191
- // packages/agent-spawn/src/configs/mcp.ts
192
- function toJsonMcpServers(servers) {
193
- const out = {};
194
- for (const [name, server] of Object.entries(servers)) {
195
- const mapped = { command: server.command };
196
- if (server.args && server.args.length > 0) {
197
- mapped.args = server.args;
194
+ // packages/agent-harness-tools/src/select-agent.ts
195
+ var loopAgents = allAgents.filter(
196
+ (agent) => agent.binaryName !== void 0 || agent.id === "poe-agent"
197
+ );
198
+ var supportedAgents = loopAgents.map((agent) => agent.id).join(", ");
199
+
200
+ // packages/file-lock/src/lock.ts
201
+ import * as fsPromises from "node:fs/promises";
202
+ import * as os from "node:os";
203
+
204
+ // packages/agent-harness-tools/src/run-logs.ts
205
+ import path2 from "node:path";
206
+
207
+ // packages/agent-harness-tools/src/log-stream.ts
208
+ import nodeFs from "node:fs";
209
+ var JOB_DIR = "/tmp/poe-jobs";
210
+ var POLL_INTERVAL_MS = 250;
211
+ async function* streamLogFile(env, jobId, opts) {
212
+ const fs = env.fs ?? nodeFs;
213
+ const file = jobLogPath(jobId);
214
+ let byteOffset = opts.sinceByte ?? 0;
215
+ while (true) {
216
+ if (opts.since !== void 0 && !await wasModifiedSince(fs, file, opts.since)) {
217
+ await waitForLogChange(fs, file);
218
+ continue;
198
219
  }
199
- if (server.env && Object.keys(server.env).length > 0) {
200
- mapped.env = server.env;
220
+ const result = await readLogChunk(fs, file, byteOffset);
221
+ if (result !== null) {
222
+ byteOffset = result.nextByteOffset;
223
+ yield result.chunk;
224
+ continue;
201
225
  }
202
- if (server.timeout !== void 0) {
203
- mapped.timeout = server.timeout;
226
+ await waitForLogChange(fs, file);
227
+ }
228
+ }
229
+ async function wasModifiedSince(fs, file, since) {
230
+ if (fs.promises.stat === void 0) {
231
+ return true;
232
+ }
233
+ try {
234
+ const stat2 = await fs.promises.stat(file);
235
+ return stat2.mtimeMs >= since.getTime();
236
+ } catch (error2) {
237
+ if (isNodeError(error2) && error2.code === "ENOENT") {
238
+ return false;
204
239
  }
205
- out[name] = mapped;
240
+ throw error2;
206
241
  }
207
- return out;
208
242
  }
209
- function toTomlString(value) {
210
- return JSON.stringify(value);
243
+ async function waitForExit(env, jobId, opts = {}) {
244
+ const fs = env.fs ?? nodeFs;
245
+ const file = jobExitPath(jobId);
246
+ while (true) {
247
+ throwIfAborted(opts.signal);
248
+ const contents = await readTextFileIfExists(fs, file);
249
+ if (contents !== null) {
250
+ const text4 = contents.trim();
251
+ const exitCode = Number(text4);
252
+ if (text4.length === 0 || !Number.isInteger(exitCode)) {
253
+ throw new Error(`Invalid exit code in ${file}: ${contents}`);
254
+ }
255
+ return { exitCode };
256
+ }
257
+ await sleep(POLL_INTERVAL_MS, opts.signal);
258
+ }
211
259
  }
212
- function toTomlArray(values) {
213
- const serialized = values.map((value) => toTomlString(value));
214
- return `[${serialized.join(", ")}]`;
260
+ function jobLogPath(jobId) {
261
+ return `${JOB_DIR}/${jobId}.log`;
215
262
  }
216
- function toTomlInlineTable(values) {
217
- const parts = [];
218
- for (const [key, value] of Object.entries(values)) {
219
- parts.push(`${JSON.stringify(key)}=${toTomlString(value)}`);
263
+ function jobExitPath(jobId) {
264
+ return `${JOB_DIR}/${jobId}.exit`;
265
+ }
266
+ async function readLogChunk(fs, file, byteOffset) {
267
+ const contents = await readFileIfExists(fs, file);
268
+ if (contents === null || byteOffset >= contents.byteLength) {
269
+ return null;
220
270
  }
221
- return `{${parts.join(", ")}}`;
271
+ return {
272
+ chunk: {
273
+ byteOffset,
274
+ data: contents.subarray(byteOffset).toString("utf8")
275
+ },
276
+ nextByteOffset: contents.byteLength
277
+ };
222
278
  }
223
- function serializeJsonMcpArgs(servers) {
224
- return ["--mcp-config", JSON.stringify({ mcpServers: toJsonMcpServers(servers) })];
279
+ async function readTextFileIfExists(fs, file) {
280
+ const contents = await readFileIfExists(fs, file);
281
+ return contents?.toString("utf8") ?? null;
225
282
  }
226
- function serializeOpenCodeMcpEnv(servers) {
227
- const mcp = {};
228
- for (const [name, server] of Object.entries(servers)) {
229
- const entry = { type: "local", command: [server.command, ...server.args ?? []] };
230
- if (server.env && Object.keys(server.env).length > 0) {
231
- entry.environment = server.env;
283
+ async function readFileIfExists(fs, file) {
284
+ try {
285
+ const contents = await fs.promises.readFile(file);
286
+ return Buffer.isBuffer(contents) ? contents : Buffer.from(contents);
287
+ } catch (error2) {
288
+ if (isNodeError(error2) && error2.code === "ENOENT") {
289
+ return null;
232
290
  }
233
- mcp[name] = entry;
291
+ throw error2;
234
292
  }
235
- return { OPENCODE_CONFIG_CONTENT: JSON.stringify({ mcp }) };
236
293
  }
237
- function serializeCodexMcpArgs(servers) {
238
- const args = [];
239
- for (const [name, server] of Object.entries(servers)) {
240
- const prefix = `mcp_servers.${name}`;
241
- args.push("-c", `${prefix}.command=${toTomlString(server.command)}`);
242
- if (server.args && server.args.length > 0) {
243
- args.push("-c", `${prefix}.args=${toTomlArray(server.args)}`);
294
+ async function waitForLogChange(fs, file) {
295
+ const watch = fs.watch;
296
+ if (typeof watch !== "function") {
297
+ await sleep(POLL_INTERVAL_MS);
298
+ return;
299
+ }
300
+ await new Promise((resolve2) => {
301
+ let watcher = null;
302
+ const timer = setTimeout(done, POLL_INTERVAL_MS);
303
+ function done() {
304
+ clearTimeout(timer);
305
+ watcher?.close();
306
+ resolve2();
244
307
  }
245
- if (server.env && Object.keys(server.env).length > 0) {
246
- args.push("-c", `${prefix}.env=${toTomlInlineTable(server.env)}`);
308
+ try {
309
+ watcher = watch(file, done);
310
+ } catch {
311
+ done();
247
312
  }
248
- if (server.timeout !== void 0) {
249
- args.push("-c", `${prefix}.timeout=${server.timeout}`);
313
+ });
314
+ }
315
+ function sleep(ms, signal) {
316
+ return new Promise((resolve2, reject) => {
317
+ let timer = null;
318
+ const abort = () => {
319
+ if (timer !== null) {
320
+ clearTimeout(timer);
321
+ }
322
+ reject(new Error("waitForExit aborted."));
323
+ };
324
+ if (signal?.aborted) {
325
+ abort();
326
+ return;
250
327
  }
328
+ timer = setTimeout(() => {
329
+ signal?.removeEventListener("abort", abort);
330
+ resolve2();
331
+ }, ms);
332
+ signal?.addEventListener("abort", abort, { once: true });
333
+ });
334
+ }
335
+ function throwIfAborted(signal) {
336
+ if (signal?.aborted) {
337
+ throw new Error("waitForExit aborted.");
251
338
  }
252
- return args;
253
339
  }
254
- function serializeGooseMcpArgs(servers) {
255
- return Object.values(servers).flatMap((server) => [
256
- "--with-extension",
257
- [server.command, ...server.args ?? []].join(" ")
258
- ]);
340
+ function isNodeError(error2) {
341
+ return error2 instanceof Error && "code" in error2;
259
342
  }
260
343
 
261
- // packages/agent-spawn/src/configs/claude-code.ts
262
- var claudeCodeSpawnConfig = {
263
- kind: "cli",
264
- agentId: "claude-code",
265
- // ACP adapter support: yes (adapter: "claude")
266
- adapter: "claude",
267
- promptFlag: "-p",
268
- modelFlag: "--model",
269
- modelStripProviderPrefix: true,
270
- modelTransform: (model) => model.replaceAll(".", "-"),
271
- defaultArgs: [
272
- "--output-format",
273
- "stream-json",
274
- "--verbose"
275
- ],
276
- mcpArgs: serializeJsonMcpArgs,
277
- modes: {
278
- yolo: ["--dangerously-skip-permissions"],
279
- edit: ["--permission-mode", "acceptEdits", "--allowedTools", "Bash,Read,Write,Edit,Glob,Grep,NotebookEdit"],
280
- read: ["--permission-mode", "plan"]
281
- },
282
- stdinMode: {
283
- omitPrompt: true,
284
- extraArgs: ["--input-format", "text"]
285
- },
286
- interactive: {
287
- defaultArgs: []
288
- },
289
- resumeCommand: (threadId) => ["--resume", threadId]
290
- };
344
+ // packages/agent-harness-tools/src/run-poe-command.ts
345
+ import { randomBytes } from "node:crypto";
291
346
 
292
- // packages/agent-spawn/src/configs/codex.ts
293
- var codexSpawnConfig = {
294
- kind: "cli",
295
- agentId: "codex",
296
- // ACP adapter support: yes (adapter: "codex")
297
- adapter: "codex",
298
- promptFlag: "exec",
299
- modelFlag: "--model",
300
- modelStripProviderPrefix: true,
301
- defaultArgs: ["--skip-git-repo-check", "--json"],
302
- mcpArgs: serializeCodexMcpArgs,
303
- mcpArgsBeforeCommand: true,
304
- modes: {
305
- yolo: ["-s", "danger-full-access"],
306
- edit: ["-s", "workspace-write"],
307
- read: ["-s", "read-only"]
308
- },
309
- stdinMode: {
310
- omitPrompt: true,
311
- extraArgs: ["-"]
312
- },
313
- interactive: {
314
- defaultArgs: ["-a", "never"]
315
- },
316
- resumeCommand: (threadId, cwd) => ["resume", "-C", cwd, threadId]
317
- };
347
+ // packages/agent-harness-tools/src/binary-exists.ts
348
+ function createBinaryExistsDetectors(binaryName) {
349
+ const commonPaths = [
350
+ `/usr/local/bin/${binaryName}`,
351
+ `/usr/bin/${binaryName}`,
352
+ `$HOME/.local/bin/${binaryName}`,
353
+ `$HOME/.claude/local/bin/${binaryName}`
354
+ ];
355
+ return [
356
+ {
357
+ command: "which",
358
+ args: [binaryName],
359
+ validate: (result) => result.exitCode === 0
360
+ },
361
+ {
362
+ command: "where",
363
+ args: [binaryName],
364
+ validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
365
+ },
366
+ {
367
+ command: "sh",
368
+ args: ["-c", commonPaths.map((p) => `test -f "${p}"`).join(" || ")],
369
+ validate: (result) => result.exitCode === 0
370
+ }
371
+ ];
372
+ }
318
373
 
319
- // packages/agent-spawn/src/configs/opencode.ts
320
- var openCodeSpawnConfig = {
321
- kind: "cli",
322
- agentId: "opencode",
323
- // ACP adapter support: yes (adapter: "opencode").
324
- // OpenCode's `--format json` emits NDJSON events with `{ type, sessionID, part }`
325
- // (no `{ event, ... }` field), so it needs the OpenCode adapter (not "native").
326
- adapter: "opencode",
327
- promptFlag: "run",
328
- modelFlag: "--model",
329
- modelStripProviderPrefix: false,
330
- modelTransform: (model) => {
331
- return model.startsWith("poe/") ? model : `poe/${model}`;
332
- },
333
- defaultArgs: ["--format", "json"],
334
- modes: {
335
- yolo: [],
336
- edit: [],
337
- read: ["--agent", "plan"]
338
- },
339
- interactive: {
340
- defaultArgs: [],
341
- promptFlag: "--prompt"
342
- },
343
- resumeCommand: (threadId, cwd) => [cwd, "--session", threadId],
344
- mcpEnv: serializeOpenCodeMcpEnv
345
- };
346
- var openCodeAcpSpawnConfig = {
347
- kind: "acp",
348
- agentId: "opencode",
349
- acpArgs: ["acp"],
350
- skipAuth: true,
351
- mcpEnv: serializeOpenCodeMcpEnv
352
- };
374
+ // packages/agent-harness-tools/src/poe-command-execution.ts
375
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
376
+ import os3 from "node:os";
353
377
 
354
- // packages/agent-spawn/src/configs/kimi.ts
355
- var kimiSpawnConfig = {
356
- kind: "cli",
357
- agentId: "kimi",
358
- // ACP adapter support: yes (adapter: "kimi").
359
- // Kimi's `--output-format stream-json` emits OpenAI-style `{ role, content }` JSON
360
- // (no `{ event, ... }` field), so it needs the Kimi adapter (not "native").
361
- adapter: "kimi",
362
- promptFlag: "-p",
363
- modelStripProviderPrefix: true,
364
- defaultArgs: ["--print", "--output-format", "stream-json"],
365
- mcpArgs: serializeJsonMcpArgs,
366
- modes: {
367
- yolo: ["--yolo"],
368
- edit: [],
369
- read: []
370
- },
371
- stdinMode: {
372
- omitPrompt: true,
373
- extraArgs: ["--input-format", "stream-json"]
374
- },
375
- interactive: {
376
- defaultArgs: [],
377
- promptFlag: "-p"
378
- },
379
- resumeCommand: (threadId, cwd) => ["--session", threadId, "--work-dir", cwd]
380
- };
381
- var kimiAcpSpawnConfig = {
382
- kind: "acp",
383
- agentId: "kimi",
384
- acpArgs: ["acp"]
378
+ // packages/poe-code-config/src/runtime.ts
379
+ import { existsSync } from "node:fs";
380
+ import path3 from "node:path";
381
+ var defaultWorkspaceExclude = [
382
+ ".git",
383
+ "node_modules",
384
+ "dist",
385
+ ".turbo",
386
+ ".next",
387
+ ".poe-code/state.json"
388
+ ];
389
+ var runtimeConfigScope = {
390
+ scope: "runtime",
391
+ schema: {
392
+ type: {
393
+ type: "string",
394
+ default: "host",
395
+ doc: "Runtime backend: host, docker, or e2b"
396
+ },
397
+ build_args: {
398
+ type: "json",
399
+ default: {},
400
+ parse: parseBuildArgs,
401
+ doc: "Build arguments passed to the runtime image build"
402
+ },
403
+ mounts: {
404
+ type: "json",
405
+ default: [],
406
+ parse: parseMounts,
407
+ doc: "Additional runtime mounts"
408
+ },
409
+ runner: {
410
+ type: "json",
411
+ default: createDefaultRunnerScope(),
412
+ parse: parseRunner,
413
+ doc: "Runner process and workspace transfer settings"
414
+ },
415
+ link: {
416
+ type: "string",
417
+ default: "",
418
+ doc: "Informational link for the runtime definition"
419
+ },
420
+ image: {
421
+ type: "string",
422
+ default: "",
423
+ doc: "Prebuilt Docker image"
424
+ },
425
+ dockerfile: {
426
+ type: "string",
427
+ default: "",
428
+ doc: "Path to the Dockerfile used for docker or e2b builds"
429
+ },
430
+ build_context: {
431
+ type: "string",
432
+ default: "",
433
+ doc: "Path to the Docker build context"
434
+ },
435
+ workspace_dir: {
436
+ type: "string",
437
+ default: "/workspace",
438
+ doc: "Sandbox-local workspace directory for E2B runtime upload, execution, and download"
439
+ },
440
+ engine: {
441
+ type: "string",
442
+ default: "",
443
+ doc: "Container engine for Docker runtime"
444
+ },
445
+ network: {
446
+ type: "string",
447
+ default: "",
448
+ doc: "Docker network"
449
+ },
450
+ extra_args: {
451
+ type: "json",
452
+ default: void 0,
453
+ parse: parseOptionalStringArray,
454
+ doc: "Extra Docker runtime arguments"
455
+ },
456
+ template_id: {
457
+ type: "string",
458
+ default: "",
459
+ doc: "Prebuilt E2B template id"
460
+ },
461
+ from_template: {
462
+ type: "string",
463
+ default: "",
464
+ doc: "Existing E2B template alias to extend instead of using the Dockerfile FROM image"
465
+ },
466
+ cpu: {
467
+ type: "json",
468
+ default: void 0,
469
+ parse: parseOptionalNumber,
470
+ doc: "E2B CPU count"
471
+ },
472
+ memory_mb: {
473
+ type: "json",
474
+ default: void 0,
475
+ parse: parseOptionalNumber,
476
+ doc: "E2B memory in megabytes"
477
+ },
478
+ timeout_minutes: {
479
+ type: "json",
480
+ default: void 0,
481
+ parse: parseOptionalNumber,
482
+ doc: "E2B timeout in minutes"
483
+ },
484
+ preserve_after_exit_hours: {
485
+ type: "json",
486
+ default: void 0,
487
+ parse: parseOptionalNumber,
488
+ doc: "Hours to keep an E2B sandbox alive after job exit"
489
+ }
490
+ }
385
491
  };
386
-
387
- // packages/agent-spawn/src/configs/goose.ts
388
- var gooseFileSecretsEnv = { GOOSE_DISABLE_KEYRING: "1" };
389
- var gooseSpawnConfig = {
390
- kind: "cli",
391
- agentId: "goose",
392
- adapter: "native",
393
- promptFlag: "--text",
394
- modelFlag: "--model",
395
- modelStripProviderPrefix: false,
396
- defaultArgs: ["run", "--output-format", "stream-json"],
397
- defaultArgsPosition: "beforePrompt",
398
- mcpArgs: serializeGooseMcpArgs,
399
- mcpArgsPosition: "beforePrompt",
400
- modes: {
401
- yolo: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "auto" } },
402
- edit: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "smart_approve" } },
403
- read: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "chat" } }
404
- },
405
- stdinMode: {
406
- omitPrompt: true,
407
- extraArgs: ["--instructions", "-"]
408
- },
409
- interactive: {
410
- defaultArgs: ["session"],
411
- defaultArgsPosition: "beforePrompt"
412
- },
413
- resumeCommand: () => ["run", "--resume", "--text", "continue"]
414
- };
415
- var gooseAcpSpawnConfig = {
416
- kind: "acp",
417
- agentId: "goose",
418
- acpArgs: ["acp"],
419
- env: gooseFileSecretsEnv,
420
- skipAuth: true
421
- };
422
-
423
- // packages/agent-spawn/src/configs/index.ts
424
- var allSpawnConfigs = [
425
- claudeCodeSpawnConfig,
426
- codexSpawnConfig,
427
- openCodeSpawnConfig,
428
- kimiSpawnConfig,
429
- gooseSpawnConfig
430
- ];
431
- var lookup2 = /* @__PURE__ */ new Map();
432
- for (const config of allSpawnConfigs) {
433
- lookup2.set(config.agentId, config);
492
+ function parseRunner(raw) {
493
+ if (raw === void 0) {
494
+ return createDefaultRunnerScope();
495
+ }
496
+ const record = asRecord(raw);
497
+ if (record === void 0) {
498
+ throw new Error("runner: expected an object.");
499
+ }
500
+ const uploadMaxFileMb = parseOptionalNumber(record.upload_max_file_mb, "runner.upload_max_file_mb") ?? 100;
501
+ if (uploadMaxFileMb <= 0) {
502
+ throw new Error("runner.upload_max_file_mb: expected a positive finite number.");
503
+ }
504
+ return omitUndefined({
505
+ detach: parseOptionalBoolean(record.detach, "runner.detach") ?? false,
506
+ upload_max_file_mb: uploadMaxFileMb,
507
+ download_conflict: parseDownloadConflict(record.download_conflict),
508
+ sync: parseRunnerSync(record.sync),
509
+ workspace: parseRunnerWorkspace(record.workspace)
510
+ });
511
+ }
512
+ function createDefaultRunnerScope() {
513
+ return {
514
+ detach: false,
515
+ upload_max_file_mb: 100,
516
+ download_conflict: "refuse",
517
+ sync: "both",
518
+ workspace: {
519
+ exclude: [...defaultWorkspaceExclude]
520
+ }
521
+ };
522
+ }
523
+ function parseRunnerWorkspace(value) {
524
+ if (value === void 0) {
525
+ return {
526
+ exclude: [...defaultWorkspaceExclude]
527
+ };
528
+ }
529
+ const record = asRecord(value);
530
+ if (record === void 0) {
531
+ throw new Error("runner.workspace: expected an object.");
532
+ }
533
+ return {
534
+ exclude: parseOptionalStringArray(record.exclude, "runner.workspace.exclude") ?? [
535
+ ...defaultWorkspaceExclude
536
+ ]
537
+ };
538
+ }
539
+ function parseDownloadConflict(value) {
540
+ if (value === void 0) {
541
+ return "refuse";
542
+ }
543
+ if (value === "refuse" || value === "overwrite") {
544
+ return value;
545
+ }
546
+ throw new Error('runner.download_conflict: expected "refuse" or "overwrite".');
547
+ }
548
+ function parseRunnerSync(value) {
549
+ if (value === void 0) {
550
+ return "both";
551
+ }
552
+ if (value === "both" || value === "upload" || value === "none") {
553
+ return value;
554
+ }
555
+ throw new Error('runner.sync: expected "both", "upload", or "none".');
556
+ }
557
+ function parseBuildArgs(value) {
558
+ if (value === void 0) {
559
+ return {};
560
+ }
561
+ const record = asRecord(value);
562
+ if (record === void 0) {
563
+ throw new Error("build_args: expected an object.");
564
+ }
565
+ const parsed = {};
566
+ for (const [key, entry] of Object.entries(record)) {
567
+ if (typeof entry !== "string") {
568
+ throw new Error(`build_args.${key}: expected a string.`);
569
+ }
570
+ parsed[key] = entry;
571
+ }
572
+ return parsed;
573
+ }
574
+ function parseMounts(value) {
575
+ if (value === void 0) {
576
+ return [];
577
+ }
578
+ if (!Array.isArray(value)) {
579
+ throw new Error("mounts: expected an array.");
580
+ }
581
+ return value.map((entry, index) => {
582
+ const record = asRecord(entry);
583
+ if (record === void 0) {
584
+ throw new Error(`mounts[${index}]: expected an object.`);
585
+ }
586
+ const source = record.source;
587
+ const target = record.target;
588
+ if (typeof source !== "string") {
589
+ throw new Error(`mounts[${index}].source: expected a string.`);
590
+ }
591
+ if (typeof target !== "string") {
592
+ throw new Error(`mounts[${index}].target: expected a string.`);
593
+ }
594
+ return omitUndefined({
595
+ source,
596
+ target,
597
+ readonly: parseOptionalBoolean(record.readonly, `mounts[${index}].readonly`)
598
+ });
599
+ });
600
+ }
601
+ function parseOptionalStringArray(value, key = "") {
602
+ if (value === void 0) {
603
+ return void 0;
604
+ }
605
+ if (!Array.isArray(value)) {
606
+ throw new Error(`${key ? `${key}: ` : ""}expected an array.`);
607
+ }
608
+ return value.map((entry, index) => {
609
+ if (typeof entry !== "string") {
610
+ throw new Error(`${key}[${index}]: expected a string.`);
611
+ }
612
+ return entry;
613
+ });
614
+ }
615
+ function parseOptionalNumber(value, key = "") {
616
+ if (value === void 0) {
617
+ return void 0;
618
+ }
619
+ if (typeof value !== "number" || !Number.isFinite(value)) {
620
+ throw new Error(`${key ? `${key}: ` : ""}expected a finite number.`);
621
+ }
622
+ return value;
623
+ }
624
+ function parseOptionalBoolean(value, key) {
625
+ if (value === void 0) {
626
+ return void 0;
627
+ }
628
+ if (typeof value !== "boolean") {
629
+ throw new Error(`${key}: expected a boolean.`);
630
+ }
631
+ return value;
632
+ }
633
+ function asRecord(value) {
634
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
635
+ return void 0;
636
+ }
637
+ return value;
638
+ }
639
+ function omitUndefined(value) {
640
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
434
641
  }
435
- var acpLookup = /* @__PURE__ */ new Map();
436
- acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
437
- acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
438
- acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
439
-
440
- // packages/agent-spawn/src/spawn.ts
441
- import { spawn as spawnChildProcess } from "node:child_process";
442
- import { mkdirSync, openSync, writeSync, closeSync } from "node:fs";
443
- import path from "node:path";
444
642
 
445
- // packages/agent-spawn/src/spawn-interactive.ts
446
- import { spawn as spawnChildProcess2 } from "node:child_process";
643
+ // packages/poe-code-config/src/schema.ts
644
+ function defineScope(scope, schema) {
645
+ return {
646
+ scope,
647
+ schema
648
+ };
649
+ }
650
+ var integrationsConfigScope = defineScope("integrations", {
651
+ braintrust: {
652
+ type: "json",
653
+ default: {
654
+ enabled: false
655
+ },
656
+ parse: parseBraintrustIntegrationConfig,
657
+ doc: "Braintrust integration configuration"
658
+ }
659
+ });
660
+ function parseBraintrustIntegrationConfig(value) {
661
+ if (!isRecord(value)) {
662
+ throw new Error("expected an object");
663
+ }
664
+ const enabled = value.enabled === void 0 ? false : value.enabled;
665
+ if (typeof enabled !== "boolean") {
666
+ throw new Error("enabled must be a boolean");
667
+ }
668
+ return {
669
+ enabled,
670
+ ...optionalStringEntry("apiKey", value.apiKey),
671
+ ...optionalStringEntry("apiUrl", value.apiUrl),
672
+ ...optionalStringEntry("project", value.project)
673
+ };
674
+ }
675
+ function optionalStringEntry(key, value) {
676
+ if (value === void 0) {
677
+ return {};
678
+ }
679
+ if (typeof value !== "string") {
680
+ throw new Error(`${key} must be a string`);
681
+ }
682
+ return { [key]: value };
683
+ }
684
+ function isRecord(value) {
685
+ return typeof value === "object" && value !== null && !Array.isArray(value);
686
+ }
447
687
 
448
- // packages/design-system/src/tokens/colors.ts
449
- import chalk from "chalk";
450
- var dark = {
451
- header: (text4) => chalk.magentaBright.bold(text4),
452
- divider: (text4) => chalk.dim(text4),
453
- prompt: (text4) => chalk.cyan(text4),
454
- number: (text4) => chalk.cyanBright(text4),
455
- intro: (text4) => chalk.bgMagenta.white(` Poe - ${text4} `),
456
- resolvedSymbol: chalk.magenta("\u25C7"),
457
- errorSymbol: chalk.red("\u25A0"),
458
- accent: (text4) => chalk.cyan(text4),
459
- muted: (text4) => chalk.dim(text4),
460
- success: (text4) => chalk.green(text4),
461
- warning: (text4) => chalk.yellow(text4),
462
- error: (text4) => chalk.red(text4),
463
- info: (text4) => chalk.magenta(text4),
464
- badge: (text4) => chalk.bgYellow.black(` ${text4} `)
465
- };
466
- var light = {
467
- header: (text4) => chalk.hex("#a200ff").bold(text4),
468
- divider: (text4) => chalk.hex("#666666")(text4),
469
- prompt: (text4) => chalk.hex("#006699").bold(text4),
470
- number: (text4) => chalk.hex("#0077cc").bold(text4),
471
- intro: (text4) => chalk.bgHex("#a200ff").white(` Poe - ${text4} `),
472
- resolvedSymbol: chalk.hex("#a200ff")("\u25C7"),
473
- errorSymbol: chalk.hex("#cc0000")("\u25A0"),
474
- accent: (text4) => chalk.hex("#006699").bold(text4),
475
- muted: (text4) => chalk.hex("#666666")(text4),
476
- success: (text4) => chalk.hex("#008800")(text4),
477
- warning: (text4) => chalk.hex("#cc6600")(text4),
478
- error: (text4) => chalk.hex("#cc0000")(text4),
479
- info: (text4) => chalk.hex("#a200ff")(text4),
480
- badge: (text4) => chalk.bgHex("#cc6600").white(` ${text4} `)
481
- };
688
+ // packages/poe-code-config/src/plan-scope.ts
689
+ var planConfigScope = defineScope("plan", {
690
+ plan_directory: {
691
+ type: "string",
692
+ default: "docs/plans",
693
+ env: "POE_PLAN_DIRECTORY",
694
+ doc: "Directory where planning documents are stored"
695
+ }
696
+ });
482
697
 
483
- // packages/design-system/src/tokens/typography.ts
484
- import chalk2 from "chalk";
698
+ // packages/poe-code-config/src/store.ts
699
+ import path8 from "node:path";
485
700
 
486
- // packages/design-system/src/components/text.ts
487
- import chalk3 from "chalk";
701
+ // packages/config-extends/src/discover.ts
702
+ import path4 from "node:path";
703
+ async function findBase(name, bases, fs) {
704
+ const checkedPaths = [];
705
+ for (const basePath of bases) {
706
+ for (const extension of [".md", ".yaml", ".yml", ".json"]) {
707
+ const filePath = path4.join(basePath, `${name}${extension}`);
708
+ checkedPaths.push(filePath);
709
+ try {
710
+ return {
711
+ content: await fs.readFile(filePath, "utf8"),
712
+ filePath
713
+ };
714
+ } catch (error2) {
715
+ if (hasCode(error2, "ENOENT")) {
716
+ continue;
717
+ }
718
+ throw error2;
719
+ }
720
+ }
721
+ }
722
+ throw new Error(`Base "${name}" not found.
723
+ Checked paths:
724
+ - ${checkedPaths.join("\n- ")}`);
725
+ }
726
+ function hasCode(error2, code) {
727
+ return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === code;
728
+ }
488
729
 
489
- // packages/design-system/src/internal/output-format.ts
490
- import { AsyncLocalStorage } from "node:async_hooks";
491
- var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
492
- var formatStorage = new AsyncLocalStorage();
493
- var cached;
494
- function resolveOutputFormat(env = process.env) {
495
- const scoped = formatStorage.getStore();
496
- if (scoped) {
497
- return scoped;
730
+ // packages/config-extends/src/parse.ts
731
+ import path5 from "node:path";
732
+ import matter from "gray-matter";
733
+ import { parse as parseYaml } from "yaml";
734
+ function parseDocument(content, filePath) {
735
+ const normalizedContent = stripBom(content);
736
+ const format = detectFormat(normalizedContent, filePath);
737
+ const data = format === "markdown" ? parseMarkdown(normalizedContent) : toData(format === "json" ? JSON.parse(normalizedContent) : parseYaml(normalizedContent));
738
+ const hasExtendsField = Object.hasOwn(data, "extends");
739
+ const extendsValue = data.extends === true;
740
+ delete data.extends;
741
+ return {
742
+ data,
743
+ format,
744
+ extends: extendsValue,
745
+ hasExtendsField
746
+ };
747
+ }
748
+ function detectFormat(content, filePath) {
749
+ const extension = path5.extname(filePath).toLowerCase();
750
+ if (extension === ".md") {
751
+ return "markdown";
498
752
  }
499
- if (cached) {
500
- return cached;
753
+ if (extension === ".yaml" || extension === ".yml") {
754
+ return "yaml";
501
755
  }
502
- const raw = env.OUTPUT_FORMAT?.toLowerCase();
503
- cached = VALID_FORMATS.has(raw) ? raw : "terminal";
504
- return cached;
756
+ if (extension === ".json") {
757
+ return "json";
758
+ }
759
+ if (content.startsWith("{")) {
760
+ return "json";
761
+ }
762
+ if (content.startsWith("---\n") || content.startsWith("---\r\n")) {
763
+ return "markdown";
764
+ }
765
+ return "yaml";
505
766
  }
506
-
507
- // packages/design-system/src/internal/theme-detect.ts
508
- function detectThemeFromEnv(env) {
509
- const apple = env.APPLE_INTERFACE_STYLE;
510
- if (typeof apple === "string") {
511
- return apple.toLowerCase() === "dark" ? "dark" : "light";
767
+ function parseMarkdown(content) {
768
+ const document = matter(content);
769
+ return {
770
+ ...toData(document.data),
771
+ prompt: document.content
772
+ };
773
+ }
774
+ function toData(value) {
775
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
776
+ return {};
512
777
  }
513
- const vscodeKind = env.VSCODE_COLOR_THEME_KIND;
514
- if (typeof vscodeKind === "string") {
515
- const normalized = vscodeKind.toLowerCase();
516
- if (normalized.includes("light")) {
517
- return "light";
778
+ return { ...value };
779
+ }
780
+ function stripBom(content) {
781
+ if (!content.startsWith("\uFEFF")) {
782
+ return content;
783
+ }
784
+ return content.slice(1);
785
+ }
786
+
787
+ // packages/config-extends/src/merge.ts
788
+ function mergeLayers(layers) {
789
+ return mergeObjectLayers(layers, []);
790
+ }
791
+ function mergeObjectLayers(layers, path22) {
792
+ const data = {};
793
+ const sources = {};
794
+ for (const key of collectKeys(layers)) {
795
+ const resolved = resolveKey(layers, key, path22);
796
+ if (resolved === void 0) {
797
+ continue;
518
798
  }
519
- if (normalized.includes("dark")) {
520
- return "dark";
799
+ data[key] = resolved.value;
800
+ Object.assign(sources, resolved.sources);
801
+ }
802
+ return { data, sources };
803
+ }
804
+ function collectKeys(layers) {
805
+ const keys = /* @__PURE__ */ new Set();
806
+ for (const layer of layers) {
807
+ for (const key of Object.keys(layer.data)) {
808
+ keys.add(key);
521
809
  }
522
810
  }
523
- const colorFGBG = env.COLORFGBG;
524
- if (typeof colorFGBG === "string") {
525
- const parts = colorFGBG.split(";").map((part) => Number.parseInt(part, 10));
526
- const background = parts.at(-1);
527
- if (Number.isFinite(background)) {
528
- return background >= 8 ? "light" : "dark";
811
+ return [...keys];
812
+ }
813
+ function resolveKey(layers, key, path22) {
814
+ let winningSource;
815
+ let winningValue;
816
+ const objectLayers = [];
817
+ for (const layer of layers) {
818
+ const candidate = layer.data[key];
819
+ if (!isWinningCandidate(key, candidate)) {
820
+ continue;
821
+ }
822
+ if (winningSource === void 0) {
823
+ winningSource = layer.source;
824
+ winningValue = candidate;
825
+ if (isPlainObject(candidate)) {
826
+ objectLayers.push({
827
+ source: layer.source,
828
+ data: candidate
829
+ });
830
+ }
831
+ continue;
832
+ }
833
+ if (isPlainObject(winningValue) && isPlainObject(candidate)) {
834
+ objectLayers.push({
835
+ source: layer.source,
836
+ data: candidate
837
+ });
529
838
  }
530
839
  }
531
- return void 0;
840
+ if (winningSource === void 0) {
841
+ return void 0;
842
+ }
843
+ const fullPath = buildPath(path22, key);
844
+ if (isPlainObject(winningValue)) {
845
+ const merged = mergeObjectLayers(objectLayers, [...path22, key]);
846
+ return {
847
+ value: merged.data,
848
+ sources: {
849
+ [fullPath]: winningSource,
850
+ ...merged.sources
851
+ }
852
+ };
853
+ }
854
+ return {
855
+ value: cloneValue(winningValue),
856
+ sources: {
857
+ [fullPath]: winningSource
858
+ }
859
+ };
532
860
  }
533
- function resolveThemeName(env = process.env) {
534
- const raw = (env.POE_CODE_THEME ?? env.POE_THEME)?.toLowerCase();
535
- if (raw === "light" || raw === "dark") {
536
- return raw;
861
+ function isWinningCandidate(key, value) {
862
+ if (value === void 0) {
863
+ return false;
537
864
  }
538
- const detected = detectThemeFromEnv(env);
539
- if (detected) {
540
- return detected;
865
+ if (key === "prompt" && value === "") {
866
+ return false;
541
867
  }
542
- return "dark";
868
+ return true;
543
869
  }
544
- var cachedTheme;
545
- function getTheme(env) {
546
- if (cachedTheme) {
547
- return cachedTheme;
870
+ function buildPath(path22, key) {
871
+ return [...path22, key].join(".");
872
+ }
873
+ function isPlainObject(value) {
874
+ if (value === null || Array.isArray(value) || typeof value !== "object") {
875
+ return false;
548
876
  }
549
- const themeName = resolveThemeName(env);
550
- cachedTheme = themeName === "light" ? light : dark;
551
- return cachedTheme;
877
+ const prototype = Object.getPrototypeOf(value);
878
+ return prototype === Object.prototype || prototype === null;
879
+ }
880
+ function cloneValue(value) {
881
+ if (Array.isArray(value)) {
882
+ return value.map((entry) => cloneValue(entry));
883
+ }
884
+ if (!isPlainObject(value)) {
885
+ return value;
886
+ }
887
+ const clone = Object.create(Object.getPrototypeOf(value));
888
+ for (const [key, entry] of Object.entries(value)) {
889
+ clone[key] = cloneValue(entry);
890
+ }
891
+ return clone;
552
892
  }
553
893
 
554
- // packages/design-system/src/components/symbols.ts
555
- import chalk4 from "chalk";
556
- var symbols = {
557
- get info() {
558
- const format = resolveOutputFormat();
559
- if (format === "json") return "info";
560
- if (format === "markdown") return "(i)";
561
- return chalk4.magenta("\u25CF");
562
- },
563
- get success() {
564
- const format = resolveOutputFormat();
565
- if (format === "json") return "success";
566
- if (format === "markdown") return "[ok]";
567
- return chalk4.magenta("\u25C6");
568
- },
569
- get resolved() {
570
- const format = resolveOutputFormat();
571
- if (format === "json") return "resolved";
572
- if (format === "markdown") return ">";
573
- return getTheme().resolvedSymbol;
574
- },
575
- get errorResolved() {
576
- const format = resolveOutputFormat();
577
- if (format === "json") return "error";
578
- if (format === "markdown") return "[!]";
579
- return getTheme().errorSymbol;
580
- },
581
- get bar() {
582
- const format = resolveOutputFormat();
583
- if (format === "json") return "";
584
- if (format === "markdown") return "|";
585
- return "\u2502";
586
- },
587
- cornerTopRight: "\u256E",
588
- cornerBottomRight: "\u256F",
589
- get warning() {
590
- const format = resolveOutputFormat();
591
- if (format === "json") return "warning";
592
- if (format === "markdown") return "[!]";
593
- return "\u25B2";
594
- },
595
- get active() {
596
- const format = resolveOutputFormat();
597
- if (format === "json") return "active";
598
- if (format === "markdown") return "[x]";
599
- return "\u25C6";
600
- },
601
- get inactive() {
602
- const format = resolveOutputFormat();
603
- if (format === "json") return "inactive";
604
- if (format === "markdown") return "[ ]";
605
- return "\u25CB";
894
+ // packages/config-extends/src/resolve.ts
895
+ import path6 from "node:path";
896
+ var MAX_EXTENDS_DEPTH = 5;
897
+ var YIELD_TOKEN = "{{yield}}";
898
+ async function resolve(chain, options) {
899
+ const { baseLayers, documentIndex, documentLayer } = classifyChain(chain);
900
+ const parsedDocument = parseDocument(documentLayer.content, documentLayer.filePath);
901
+ const resolvedBase = shouldResolveBase(parsedDocument, options.autoExtend) ? await resolveBaseChain({
902
+ name: documentLayer.baseName ?? getBaseName(documentLayer.filePath),
903
+ baseLayers,
904
+ options,
905
+ optional: !parsedDocument.extends,
906
+ visited: /* @__PURE__ */ new Set([documentLayer.filePath]),
907
+ depth: 1
908
+ }) : void 0;
909
+ const composedPrompt = composePromptChain(
910
+ {
911
+ source: documentLayer.source,
912
+ data: parsedDocument.data
913
+ },
914
+ resolvedBase?.layers ?? []
915
+ );
916
+ const merged = mergeLayers([
917
+ ...collectDataLayers(chain.slice(0, documentIndex)),
918
+ {
919
+ source: documentLayer.source,
920
+ data: withResolvedPrompt(parsedDocument.data, composedPrompt?.prompt)
921
+ },
922
+ ...stripResolvedBasePrompts(resolvedBase?.layers ?? [], composedPrompt?.consumedBaseIndexes ?? /* @__PURE__ */ new Set()),
923
+ ...collectDataLayers(chain.slice(documentIndex + 1))
924
+ ]);
925
+ if (composedPrompt !== void 0 && merged.sources.prompt === documentLayer.source && composedPrompt.source !== void 0) {
926
+ merged.sources.prompt = composedPrompt.source;
606
927
  }
607
- };
608
-
609
- // packages/design-system/src/components/logger.ts
610
- import chalk6 from "chalk";
611
-
612
- // packages/design-system/src/prompts/primitives/log.ts
613
- import chalk5 from "chalk";
614
-
615
- // packages/design-system/src/internal/strip-ansi.ts
616
- function stripAnsi(value) {
617
- return value.replace(/\u001b\[[0-9;]*m/g, "");
928
+ return {
929
+ data: merged.data,
930
+ sources: merged.sources,
931
+ chain: [documentLayer.filePath, ...resolvedBase?.chain ?? []]
932
+ };
618
933
  }
619
-
620
- // packages/design-system/src/prompts/primitives/log.ts
621
- function writeTerminalMessage(msg, {
622
- symbol = chalk5.gray("\u2502"),
623
- secondarySymbol = chalk5.gray("\u2502"),
624
- spacing: spacing2 = 1,
625
- withGuide = true
626
- } = {}) {
627
- const lines = [];
628
- const showGuide = withGuide !== false;
629
- const contentLines = msg.split("\n");
630
- const prefix = showGuide ? `${symbol} ` : "";
631
- const continuationPrefix = showGuide ? `${secondarySymbol} ` : "";
632
- const emptyGuide = showGuide ? secondarySymbol : "";
633
- for (let index = 0; index < spacing2; index += 1) {
634
- lines.push(emptyGuide);
635
- }
636
- if (contentLines.length === 0) {
637
- process.stdout.write("\n");
638
- return;
639
- }
640
- const [firstLine = "", ...continuationLines] = contentLines;
641
- if (firstLine.length > 0) {
642
- lines.push(`${prefix}${firstLine}`);
643
- } else {
644
- lines.push(showGuide ? symbol : "");
645
- }
646
- for (const line of continuationLines) {
647
- if (line.length > 0) {
648
- lines.push(`${continuationPrefix}${line}`);
934
+ function classifyChain(chain) {
935
+ const baseLayers = [];
936
+ const documentLayers = [];
937
+ for (const [index, layer] of chain.entries()) {
938
+ if (isDataLayer(layer)) {
649
939
  continue;
650
940
  }
651
- lines.push(emptyGuide);
652
- }
653
- process.stdout.write(`${lines.join("\n")}
654
- `);
655
- }
656
- function message(msg, options) {
657
- const format = resolveOutputFormat();
658
- if (format === "markdown") {
659
- process.stdout.write(`- ${stripAnsi(msg)}
660
- `);
661
- return;
941
+ if (isDocumentLayer(layer)) {
942
+ documentLayers.push({ index, layer });
943
+ continue;
944
+ }
945
+ if (isBaseLayer(layer)) {
946
+ baseLayers.push(layer);
947
+ }
662
948
  }
663
- if (format === "json") {
664
- process.stdout.write(
665
- `${JSON.stringify({ level: "message", message: stripAnsi(msg) })}
666
- `
667
- );
668
- return;
949
+ if (documentLayers.length !== 1) {
950
+ throw new Error(`Exactly one document layer is required, received ${documentLayers.length}.`);
669
951
  }
670
- writeTerminalMessage(msg, options);
952
+ return {
953
+ baseLayers,
954
+ documentIndex: documentLayers[0].index,
955
+ documentLayer: documentLayers[0].layer
956
+ };
671
957
  }
672
- function info(msg) {
673
- const format = resolveOutputFormat();
674
- if (format === "markdown") {
675
- process.stdout.write(`- **info:** ${stripAnsi(msg)}
676
- `);
677
- return;
958
+ async function resolveBaseChain({
959
+ name,
960
+ baseLayers,
961
+ options,
962
+ optional,
963
+ visited,
964
+ depth
965
+ }) {
966
+ if (depth > MAX_EXTENDS_DEPTH) {
967
+ throw new Error(`Maximum extends depth exceeded (${MAX_EXTENDS_DEPTH}).`);
968
+ }
969
+ let discoveredBase;
970
+ try {
971
+ discoveredBase = await findBase(
972
+ name,
973
+ baseLayers.map((layer) => layer.path),
974
+ options.fs
975
+ );
976
+ } catch (error2) {
977
+ if (optional && isBaseNotFoundError(error2)) {
978
+ return void 0;
979
+ }
980
+ throw error2;
678
981
  }
679
- if (format === "json") {
680
- process.stdout.write(
681
- `${JSON.stringify({ level: "info", message: stripAnsi(msg) })}
682
- `
982
+ if (visited.has(discoveredBase.filePath)) {
983
+ if (optional) {
984
+ return void 0;
985
+ }
986
+ throw new Error(
987
+ `Circular extends detected.
988
+ Visited files:
989
+ - ${[...visited, discoveredBase.filePath].join("\n- ")}`
683
990
  );
684
- return;
685
991
  }
686
- message(msg, { symbol: symbols.info });
992
+ const matchedBaseIndex = baseLayers.findIndex(
993
+ (layer) => layer.path === path6.dirname(discoveredBase.filePath)
994
+ );
995
+ if (matchedBaseIndex === -1) {
996
+ throw new Error(`Resolved base is outside configured base paths: ${discoveredBase.filePath}`);
997
+ }
998
+ const parsedBase = parseDocument(discoveredBase.content, discoveredBase.filePath);
999
+ const nextVisited = new Set(visited);
1000
+ nextVisited.add(discoveredBase.filePath);
1001
+ const nestedBase = parsedBase.extends ? await resolveBaseChain({
1002
+ name: getBaseName(discoveredBase.filePath),
1003
+ baseLayers: baseLayers.slice(matchedBaseIndex + 1),
1004
+ options,
1005
+ optional: false,
1006
+ visited: nextVisited,
1007
+ depth: depth + 1
1008
+ }) : void 0;
1009
+ return {
1010
+ layers: [
1011
+ {
1012
+ source: baseLayers[matchedBaseIndex].source,
1013
+ data: parsedBase.data
1014
+ },
1015
+ ...nestedBase?.layers ?? []
1016
+ ],
1017
+ chain: [discoveredBase.filePath, ...nestedBase?.chain ?? []]
1018
+ };
687
1019
  }
688
- function success(msg) {
689
- const format = resolveOutputFormat();
690
- if (format === "markdown") {
691
- process.stdout.write(`- **success:** ${stripAnsi(msg)}
692
- `);
693
- return;
1020
+ function collectDataLayers(chain) {
1021
+ return chain.filter(isDataLayer);
1022
+ }
1023
+ function composePromptChain(documentLayer, baseLayers) {
1024
+ const documentPrompt = documentLayer.data.prompt;
1025
+ if (documentPrompt !== void 0 && typeof documentPrompt !== "string") {
1026
+ return void 0;
1027
+ }
1028
+ if (documentPrompt !== void 0) {
1029
+ assertValidYieldCount(documentPrompt);
1030
+ }
1031
+ let prompt = documentPrompt;
1032
+ let source = prompt === void 0 || prompt === "" ? void 0 : documentLayer.source;
1033
+ const consumedBaseIndexes = /* @__PURE__ */ new Set();
1034
+ for (const [index, layer] of baseLayers.entries()) {
1035
+ const candidate = layer.data.prompt;
1036
+ if (candidate === void 0) {
1037
+ continue;
1038
+ }
1039
+ if (typeof candidate !== "string") {
1040
+ break;
1041
+ }
1042
+ assertValidYieldCount(candidate);
1043
+ consumedBaseIndexes.add(index);
1044
+ prompt = composeAdjacentPrompts(prompt, candidate);
1045
+ if (source === void 0 && candidate !== "") {
1046
+ source = layer.source;
1047
+ }
694
1048
  }
695
- if (format === "json") {
696
- process.stdout.write(
697
- `${JSON.stringify({ level: "success", message: stripAnsi(msg) })}
698
- `
699
- );
700
- return;
1049
+ if (prompt !== void 0 && prompt.includes(YIELD_TOKEN)) {
1050
+ throw new Error('Final resolved prompt contains an unresolved "{{yield}}" token.');
701
1051
  }
702
- message(msg, { symbol: symbols.success });
1052
+ if (prompt === void 0) {
1053
+ return void 0;
1054
+ }
1055
+ return {
1056
+ consumedBaseIndexes,
1057
+ prompt,
1058
+ source
1059
+ };
703
1060
  }
704
- function warn(msg) {
705
- const format = resolveOutputFormat();
706
- if (format === "markdown") {
707
- process.stdout.write(`- **warning:** ${stripAnsi(msg)}
708
- `);
709
- return;
1061
+ function composeAdjacentPrompts(high, low) {
1062
+ if (high === void 0 || high === "") {
1063
+ return low.includes(YIELD_TOKEN) ? replaceYield(low, "") : low;
710
1064
  }
711
- if (format === "json") {
712
- process.stdout.write(
713
- `${JSON.stringify({ level: "warn", message: stripAnsi(msg) })}
714
- `
715
- );
716
- return;
1065
+ if (high.includes(YIELD_TOKEN)) {
1066
+ return replaceYield(high, low);
717
1067
  }
718
- message(msg, { symbol: chalk5.yellow("\u25B2") });
1068
+ if (low.includes(YIELD_TOKEN)) {
1069
+ return replaceYield(low, high);
1070
+ }
1071
+ return high;
719
1072
  }
720
- function error(msg) {
721
- const format = resolveOutputFormat();
722
- if (format === "markdown") {
723
- process.stdout.write(`- **error:** ${stripAnsi(msg)}
724
- `);
725
- return;
1073
+ function replaceYield(prompt, replacement) {
1074
+ return prompt.replace(YIELD_TOKEN, replacement);
1075
+ }
1076
+ function assertValidYieldCount(prompt) {
1077
+ if (countYieldTokens(prompt) > 1) {
1078
+ throw new Error('Prompt composition supports exactly one "{{yield}}" token per prompt.');
726
1079
  }
727
- if (format === "json") {
728
- process.stdout.write(
729
- `${JSON.stringify({ level: "error", message: stripAnsi(msg) })}
730
- `
731
- );
732
- return;
1080
+ }
1081
+ function countYieldTokens(prompt) {
1082
+ return prompt.split(YIELD_TOKEN).length - 1;
1083
+ }
1084
+ function withResolvedPrompt(data, prompt) {
1085
+ if (prompt === void 0) {
1086
+ return data;
733
1087
  }
734
- message(msg, { symbol: chalk5.red("\u25A0") });
1088
+ return {
1089
+ ...data,
1090
+ prompt
1091
+ };
735
1092
  }
736
- var log = {
737
- info,
738
- success,
739
- message,
740
- warn,
741
- error
742
- };
743
-
744
- // packages/design-system/src/components/logger.ts
745
- function createLogger(emitter) {
746
- const emit = (level, message2) => {
747
- if (emitter) {
748
- emitter(message2);
749
- return;
750
- }
751
- if (level === "success") {
752
- log.success(message2);
753
- return;
754
- }
755
- if (level === "warn") {
756
- log.warn(message2);
757
- return;
758
- }
759
- if (level === "error") {
760
- log.error(message2);
761
- return;
1093
+ function stripResolvedBasePrompts(layers, consumedBaseIndexes) {
1094
+ return layers.map((layer, index) => {
1095
+ if (!consumedBaseIndexes.has(index) || typeof layer.data.prompt !== "string") {
1096
+ return layer;
762
1097
  }
763
- log.info(message2);
1098
+ const { prompt: ignoredPrompt, ...data } = layer.data;
1099
+ void ignoredPrompt;
1100
+ return {
1101
+ source: layer.source,
1102
+ data
1103
+ };
1104
+ });
1105
+ }
1106
+ function getBaseName(filePath) {
1107
+ return path6.basename(filePath, path6.extname(filePath));
1108
+ }
1109
+ function shouldResolveBase(parsedDocument, autoExtend) {
1110
+ return parsedDocument.extends || autoExtend === true && !parsedDocument.hasExtendsField;
1111
+ }
1112
+ function isBaseNotFoundError(error2) {
1113
+ return error2 instanceof Error && error2.message.startsWith('Base "') && error2.message.includes('" not found.\nChecked paths:');
1114
+ }
1115
+ function isDataLayer(layer) {
1116
+ return "data" in layer;
1117
+ }
1118
+ function isDocumentLayer(layer) {
1119
+ return "filePath" in layer && "content" in layer;
1120
+ }
1121
+ function isBaseLayer(layer) {
1122
+ return "path" in layer;
1123
+ }
1124
+
1125
+ // packages/config-mutations/src/mutations/config-mutation.ts
1126
+ function merge(options) {
1127
+ return {
1128
+ kind: "configMerge",
1129
+ target: options.target,
1130
+ value: options.value,
1131
+ format: options.format,
1132
+ pruneByPrefix: options.pruneByPrefix,
1133
+ label: options.label
764
1134
  };
765
- return {
766
- info(message2) {
767
- emit("info", message2);
768
- },
769
- success(message2) {
770
- emit("success", message2);
771
- },
772
- warn(message2) {
773
- emit("warn", message2);
774
- },
775
- error(message2) {
776
- emit("error", message2);
777
- },
778
- resolved(label, value) {
779
- if (emitter) {
780
- emitter(`${label}: ${value}`);
781
- return;
782
- }
783
- log.message(`${label}
784
- ${value}`, { symbol: symbols.resolved });
785
- },
786
- errorResolved(label, value) {
787
- if (emitter) {
788
- emitter(`${label}: ${value}`);
789
- return;
790
- }
791
- log.message(`${label}
792
- ${value}`, { symbol: symbols.errorResolved });
793
- },
794
- message(message2, symbol) {
795
- if (emitter) {
796
- emitter(message2);
797
- return;
798
- }
799
- log.message(message2, { symbol: symbol ?? chalk6.gray("\u2502") });
800
- }
801
- };
802
- }
803
- var logger = createLogger();
804
-
805
- // packages/design-system/src/components/table.ts
806
- import { Table } from "console-table-printer";
807
-
808
- // packages/design-system/src/acp/components.ts
809
- import chalk7 from "chalk";
810
-
811
- // packages/design-system/src/acp/writer.ts
812
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
813
- var storage = new AsyncLocalStorage2();
814
-
815
- // packages/design-system/src/acp/components.ts
816
- var AGENT_PREFIX = `${chalk7.green.bold("\u2713")} agent: `;
817
-
818
- // packages/design-system/src/dashboard/buffer.ts
819
- import chalk8 from "chalk";
820
-
821
- // packages/design-system/src/dashboard/terminal.ts
822
- import readline from "node:readline";
823
- import { PassThrough } from "node:stream";
824
-
825
- // packages/design-system/src/prompts/index.ts
826
- import chalk15 from "chalk";
827
- import * as clack from "@clack/prompts";
828
-
829
- // packages/design-system/src/prompts/primitives/cancel.ts
830
- import chalk9 from "chalk";
831
- import { isCancel } from "@clack/prompts";
832
-
833
- // packages/design-system/src/prompts/primitives/intro.ts
834
- import chalk10 from "chalk";
835
-
836
- // packages/design-system/src/prompts/primitives/note.ts
837
- import chalk11 from "chalk";
838
-
839
- // packages/design-system/src/prompts/primitives/outro.ts
840
- import chalk12 from "chalk";
841
-
842
- // packages/design-system/src/prompts/primitives/spinner.ts
843
- import chalk14 from "chalk";
844
-
845
- // packages/design-system/src/static/spinner.ts
846
- import chalk13 from "chalk";
847
-
848
- // packages/design-system/src/static/menu.ts
849
- import chalk16 from "chalk";
850
-
851
- // packages/agent-spawn/src/autonomous.ts
852
- var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
853
-
854
- // packages/agent-spawn/src/acp/replay.ts
855
- import path2 from "node:path";
856
- import { homedir as homedir2 } from "node:os";
857
- import { open, readdir } from "node:fs/promises";
858
- import { createInterface } from "node:readline";
859
-
860
- // packages/poe-acp-client/src/acp-client.ts
861
- import { isAbsolute } from "node:path";
862
-
863
- // packages/poe-acp-client/src/acp-transport.ts
864
- import {
865
- spawn as spawnChildProcess3
866
- } from "node:child_process";
867
-
868
- // packages/poe-acp-client/src/run-report.ts
869
- import * as fsPromises from "node:fs/promises";
870
- import { homedir } from "node:os";
871
- import { join } from "node:path";
872
-
873
- // packages/agent-spawn/src/acp/spawn.ts
874
- import { spawn as spawnChildProcess4 } from "node:child_process";
875
-
876
- // packages/agent-spawn/src/acp/middlewares/spawn-log.ts
877
- import path3 from "node:path";
878
- import { homedir as homedir3 } from "node:os";
879
- import { mkdir, open as open2 } from "node:fs/promises";
880
-
881
- // src/utils/command-checks.ts
882
- function formatCommandRunnerResult(result) {
883
- const stdout = result.stdout.length > 0 ? result.stdout : "<empty>";
884
- const stderr = result.stderr.length > 0 ? result.stderr : "<empty>";
885
- return `stdout:
886
- ${stdout}
887
- stderr:
888
- ${stderr}`;
889
- }
890
- function describeCommandExpectation(command, args, expectedOutput) {
891
- return `${renderCommandLine(command, args)} (expecting "${expectedOutput}")`;
892
- }
893
- function createCommandExpectationCheck(options) {
894
- return {
895
- id: options.id,
896
- description: describeCommandExpectation(
897
- options.command,
898
- options.args,
899
- options.expectedOutput
900
- ),
901
- async run(context) {
902
- await runAndMatchOutput(context, options);
903
- }
904
- };
905
- }
906
- async function runAndMatchOutput(context, options) {
907
- const rendered = renderCommandLine(options.command, options.args);
908
- if (options.skipOnDryRun !== false && context.isDryRun) {
909
- if (context.logDryRun) {
910
- context.logDryRun(
911
- `Dry run: ${rendered} (expecting "${options.expectedOutput}")`
912
- );
913
- }
914
- return;
915
- }
916
- const result = options.commandOptions ? await context.runCommand(options.command, options.args, options.commandOptions) : await context.runCommand(options.command, options.args);
917
- if (result.exitCode !== 0) {
918
- const detail = formatCommandRunnerResult(result);
919
- throw new Error(
920
- [`Command ${rendered} failed with exit code ${result.exitCode}.`, detail].join("\n")
921
- );
922
- }
923
- if (!stdoutMatchesExpected(result.stdout, options.expectedOutput)) {
924
- const detail = formatCommandRunnerResult(result);
925
- const received = result.stdout.trim();
926
- throw new Error(
927
- [
928
- `Command ${rendered} failed: expected "${options.expectedOutput}" but received "${received}".`,
929
- detail
930
- ].join("\n")
931
- );
932
- }
933
- }
934
- function stdoutMatchesExpected(stdout, expected) {
935
- const trimmed = stdout.trim();
936
- if (trimmed === expected) {
937
- return true;
938
- }
939
- const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
940
- if (lines.some((line) => line === expected)) {
941
- return true;
942
- }
943
- for (const line of lines) {
944
- if (line[0] !== "{") continue;
945
- try {
946
- const parsed = JSON.parse(line);
947
- if (parsed.type === "result" && parsed.result === expected) {
948
- return true;
949
- }
950
- } catch {
951
- continue;
952
- }
953
- }
954
- return false;
955
- }
956
- function renderCommandLine(command, args) {
957
- return [command, ...args].map(quoteIfNeeded).join(" ").trim();
958
- }
959
- function quoteIfNeeded(value) {
960
- if (value.length === 0) {
961
- return '""';
962
- }
963
- if (needsQuoting(value)) {
964
- return `"${value.replaceAll('"', '\\"')}"`;
965
- }
966
- return value;
967
- }
968
- function needsQuoting(value) {
969
- return value.includes(" ") || value.includes(" ") || value.includes("\n");
970
- }
971
- function createBinaryExistsCheck(binaryName, id, description) {
972
- return {
973
- id,
974
- description,
975
- async run({ runCommand: runCommand2 }) {
976
- const commonPaths = [
977
- `/usr/local/bin/${binaryName}`,
978
- `/usr/bin/${binaryName}`,
979
- `$HOME/.local/bin/${binaryName}`,
980
- `$HOME/.claude/local/bin/${binaryName}`
981
- ];
982
- const detectors = [
983
- {
984
- command: "which",
985
- args: [binaryName],
986
- validate: (result) => result.exitCode === 0
987
- },
988
- {
989
- command: "where",
990
- args: [binaryName],
991
- validate: (result) => result.exitCode === 0 && result.stdout.trim().length > 0
992
- },
993
- // Check common installation paths using shell expansion for $HOME
994
- {
995
- command: "sh",
996
- args: [
997
- "-c",
998
- commonPaths.map((p) => `test -f "${p}"`).join(" || ")
999
- ],
1000
- validate: (result) => result.exitCode === 0
1001
- }
1002
- ];
1003
- for (const detector of detectors) {
1004
- const result = await runCommand2(detector.command, detector.args);
1005
- if (detector.validate(result)) {
1006
- return;
1007
- }
1008
- }
1009
- throw new Error(`${binaryName} CLI binary not found on PATH.`);
1010
- }
1011
- };
1012
- }
1013
-
1014
- // packages/config-mutations/src/mutations/config-mutation.ts
1015
- function merge(options) {
1016
- return {
1017
- kind: "configMerge",
1018
- target: options.target,
1019
- value: options.value,
1020
- format: options.format,
1021
- pruneByPrefix: options.pruneByPrefix,
1022
- label: options.label
1023
- };
1024
- }
1025
- function prune(options) {
1135
+ }
1136
+ function prune(options) {
1026
1137
  return {
1027
1138
  kind: "configPrune",
1028
1139
  target: options.target,
@@ -1103,7 +1214,7 @@ import * as jsonc from "jsonc-parser";
1103
1214
  function isConfigObject(value) {
1104
1215
  return typeof value === "object" && value !== null && !Array.isArray(value);
1105
1216
  }
1106
- function parse3(content) {
1217
+ function parse2(content) {
1107
1218
  if (!content || content.trim() === "") {
1108
1219
  return {};
1109
1220
  }
@@ -1176,7 +1287,7 @@ function prune2(obj, shape) {
1176
1287
  return { changed, result };
1177
1288
  }
1178
1289
  var jsonFormat = {
1179
- parse: parse3,
1290
+ parse: parse2,
1180
1291
  serialize,
1181
1292
  merge: merge2,
1182
1293
  prune: prune2
@@ -1187,7 +1298,7 @@ import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
1187
1298
  function isConfigObject2(value) {
1188
1299
  return typeof value === "object" && value !== null && !Array.isArray(value);
1189
1300
  }
1190
- function parse4(content) {
1301
+ function parse3(content) {
1191
1302
  if (!content || content.trim() === "") {
1192
1303
  return {};
1193
1304
  }
@@ -1251,22 +1362,22 @@ function prune3(obj, shape) {
1251
1362
  return { changed, result };
1252
1363
  }
1253
1364
  var tomlFormat = {
1254
- parse: parse4,
1365
+ parse: parse3,
1255
1366
  serialize: serialize2,
1256
1367
  merge: merge3,
1257
1368
  prune: prune3
1258
1369
  };
1259
1370
 
1260
1371
  // packages/config-mutations/src/formats/yaml.ts
1261
- import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
1372
+ import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
1262
1373
  function isConfigObject3(value) {
1263
1374
  return typeof value === "object" && value !== null && !Array.isArray(value);
1264
1375
  }
1265
- function parse5(content) {
1376
+ function parse4(content) {
1266
1377
  if (!content || content.trim() === "") {
1267
1378
  return {};
1268
1379
  }
1269
- const parsed = parseYaml(content);
1380
+ const parsed = parseYaml2(content);
1270
1381
  if (parsed === null || parsed === void 0) {
1271
1382
  return {};
1272
1383
  }
@@ -1326,7 +1437,7 @@ function prune4(obj, shape) {
1326
1437
  return { changed, result };
1327
1438
  }
1328
1439
  var yamlFormat = {
1329
- parse: parse5,
1440
+ parse: parse4,
1330
1441
  serialize: serialize3,
1331
1442
  merge: merge4,
1332
1443
  prune: prune4
@@ -1357,20 +1468,20 @@ function getConfigFormat(pathOrFormat) {
1357
1468
  }
1358
1469
  return formatRegistry[formatName];
1359
1470
  }
1360
- function detectFormat(path5) {
1361
- const ext = getExtension(path5);
1471
+ function detectFormat2(path22) {
1472
+ const ext = getExtension(path22);
1362
1473
  return extensionMap[ext];
1363
1474
  }
1364
- function getExtension(path5) {
1365
- const lastDot = path5.lastIndexOf(".");
1475
+ function getExtension(path22) {
1476
+ const lastDot = path22.lastIndexOf(".");
1366
1477
  if (lastDot === -1) {
1367
1478
  return "";
1368
1479
  }
1369
- return path5.slice(lastDot).toLowerCase();
1480
+ return path22.slice(lastDot).toLowerCase();
1370
1481
  }
1371
1482
 
1372
1483
  // packages/config-mutations/src/execution/path-utils.ts
1373
- import path4 from "node:path";
1484
+ import path7 from "node:path";
1374
1485
  function expandHome(targetPath, homeDir) {
1375
1486
  if (!targetPath?.startsWith("~")) {
1376
1487
  return targetPath;
@@ -1387,7 +1498,7 @@ function expandHome(targetPath, homeDir) {
1387
1498
  remainder = remainder.slice(1);
1388
1499
  }
1389
1500
  }
1390
- return remainder.length === 0 ? homeDir : path4.join(homeDir, remainder);
1501
+ return remainder.length === 0 ? homeDir : path7.join(homeDir, remainder);
1391
1502
  }
1392
1503
  function validateHomePath(targetPath) {
1393
1504
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -1405,19 +1516,19 @@ function resolvePath(rawPath, homeDir, pathMapper) {
1405
1516
  if (!pathMapper) {
1406
1517
  return expanded;
1407
1518
  }
1408
- const rawDirectory = path4.dirname(expanded);
1519
+ const rawDirectory = path7.dirname(expanded);
1409
1520
  const mappedDirectory = pathMapper.mapTargetDirectory({
1410
1521
  targetDirectory: rawDirectory
1411
1522
  });
1412
- const filename = path4.basename(expanded);
1413
- return filename.length === 0 ? mappedDirectory : path4.join(mappedDirectory, filename);
1523
+ const filename = path7.basename(expanded);
1524
+ return filename.length === 0 ? mappedDirectory : path7.join(mappedDirectory, filename);
1414
1525
  }
1415
1526
 
1416
1527
  // packages/config-mutations/src/fs-utils.ts
1417
1528
  function isNotFound(error2) {
1418
1529
  return typeof error2 === "object" && error2 !== null && "code" in error2 && error2.code === "ENOENT";
1419
1530
  }
1420
- async function readFileIfExists(fs, target) {
1531
+ async function readFileIfExists2(fs, target) {
1421
1532
  try {
1422
1533
  return await fs.readFile(target, "utf8");
1423
1534
  } catch (error2) {
@@ -1668,8 +1779,8 @@ async function applyChmod(mutation, context, options) {
1668
1779
  };
1669
1780
  }
1670
1781
  try {
1671
- const stat = await context.fs.stat(targetPath);
1672
- const currentMode = typeof stat.mode === "number" ? stat.mode & 511 : null;
1782
+ const stat2 = await context.fs.stat(targetPath);
1783
+ const currentMode = typeof stat2.mode === "number" ? stat2.mode & 511 : null;
1673
1784
  if (currentMode === mutation.mode) {
1674
1785
  return {
1675
1786
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -1701,7 +1812,7 @@ async function applyBackup(mutation, context, options) {
1701
1812
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
1702
1813
  targetPath
1703
1814
  };
1704
- const content = await readFileIfExists(context.fs, targetPath);
1815
+ const content = await readFileIfExists2(context.fs, targetPath);
1705
1816
  if (content === null) {
1706
1817
  return {
1707
1818
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -1725,14 +1836,14 @@ async function applyConfigMerge(mutation, context, options) {
1725
1836
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
1726
1837
  targetPath
1727
1838
  };
1728
- const formatName = mutation.format ?? detectFormat(rawPath);
1839
+ const formatName = mutation.format ?? detectFormat2(rawPath);
1729
1840
  if (!formatName) {
1730
1841
  throw new Error(
1731
1842
  `Cannot detect config format for "${rawPath}". Provide explicit format option.`
1732
1843
  );
1733
1844
  }
1734
1845
  const format = getConfigFormat(formatName);
1735
- const rawContent = await readFileIfExists(context.fs, targetPath);
1846
+ const rawContent = await readFileIfExists2(context.fs, targetPath);
1736
1847
  let current;
1737
1848
  try {
1738
1849
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -1771,14 +1882,14 @@ async function applyConfigPrune(mutation, context, options) {
1771
1882
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
1772
1883
  targetPath
1773
1884
  };
1774
- const rawContent = await readFileIfExists(context.fs, targetPath);
1885
+ const rawContent = await readFileIfExists2(context.fs, targetPath);
1775
1886
  if (rawContent === null) {
1776
1887
  return {
1777
1888
  outcome: { changed: false, effect: "none", detail: "noop" },
1778
1889
  details
1779
1890
  };
1780
1891
  }
1781
- const formatName = mutation.format ?? detectFormat(rawPath);
1892
+ const formatName = mutation.format ?? detectFormat2(rawPath);
1782
1893
  if (!formatName) {
1783
1894
  throw new Error(
1784
1895
  `Cannot detect config format for "${rawPath}". Provide explicit format option.`
@@ -1834,14 +1945,14 @@ async function applyConfigTransform(mutation, context, options) {
1834
1945
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
1835
1946
  targetPath
1836
1947
  };
1837
- const formatName = mutation.format ?? detectFormat(rawPath);
1948
+ const formatName = mutation.format ?? detectFormat2(rawPath);
1838
1949
  if (!formatName) {
1839
1950
  throw new Error(
1840
1951
  `Cannot detect config format for "${rawPath}". Provide explicit format option.`
1841
1952
  );
1842
1953
  }
1843
1954
  const format = getConfigFormat(formatName);
1844
- const rawContent = await readFileIfExists(context.fs, targetPath);
1955
+ const rawContent = await readFileIfExists2(context.fs, targetPath);
1845
1956
  let current;
1846
1957
  try {
1847
1958
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -1941,7 +2052,7 @@ async function applyTemplateMerge(mutation, context, options, formatName) {
1941
2052
  { cause: error2 }
1942
2053
  );
1943
2054
  }
1944
- const rawContent = await readFileIfExists(context.fs, targetPath);
2055
+ const rawContent = await readFileIfExists2(context.fs, targetPath);
1945
2056
  let current;
1946
2057
  try {
1947
2058
  current = rawContent === null ? {} : format.parse(rawContent);
@@ -2016,6 +2127,2529 @@ async function executeMutation(mutation, context, options) {
2016
2127
  import Mustache2 from "mustache";
2017
2128
  var originalEscape = Mustache2.escape;
2018
2129
 
2130
+ // packages/poe-code-config/src/store.ts
2131
+ async function readMergedDocument(fs, globalPath, projectPath) {
2132
+ const globalDocument = await readStoredDocument(fs, globalPath);
2133
+ if (!projectPath || projectPath === globalPath) {
2134
+ return globalDocument.data;
2135
+ }
2136
+ const projectDocument = await readStoredDocument(fs, projectPath);
2137
+ const resolved = await resolve(
2138
+ [
2139
+ {
2140
+ source: "project",
2141
+ filePath: projectPath,
2142
+ content: projectDocument.content
2143
+ },
2144
+ {
2145
+ source: "base",
2146
+ path: path8.dirname(globalPath)
2147
+ }
2148
+ ],
2149
+ {
2150
+ fs: createResolvedConfigFs(fs, globalPath, globalDocument.content),
2151
+ autoExtend: true
2152
+ }
2153
+ );
2154
+ return normalizeDocument(resolved.data);
2155
+ }
2156
+ async function readStoredDocument(fs, filePath) {
2157
+ try {
2158
+ const raw = await fs.readFile(filePath, "utf8");
2159
+ return await parseStoredDocument(fs, filePath, raw);
2160
+ } catch (error2) {
2161
+ if (isNotFound(error2)) {
2162
+ return {
2163
+ content: EMPTY_DOCUMENT,
2164
+ data: {}
2165
+ };
2166
+ }
2167
+ throw error2;
2168
+ }
2169
+ }
2170
+ async function parseStoredDocument(fs, filePath, raw) {
2171
+ try {
2172
+ return {
2173
+ content: raw,
2174
+ data: normalizeDocument(JSON.parse(raw))
2175
+ };
2176
+ } catch (error2) {
2177
+ if (error2 instanceof SyntaxError) {
2178
+ await recoverInvalidDocument(fs, filePath, raw);
2179
+ return {
2180
+ content: EMPTY_DOCUMENT,
2181
+ data: {}
2182
+ };
2183
+ }
2184
+ throw error2;
2185
+ }
2186
+ }
2187
+ function normalizeDocument(value) {
2188
+ if (!isRecord2(value)) {
2189
+ return {};
2190
+ }
2191
+ const document = {};
2192
+ for (const [scope, scopeValues] of Object.entries(value)) {
2193
+ const normalizedValues = normalizeScopeValues(scopeValues);
2194
+ if (Object.keys(normalizedValues).length > 0) {
2195
+ document[scope] = normalizedValues;
2196
+ }
2197
+ }
2198
+ return document;
2199
+ }
2200
+ function normalizeScopeValues(value) {
2201
+ if (!isRecord2(value)) {
2202
+ return {};
2203
+ }
2204
+ const normalized = {};
2205
+ for (const [key, entry] of Object.entries(value)) {
2206
+ if (entry !== void 0) {
2207
+ normalized[key] = entry;
2208
+ }
2209
+ }
2210
+ return normalized;
2211
+ }
2212
+ function createResolvedConfigFs(fs, globalPath, globalContent) {
2213
+ return {
2214
+ readFile(filePath, _encoding) {
2215
+ if (filePath === globalPath) {
2216
+ return Promise.resolve(globalContent);
2217
+ }
2218
+ return fs.readFile(filePath, "utf8");
2219
+ }
2220
+ };
2221
+ }
2222
+ async function recoverInvalidDocument(fs, filePath, content) {
2223
+ await fs.mkdir(path8.dirname(filePath), { recursive: true });
2224
+ const backupPath = createInvalidBackupPath(filePath);
2225
+ await fs.writeFile(backupPath, content, { encoding: "utf8" });
2226
+ await fs.writeFile(filePath, EMPTY_DOCUMENT, { encoding: "utf8" });
2227
+ }
2228
+ function createInvalidBackupPath(filePath) {
2229
+ const directory = path8.dirname(filePath);
2230
+ const baseName = path8.basename(filePath);
2231
+ return path8.join(directory, `${baseName}.invalid-${createTimestamp()}.json`);
2232
+ }
2233
+ function isRecord2(value) {
2234
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
2235
+ }
2236
+ function resolveConfigPath(homeDir) {
2237
+ return path8.join(homeDir, ".poe-code", "config.json");
2238
+ }
2239
+ function resolveProjectConfigPath(cwd) {
2240
+ return path8.join(cwd, ".poe-code", "config.json");
2241
+ }
2242
+ var EMPTY_DOCUMENT = `${JSON.stringify({}, null, 2)}
2243
+ `;
2244
+
2245
+ // packages/poe-code-config/src/resolve.ts
2246
+ function resolveScope(schema, fileValues, env = {}) {
2247
+ const resolved = {};
2248
+ for (const key of Object.keys(schema)) {
2249
+ const field = schema[key];
2250
+ const envValue = resolveEnvValue(field, env, key);
2251
+ const fileValue = resolveFileValue(field, fileValues?.[key], key);
2252
+ resolved[key] = envValue ?? fileValue ?? field.default;
2253
+ }
2254
+ return resolved;
2255
+ }
2256
+ function resolveEnvValue(field, env, key) {
2257
+ if (!field.env) {
2258
+ return void 0;
2259
+ }
2260
+ const raw = env[field.env];
2261
+ if (raw === void 0) {
2262
+ return void 0;
2263
+ }
2264
+ return coerceValue(field, raw, key);
2265
+ }
2266
+ function resolveFileValue(field, value, key) {
2267
+ return coerceValue(field, value, key);
2268
+ }
2269
+ function coerceValue(field, value, key) {
2270
+ switch (field.type) {
2271
+ case "string":
2272
+ return typeof value === "string" ? value : void 0;
2273
+ case "number":
2274
+ return coerceNumber(value);
2275
+ case "boolean":
2276
+ return coerceBoolean(value);
2277
+ case "json":
2278
+ return coerceJson(field, value, key);
2279
+ }
2280
+ }
2281
+ function coerceNumber(value) {
2282
+ if (typeof value === "number" && Number.isFinite(value)) {
2283
+ return value;
2284
+ }
2285
+ if (typeof value !== "string" || value.length === 0) {
2286
+ return void 0;
2287
+ }
2288
+ const parsed = Number(value);
2289
+ return Number.isNaN(parsed) ? void 0 : parsed;
2290
+ }
2291
+ function coerceBoolean(value) {
2292
+ if (typeof value === "boolean") {
2293
+ return value;
2294
+ }
2295
+ if (value === "true" || value === "1") {
2296
+ return true;
2297
+ }
2298
+ if (value === "false" || value === "0") {
2299
+ return false;
2300
+ }
2301
+ return void 0;
2302
+ }
2303
+ function coerceJson(field, value, key) {
2304
+ if (value === void 0) {
2305
+ return void 0;
2306
+ }
2307
+ const parsedValue = parseJsonValue(value, key);
2308
+ try {
2309
+ return field.parse(parsedValue);
2310
+ } catch (error2) {
2311
+ const message2 = error2 instanceof Error ? error2.message : "Invalid JSON value.";
2312
+ throw new Error(`Invalid config value for "${key}": ${message2}`);
2313
+ }
2314
+ }
2315
+ function parseJsonValue(value, key) {
2316
+ if (typeof value !== "string") {
2317
+ return value;
2318
+ }
2319
+ try {
2320
+ return JSON.parse(value);
2321
+ } catch {
2322
+ throw new Error(`Invalid config value for "${key}": expected valid JSON.`);
2323
+ }
2324
+ }
2325
+
2326
+ // packages/poe-code-config/src/inspect.ts
2327
+ import path9 from "node:path";
2328
+ var EMPTY_DOCUMENT2 = `${JSON.stringify({}, null, 2)}
2329
+ `;
2330
+
2331
+ // packages/poe-code-config/src/state/index.ts
2332
+ import os2 from "node:os";
2333
+
2334
+ // packages/poe-code-config/src/state/jobs.ts
2335
+ import path10 from "node:path";
2336
+
2337
+ // packages/poe-code-config/src/state/fs.ts
2338
+ import * as nodeFs2 from "node:fs/promises";
2339
+
2340
+ // packages/poe-code-config/src/state/templates.ts
2341
+ import path11 from "node:path";
2342
+
2343
+ // packages/agent-harness-tools/src/execution-env.ts
2344
+ var executionEnvFactories = /* @__PURE__ */ new Map();
2345
+ function registerExecutionEnvFactory(factory) {
2346
+ executionEnvFactories.set(factory.type, factory);
2347
+ }
2348
+
2349
+ // packages/agent-harness-tools/src/workspace-transfer.ts
2350
+ import { createHash } from "node:crypto";
2351
+ import { promises as nodeFs3 } from "node:fs";
2352
+ import path12 from "node:path";
2353
+
2354
+ // packages/process-runner/src/docker/context.ts
2355
+ import { execSync } from "node:child_process";
2356
+ function detectContext() {
2357
+ try {
2358
+ const output = execSync("colima list --json", {
2359
+ encoding: "utf-8",
2360
+ stdio: ["pipe", "pipe", "ignore"]
2361
+ });
2362
+ const lines = output.trim().split("\n").filter(Boolean);
2363
+ for (const line of lines) {
2364
+ const profile = JSON.parse(line);
2365
+ if (profile.status === "Running" && profile.runtime === "docker") {
2366
+ const name = profile.name ?? profile.profile;
2367
+ if (!name) {
2368
+ continue;
2369
+ }
2370
+ return name === "default" ? "colima" : `colima-${name}`;
2371
+ }
2372
+ }
2373
+ } catch {
2374
+ return null;
2375
+ }
2376
+ return null;
2377
+ }
2378
+ function buildContextArgs(engine, context) {
2379
+ if (engine === "docker" && context) {
2380
+ return ["--context", context];
2381
+ }
2382
+ return [];
2383
+ }
2384
+
2385
+ // packages/process-runner/src/docker/engine.ts
2386
+ import { execSync as execSync2 } from "node:child_process";
2387
+ function detectEngine() {
2388
+ if (isEngineAvailable("docker")) {
2389
+ return "docker";
2390
+ }
2391
+ if (isEngineAvailable("podman")) {
2392
+ return "podman";
2393
+ }
2394
+ throw new Error(
2395
+ "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"
2396
+ );
2397
+ }
2398
+ function isEngineAvailable(engine) {
2399
+ try {
2400
+ execSync2(`${engine} --version`, {
2401
+ stdio: "ignore"
2402
+ });
2403
+ return true;
2404
+ } catch {
2405
+ return false;
2406
+ }
2407
+ }
2408
+
2409
+ // packages/process-runner/src/docker/docker-runner.ts
2410
+ import * as childProcess from "node:child_process";
2411
+ import { randomBytes as randomBytes2 } from "node:crypto";
2412
+
2413
+ // packages/process-runner/src/docker/args.ts
2414
+ import path13 from "node:path";
2415
+ function buildDockerRunArgs(input) {
2416
+ const args = [input.engine];
2417
+ if (input.engine === "docker" && input.context) {
2418
+ args.push("--context", input.context);
2419
+ }
2420
+ args.push("run");
2421
+ if (input.rm) {
2422
+ args.push("--rm");
2423
+ }
2424
+ if (input.detached) {
2425
+ args.push("-d");
2426
+ }
2427
+ if (input.interactive) {
2428
+ args.push("-i");
2429
+ }
2430
+ if (input.tty) {
2431
+ args.push("-t");
2432
+ }
2433
+ args.push("--name", input.containerName);
2434
+ if (input.cwd !== void 0) {
2435
+ args.push("-w", input.cwd);
2436
+ }
2437
+ for (const [key, value] of Object.entries(input.env ?? {})) {
2438
+ args.push("-e", `${key}=${value}`);
2439
+ }
2440
+ for (const mount of input.mounts) {
2441
+ const volume = `${path13.resolve(mount.source)}:${mount.target}${mount.readonly ? ":ro" : ""}`;
2442
+ args.push("-v", volume);
2443
+ }
2444
+ for (const port of input.ports) {
2445
+ const mapping = `${port.host}:${port.container}${port.protocol === void 0 || port.protocol === "tcp" ? "" : `/${port.protocol}`}`;
2446
+ args.push("-p", mapping);
2447
+ }
2448
+ if (input.network !== void 0) {
2449
+ args.push("--network", input.network);
2450
+ }
2451
+ args.push(...input.extraArgs, input.image, input.command, ...input.args);
2452
+ return args;
2453
+ }
2454
+
2455
+ // packages/process-runner/src/docker/docker-execution-env.ts
2456
+ import { createHash as createHash2, randomBytes as randomBytes3 } from "node:crypto";
2457
+ import { mkdtempSync, rmSync } from "node:fs";
2458
+ import { readFile as readFile2 } from "node:fs/promises";
2459
+ import { tmpdir } from "node:os";
2460
+ import path14 from "node:path";
2461
+
2462
+ // packages/process-runner/src/host/host-runner.ts
2463
+ import { spawn as spawnChildProcess } from "node:child_process";
2464
+ function createHostRunner(options = {}) {
2465
+ const detached = options.detached === true;
2466
+ return {
2467
+ name: "host",
2468
+ exec(spec) {
2469
+ const stdinMode = spec.stdin ?? "ignore";
2470
+ const stdoutMode = spec.stdout ?? "pipe";
2471
+ const stderrMode = spec.stderr ?? "pipe";
2472
+ const stdio = stdinMode === "inherit" && stdoutMode === "inherit" && stderrMode === "inherit" ? "inherit" : [stdinMode, stdoutMode, stderrMode];
2473
+ const child = spawnChildProcess(spec.command, spec.args ?? [], {
2474
+ cwd: spec.cwd,
2475
+ env: spec.env,
2476
+ stdio,
2477
+ ...detached ? { detached: true } : {}
2478
+ });
2479
+ if (detached) {
2480
+ child.unref();
2481
+ }
2482
+ const kill = (signal) => {
2483
+ if (detached && process.platform !== "win32" && child.pid !== void 0) {
2484
+ process.kill(-child.pid, signal);
2485
+ return;
2486
+ }
2487
+ child.kill(signal);
2488
+ };
2489
+ let settled = false;
2490
+ let resolveResult = null;
2491
+ const result = new Promise((resolve2) => {
2492
+ resolveResult = resolve2;
2493
+ });
2494
+ const cleanupAbort = bindAbortSignal(spec.signal, () => {
2495
+ kill("SIGTERM");
2496
+ });
2497
+ child.once("close", (code) => {
2498
+ if (settled) return;
2499
+ settled = true;
2500
+ cleanupAbort();
2501
+ resolveResult?.({ exitCode: code ?? 1 });
2502
+ });
2503
+ child.once("error", () => {
2504
+ if (settled) return;
2505
+ settled = true;
2506
+ cleanupAbort();
2507
+ resolveResult?.({ exitCode: 1 });
2508
+ });
2509
+ return {
2510
+ pid: child.pid ?? null,
2511
+ stdin: child.stdin,
2512
+ stdout: child.stdout,
2513
+ stderr: child.stderr,
2514
+ result,
2515
+ kill
2516
+ };
2517
+ }
2518
+ };
2519
+ }
2520
+ function bindAbortSignal(signal, onAbort) {
2521
+ if (signal === void 0) {
2522
+ return () => {
2523
+ };
2524
+ }
2525
+ if (signal.aborted) {
2526
+ onAbort();
2527
+ return () => {
2528
+ };
2529
+ }
2530
+ signal.addEventListener("abort", onAbort, { once: true });
2531
+ return () => {
2532
+ signal.removeEventListener("abort", onAbort);
2533
+ };
2534
+ }
2535
+
2536
+ // packages/process-runner/src/docker/docker-execution-env.ts
2537
+ var containerCommand = ["sh", "-c", "while :; do sleep 3600; done"];
2538
+ var dockerExecutionEnvFactory = {
2539
+ type: "docker",
2540
+ supportsDetach: true,
2541
+ async open(spec) {
2542
+ const runtime = parseDockerRuntime(spec.runtime);
2543
+ const runner = spec.hostRunner ?? createHostRunner();
2544
+ const engine = runtime.engine ?? detectEngine();
2545
+ const context = detectContext();
2546
+ const image = await resolveImage({
2547
+ spec,
2548
+ runtime,
2549
+ runner,
2550
+ engine,
2551
+ context
2552
+ });
2553
+ const containerName = createContainerName();
2554
+ const runArgs = buildDockerRunArgs({
2555
+ engine,
2556
+ context,
2557
+ image,
2558
+ command: containerCommand[0],
2559
+ args: containerCommand.slice(1),
2560
+ cwd: void 0,
2561
+ env: void 0,
2562
+ mounts: runtime.mounts ?? [],
2563
+ ports: [],
2564
+ network: runtime.network,
2565
+ containerName,
2566
+ detached: true,
2567
+ interactive: true,
2568
+ tty: false,
2569
+ rm: false,
2570
+ extraArgs: runtime.extra_args ?? []
2571
+ });
2572
+ const [command, ...args] = runArgs;
2573
+ const id = (await runAndRead(runner, { command, args, stdout: "pipe", stderr: "pipe" })).trim();
2574
+ return createDockerEnv({
2575
+ id,
2576
+ spec,
2577
+ runner,
2578
+ engine,
2579
+ context
2580
+ });
2581
+ },
2582
+ async attach(envId, context) {
2583
+ const engine = detectEngine();
2584
+ return createDockerEnv({
2585
+ id: envId,
2586
+ spec: createAttachedSpec(context?.cwd),
2587
+ runner: createHostRunner(),
2588
+ engine,
2589
+ context: detectContext(),
2590
+ attachedJobId: context?.jobId
2591
+ });
2592
+ }
2593
+ };
2594
+ function createDockerEnv(input) {
2595
+ const containerRef = input.id;
2596
+ return {
2597
+ id: containerRef,
2598
+ job: input.attachedJobId === void 0 ? null : createContainerJob(containerRef, input.runner, input.engine, input.context, input.attachedJobId),
2599
+ async uploadWorkspace() {
2600
+ const tempDir = mkdtempSync(path14.join(tmpdir(), "poe-docker-upload-"));
2601
+ const archivePath = path14.join(tempDir, "workspace.tar");
2602
+ try {
2603
+ const excludeArgs = input.spec.uploadIgnoreFiles.flatMap((ignored) => [
2604
+ "--exclude",
2605
+ ignored
2606
+ ]);
2607
+ const tarArgs = [...excludeArgs, "-cf", archivePath, "-C", input.spec.cwd, "."];
2608
+ await runOrThrow(input.runner, {
2609
+ command: "tar",
2610
+ args: tarArgs,
2611
+ stdout: "pipe",
2612
+ stderr: "pipe"
2613
+ });
2614
+ await runOrThrow(input.runner, {
2615
+ command: input.engine,
2616
+ args: [
2617
+ ...buildContextArgs(input.engine, input.context),
2618
+ "cp",
2619
+ archivePath,
2620
+ `${containerRef}:/tmp/poe-workspace-upload.tar`
2621
+ ],
2622
+ stdout: "pipe",
2623
+ stderr: "pipe"
2624
+ });
2625
+ await runOrThrow(input.runner, {
2626
+ command: input.engine,
2627
+ args: [
2628
+ ...buildContextArgs(input.engine, input.context),
2629
+ "exec",
2630
+ containerRef,
2631
+ "sh",
2632
+ "-c",
2633
+ `mkdir -p ${shellQuote(input.spec.cwd)} && tar -xf /tmp/poe-workspace-upload.tar -C ${shellQuote(input.spec.cwd)}`
2634
+ ],
2635
+ stdout: "pipe",
2636
+ stderr: "pipe"
2637
+ });
2638
+ return { files: 0, bytes: 0, skipped: [] };
2639
+ } finally {
2640
+ rmSync(tempDir, { recursive: true, force: true });
2641
+ }
2642
+ },
2643
+ async downloadWorkspace(opts) {
2644
+ const tempDir = mkdtempSync(path14.join(tmpdir(), "poe-docker-download-"));
2645
+ const archivePath = path14.join(tempDir, "workspace.tar");
2646
+ try {
2647
+ await runOrThrow(input.runner, {
2648
+ command: input.engine,
2649
+ args: [
2650
+ ...buildContextArgs(input.engine, input.context),
2651
+ "exec",
2652
+ containerRef,
2653
+ "sh",
2654
+ "-c",
2655
+ `tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote(input.spec.cwd)} .`
2656
+ ],
2657
+ stdout: "pipe",
2658
+ stderr: "pipe"
2659
+ });
2660
+ await runOrThrow(input.runner, {
2661
+ command: input.engine,
2662
+ args: [
2663
+ ...buildContextArgs(input.engine, input.context),
2664
+ "cp",
2665
+ `${containerRef}:/tmp/poe-workspace-download.tar`,
2666
+ archivePath
2667
+ ],
2668
+ stdout: "pipe",
2669
+ stderr: "pipe"
2670
+ });
2671
+ const extractMode = opts.conflictPolicy === "refuse" ? "-xkf" : "-xf";
2672
+ await runOrThrow(input.runner, {
2673
+ command: "tar",
2674
+ args: [extractMode, archivePath, "-C", input.spec.cwd],
2675
+ stdout: "pipe",
2676
+ stderr: "pipe"
2677
+ });
2678
+ return { files: 0, bytes: 0, conflicts: [] };
2679
+ } finally {
2680
+ rmSync(tempDir, { recursive: true, force: true });
2681
+ }
2682
+ },
2683
+ exec(spec) {
2684
+ return input.runner.exec({
2685
+ command: input.engine,
2686
+ args: [
2687
+ ...buildContextArgs(input.engine, input.context),
2688
+ "exec",
2689
+ ...spec.stdin === "pipe" || spec.stdin === "inherit" ? ["-i"] : [],
2690
+ ...spec.tty === true ? ["-t"] : [],
2691
+ ...spec.cwd !== void 0 ? ["-w", spec.cwd] : [],
2692
+ ...buildEnvArgs(spec.env),
2693
+ containerRef,
2694
+ spec.command,
2695
+ ...spec.args ?? []
2696
+ ],
2697
+ stdin: spec.stdin,
2698
+ stdout: spec.stdout,
2699
+ stderr: spec.stderr,
2700
+ tty: spec.tty
2701
+ });
2702
+ },
2703
+ async detach() {
2704
+ return createContainerJob(containerRef, input.runner, input.engine, input.context);
2705
+ },
2706
+ shell() {
2707
+ const shellSpec = input.spec.shellSpec;
2708
+ return this.exec({
2709
+ command: shellSpec?.command ?? input.spec.env.SHELL ?? "sh",
2710
+ ...shellSpec?.args ? { args: shellSpec.args } : {},
2711
+ cwd: input.spec.cwd,
2712
+ env: shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env,
2713
+ stdin: "inherit",
2714
+ stdout: "inherit",
2715
+ stderr: "inherit",
2716
+ tty: true
2717
+ });
2718
+ },
2719
+ async close() {
2720
+ await runOrThrow(input.runner, {
2721
+ command: input.engine,
2722
+ args: [...buildContextArgs(input.engine, input.context), "rm", "-f", containerRef],
2723
+ stdout: "pipe",
2724
+ stderr: "pipe"
2725
+ });
2726
+ }
2727
+ };
2728
+ }
2729
+ async function resolveImage(input) {
2730
+ if (input.runtime.image !== void 0) {
2731
+ return input.runtime.image;
2732
+ }
2733
+ const result = await buildDockerRuntimeTemplate({
2734
+ cwd: input.spec.cwd,
2735
+ runtime: input.runtime,
2736
+ state: input.spec.state,
2737
+ runner: input.runner
2738
+ });
2739
+ return result.image;
2740
+ }
2741
+ async function buildDockerRuntimeTemplate(input) {
2742
+ const runner = input.runner ?? createHostRunner();
2743
+ const engine = input.runtime.engine ?? detectEngine();
2744
+ const context = detectContext();
2745
+ const dockerfilePath = path14.resolve(
2746
+ input.cwd,
2747
+ input.runtime.dockerfile ?? path14.join(".poe-code", "Dockerfile")
2748
+ );
2749
+ const buildContext = path14.resolve(input.cwd, input.runtime.build_context ?? ".");
2750
+ const dockerfileBytes = await readFile2(dockerfilePath);
2751
+ const hash = hashDockerTemplate(dockerfileBytes, input.runtime.build_args ?? {});
2752
+ const cached2 = input.force ? null : await input.state?.templates.get("docker", hash);
2753
+ if (cached2?.image !== void 0) {
2754
+ return {
2755
+ backend: "docker",
2756
+ hash,
2757
+ image: cached2.image,
2758
+ cached: true
2759
+ };
2760
+ }
2761
+ const image = `poe-code/local:${hash}`;
2762
+ await buildImage({
2763
+ runner,
2764
+ engine,
2765
+ context,
2766
+ image,
2767
+ dockerfilePath,
2768
+ buildContext,
2769
+ buildArgs: input.runtime.build_args ?? {}
2770
+ });
2771
+ await input.state?.templates.put("docker", {
2772
+ hash,
2773
+ image,
2774
+ runtime_type: "docker",
2775
+ dockerfile_path: dockerfilePath,
2776
+ built_at: (/* @__PURE__ */ new Date()).toISOString()
2777
+ });
2778
+ return {
2779
+ backend: "docker",
2780
+ hash,
2781
+ image,
2782
+ cached: false
2783
+ };
2784
+ }
2785
+ function hashDockerTemplate(dockerfileBytes, buildArgs) {
2786
+ const hash = createHash2("sha256");
2787
+ hash.update(dockerfileBytes);
2788
+ hash.update("\0");
2789
+ for (const [key, value] of sortedBuildArgs(buildArgs)) {
2790
+ hash.update(key);
2791
+ hash.update("=");
2792
+ hash.update(value);
2793
+ hash.update("\0");
2794
+ }
2795
+ return hash.digest("hex");
2796
+ }
2797
+ async function buildImage(input) {
2798
+ await runOrThrow(input.runner, {
2799
+ command: input.engine,
2800
+ args: [
2801
+ ...buildContextArgs(input.engine, input.context),
2802
+ "build",
2803
+ "--tag",
2804
+ input.image,
2805
+ "-f",
2806
+ input.dockerfilePath,
2807
+ ...sortedBuildArgs(input.buildArgs).flatMap(([key, value]) => [
2808
+ "--build-arg",
2809
+ `${key}=${value}`
2810
+ ]),
2811
+ input.buildContext
2812
+ ],
2813
+ stdout: "pipe",
2814
+ stderr: "pipe"
2815
+ });
2816
+ }
2817
+ function parseDockerRuntime(runtime) {
2818
+ if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
2819
+ throw new Error("docker runtime must be an object");
2820
+ }
2821
+ const record = runtime;
2822
+ if (record.type !== "docker") {
2823
+ throw new Error('docker runtime type must be "docker"');
2824
+ }
2825
+ return record;
2826
+ }
2827
+ async function runAndRead(runner, spec) {
2828
+ const handle = runner.exec(spec);
2829
+ const stdout = readStream(handle.stdout);
2830
+ const stderr = readStream(handle.stderr);
2831
+ const result = await handle.result;
2832
+ const output = await stdout;
2833
+ if (result.exitCode !== 0) {
2834
+ const errorOutput = await stderr;
2835
+ throw new Error(
2836
+ `Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}${errorOutput ? `
2837
+ ${errorOutput}` : ""}`
2838
+ );
2839
+ }
2840
+ return output;
2841
+ }
2842
+ async function runOrThrow(runner, spec) {
2843
+ await runAndRead(runner, spec);
2844
+ }
2845
+ async function readStream(stream) {
2846
+ if (stream === null) {
2847
+ return "";
2848
+ }
2849
+ stream.setEncoding("utf8");
2850
+ const chunks = [];
2851
+ for await (const chunk of stream) {
2852
+ chunks.push(String(chunk));
2853
+ }
2854
+ return chunks.join("");
2855
+ }
2856
+ function sortedBuildArgs(buildArgs) {
2857
+ return Object.entries(buildArgs).sort(([left], [right]) => left.localeCompare(right));
2858
+ }
2859
+ function buildEnvArgs(env) {
2860
+ if (env === void 0) {
2861
+ return [];
2862
+ }
2863
+ return Object.entries(env).flatMap(([key, value]) => ["-e", `${key}=${value}`]);
2864
+ }
2865
+ function createContainerName() {
2866
+ return `poe-env-${randomBytes3(6).toString("hex")}`;
2867
+ }
2868
+ function createContainerJob(containerId, runner, engine, context, jobId = containerId) {
2869
+ return {
2870
+ id: jobId,
2871
+ envId: containerId,
2872
+ tool: "docker",
2873
+ argv: ["attach", containerId],
2874
+ async status() {
2875
+ const handle = runner.exec({
2876
+ command: engine,
2877
+ args: [
2878
+ ...buildContextArgs(engine, context),
2879
+ "inspect",
2880
+ "-f",
2881
+ "{{.State.Status}}",
2882
+ containerId
2883
+ ],
2884
+ stdout: "pipe",
2885
+ stderr: "pipe"
2886
+ });
2887
+ const stdout = await readStream(handle.stdout);
2888
+ const result = await handle.result;
2889
+ if (result.exitCode !== 0) {
2890
+ return "lost";
2891
+ }
2892
+ return stdout.trim() === "running" ? "running" : "exited";
2893
+ },
2894
+ async *stream(opts) {
2895
+ const handle = runner.exec({
2896
+ command: engine,
2897
+ args: [
2898
+ ...buildContextArgs(engine, context),
2899
+ "exec",
2900
+ containerId,
2901
+ "sh",
2902
+ "-c",
2903
+ `test -f ${shellQuote(`/tmp/poe-jobs/${jobId}.log`)} && tail -c +${(opts?.sinceByte ?? 0) + 1} ${shellQuote(`/tmp/poe-jobs/${jobId}.log`)} || true`
2904
+ ],
2905
+ stdout: "pipe",
2906
+ stderr: "pipe"
2907
+ });
2908
+ const stdout = await readStream(handle.stdout);
2909
+ await handle.result;
2910
+ if (stdout.length > 0) {
2911
+ yield { byteOffset: opts?.sinceByte ?? 0, data: stdout };
2912
+ }
2913
+ },
2914
+ async wait() {
2915
+ const handle = runner.exec({
2916
+ command: engine,
2917
+ args: [...buildContextArgs(engine, context), "wait", containerId],
2918
+ stdout: "pipe",
2919
+ stderr: "pipe"
2920
+ });
2921
+ const stdout = await readStream(handle.stdout);
2922
+ const result = await handle.result;
2923
+ return { exitCode: Number.parseInt(stdout.trim(), 10) || result.exitCode };
2924
+ },
2925
+ async kill(signal) {
2926
+ const args = signal === void 0 || signal === "SIGTERM" ? ["stop", containerId] : ["kill", ...signal === "SIGKILL" ? [] : [`--signal=${signal}`], containerId];
2927
+ await runOrThrow(runner, {
2928
+ command: engine,
2929
+ args: [...buildContextArgs(engine, context), ...args],
2930
+ stdout: "pipe",
2931
+ stderr: "pipe"
2932
+ });
2933
+ }
2934
+ };
2935
+ }
2936
+ function createAttachedSpec(cwd = "/workspace") {
2937
+ return {
2938
+ cwd,
2939
+ runtime: {
2940
+ type: "docker",
2941
+ image: "attached",
2942
+ build_args: {},
2943
+ mounts: []
2944
+ },
2945
+ env: {},
2946
+ uploadIgnoreFiles: [],
2947
+ jobLabel: {
2948
+ tool: "docker",
2949
+ argv: []
2950
+ }
2951
+ };
2952
+ }
2953
+ function shellQuote(value) {
2954
+ return `'${value.replaceAll("'", "'\\''")}'`;
2955
+ }
2956
+
2957
+ // packages/process-runner/src/host/host-execution-env.ts
2958
+ var hostExecutionEnvFactory = {
2959
+ type: "host",
2960
+ supportsDetach: false,
2961
+ async open(openSpec) {
2962
+ return {
2963
+ id: "host",
2964
+ job: null,
2965
+ async uploadWorkspace() {
2966
+ return {
2967
+ files: 0,
2968
+ bytes: 0,
2969
+ skipped: []
2970
+ };
2971
+ },
2972
+ async downloadWorkspace() {
2973
+ return {
2974
+ files: 0,
2975
+ bytes: 0,
2976
+ conflicts: []
2977
+ };
2978
+ },
2979
+ exec(spec) {
2980
+ return createHostRunner().exec(spec);
2981
+ },
2982
+ async detach() {
2983
+ throw new Error("host runtime does not support detach because host has no addressable env");
2984
+ },
2985
+ shell() {
2986
+ const shellSpec = openSpec.shellSpec;
2987
+ return createHostRunner().exec({
2988
+ command: shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
2989
+ ...shellSpec?.args ? { args: shellSpec.args } : {},
2990
+ cwd: openSpec.cwd,
2991
+ env: shellSpec && "env" in shellSpec ? shellSpec.env : openSpec.env,
2992
+ stdin: "inherit",
2993
+ stdout: "inherit",
2994
+ stderr: "inherit",
2995
+ tty: true
2996
+ });
2997
+ },
2998
+ async close() {
2999
+ }
3000
+ };
3001
+ },
3002
+ async attach() {
3003
+ throw new Error("host runtime does not support reattach");
3004
+ }
3005
+ };
3006
+
3007
+ // packages/process-runner/src/testing/mock-runner.ts
3008
+ import { Readable, Writable } from "node:stream";
3009
+
3010
+ // packages/runner-e2b/src/factory.ts
3011
+ import path18 from "node:path";
3012
+
3013
+ // packages/runner-e2b/src/sdk.ts
3014
+ import { Template, Sandbox } from "e2b";
3015
+ async function createSandbox(opts) {
3016
+ return Sandbox.create(opts.templateId, {
3017
+ apiKey: opts.apiKey,
3018
+ envs: opts.env,
3019
+ ...opts.timeoutMinutes === void 0 ? {} : { timeoutMs: opts.timeoutMinutes * 6e4 }
3020
+ });
3021
+ }
3022
+ async function connectSandbox(id, apiKey) {
3023
+ return Sandbox.connect(id, apiKey === void 0 ? void 0 : { apiKey });
3024
+ }
3025
+ async function buildTemplate(opts) {
3026
+ const template = Template({ fileContextPath: opts.buildContext }).fromDockerfile(
3027
+ opts.dockerfilePath
3028
+ );
3029
+ if (opts.fromTemplate !== void 0 && opts.fromTemplate.length > 0) {
3030
+ template.fromTemplate(opts.fromTemplate);
3031
+ }
3032
+ const result = await Template.build(template, opts.name, {
3033
+ apiKey: opts.apiKey,
3034
+ ...opts.cpu === void 0 ? {} : { cpuCount: opts.cpu },
3035
+ ...opts.memoryMb === void 0 ? {} : { memoryMB: opts.memoryMb },
3036
+ ...opts.onLog ? { onBuildLogs: opts.onLog } : {}
3037
+ });
3038
+ return { templateId: result.templateId };
3039
+ }
3040
+ function toArrayBuffer(buffer) {
3041
+ const output = new ArrayBuffer(buffer.byteLength);
3042
+ new Uint8Array(output).set(buffer);
3043
+ return output;
3044
+ }
3045
+ async function readableToString(stream) {
3046
+ if (stream === null) {
3047
+ return "";
3048
+ }
3049
+ stream.setEncoding("utf8");
3050
+ const chunks = [];
3051
+ for await (const chunk of stream) {
3052
+ chunks.push(String(chunk));
3053
+ }
3054
+ return chunks.join("");
3055
+ }
3056
+
3057
+ // packages/runner-e2b/src/template-build.ts
3058
+ import { createHash as createHash3 } from "node:crypto";
3059
+ import { readdir, readFile as readFile3 } from "node:fs/promises";
3060
+ import path15 from "node:path";
3061
+ var BUILD_LOG_TAIL_SIZE = 30;
3062
+ async function buildE2bRuntimeTemplate(input) {
3063
+ const dockerfileBytes = await readFile3(input.dockerfilePath);
3064
+ const buildContextFiles = await readBuildContextFiles(input.buildContext);
3065
+ const hash = hashTemplate(dockerfileBytes, buildContextFiles, input.runtime.build_args);
3066
+ const cached2 = input.force === true ? null : await input.state?.templates.get("e2b", hash);
3067
+ if (cached2?.template_id !== void 0) {
3068
+ return { backend: "e2b", hash, templateId: cached2.template_id, cached: true };
3069
+ }
3070
+ const tail = [];
3071
+ const onLog = (entry) => {
3072
+ tail.push(entry.message);
3073
+ if (tail.length > BUILD_LOG_TAIL_SIZE) {
3074
+ tail.shift();
3075
+ }
3076
+ input.onLog?.(entry);
3077
+ };
3078
+ let built;
3079
+ try {
3080
+ built = await buildTemplate({
3081
+ apiKey: input.apiKey,
3082
+ name: `poe-code-${hash.slice(0, 32)}`,
3083
+ dockerfilePath: input.dockerfilePath,
3084
+ buildContext: input.buildContext,
3085
+ cpu: input.runtime.cpu,
3086
+ memoryMb: input.runtime.memory_mb,
3087
+ fromTemplate: input.runtime.from_template,
3088
+ onLog
3089
+ });
3090
+ } catch (error2) {
3091
+ throw decorateBuildError(error2, tail);
3092
+ }
3093
+ await input.state?.templates.put("e2b", {
3094
+ hash,
3095
+ template_id: built.templateId,
3096
+ runtime_type: "e2b",
3097
+ dockerfile_path: input.dockerfilePath,
3098
+ built_at: (/* @__PURE__ */ new Date()).toISOString()
3099
+ });
3100
+ return { backend: "e2b", hash, templateId: built.templateId, cached: false };
3101
+ }
3102
+ function decorateBuildError(error2, tail) {
3103
+ const original = error2 instanceof Error ? error2 : new Error(String(error2));
3104
+ if (tail.length === 0) {
3105
+ return original;
3106
+ }
3107
+ const decorated = new Error(`${original.message}
3108
+
3109
+ Last build output:
3110
+ ${tail.join("\n")}`);
3111
+ decorated.stack = original.stack;
3112
+ decorated.cause = original;
3113
+ return decorated;
3114
+ }
3115
+ function hashTemplate(dockerfileBytes, buildContextFiles, buildArgs) {
3116
+ const hash = createHash3("sha256");
3117
+ hash.update(dockerfileBytes);
3118
+ hash.update("\0");
3119
+ for (const file of buildContextFiles) {
3120
+ hash.update(file.relativePath);
3121
+ hash.update("\0");
3122
+ hash.update(file.bytes);
3123
+ hash.update("\0");
3124
+ }
3125
+ for (const [key, value] of Object.entries(buildArgs).sort(
3126
+ ([left], [right]) => left.localeCompare(right)
3127
+ )) {
3128
+ hash.update(key);
3129
+ hash.update("=");
3130
+ hash.update(value);
3131
+ hash.update("\0");
3132
+ }
3133
+ return hash.digest("hex");
3134
+ }
3135
+ async function readBuildContextFiles(buildContext) {
3136
+ const files = [];
3137
+ await collectBuildContextFiles(buildContext, "", files);
3138
+ return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
3139
+ }
3140
+ async function collectBuildContextFiles(buildContext, relativeDir, files) {
3141
+ const absoluteDir = path15.join(buildContext, relativeDir);
3142
+ const entries = await readdir(absoluteDir, { withFileTypes: true });
3143
+ for (const entry of entries) {
3144
+ const relativePath = path15.join(relativeDir, entry.name);
3145
+ if (entry.isDirectory()) {
3146
+ await collectBuildContextFiles(buildContext, relativePath, files);
3147
+ continue;
3148
+ }
3149
+ if (!entry.isFile()) {
3150
+ continue;
3151
+ }
3152
+ files.push({
3153
+ relativePath: relativePath.split(path15.sep).join("/"),
3154
+ bytes: await readFile3(path15.join(buildContext, relativePath))
3155
+ });
3156
+ }
3157
+ }
3158
+
3159
+ // packages/runner-e2b/src/opened-env.ts
3160
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
3161
+ import { readFile as readFile4, writeFile } from "node:fs/promises";
3162
+ import { tmpdir as tmpdir2 } from "node:os";
3163
+ import path17 from "node:path";
3164
+ import { PassThrough, Writable as Writable2 } from "node:stream";
3165
+
3166
+ // packages/runner-e2b/src/job-handle.ts
3167
+ import path16 from "node:path";
3168
+ var JOB_DIR2 = "/tmp/poe-jobs";
3169
+ function createE2bJobHandle(input) {
3170
+ const fs = createE2bLogStreamFs(input.sandbox);
3171
+ return {
3172
+ id: input.jobId,
3173
+ envId: input.envId,
3174
+ tool: input.tool,
3175
+ argv: input.argv,
3176
+ async status() {
3177
+ const exit = await readExitCode(input.sandbox, input.jobId);
3178
+ if (exit !== null) {
3179
+ return "exited";
3180
+ }
3181
+ const processes = await input.sandbox.commands.list();
3182
+ const isRunning = input.pid === void 0 ? processes.some((process2) => processMentionsJob(process2, input.jobId)) : processes.some((process2) => process2.pid === input.pid);
3183
+ return isRunning ? "running" : "lost";
3184
+ },
3185
+ stream(opts = {}) {
3186
+ return streamLogFile({ fs }, input.jobId, opts);
3187
+ },
3188
+ async wait() {
3189
+ const result = await waitForExit({ fs }, input.jobId);
3190
+ const preserveMs = input.preserveAfterExitHours * 60 * 60 * 1e3;
3191
+ if (preserveMs > 0) {
3192
+ await input.sandbox.setTimeout(preserveMs);
3193
+ }
3194
+ return result;
3195
+ },
3196
+ async kill() {
3197
+ const pids = input.pid === void 0 ? (await input.sandbox.commands.list()).filter((process2) => processMentionsJob(process2, input.jobId)).map((process2) => process2.pid) : [input.pid];
3198
+ await Promise.all(pids.map((pid) => input.sandbox.commands.kill(pid)));
3199
+ }
3200
+ };
3201
+ }
3202
+ function createE2bLogStreamFs(sandbox) {
3203
+ return {
3204
+ promises: {
3205
+ async readFile(filePath) {
3206
+ return Buffer.from(await sandbox.files.read(filePath, { format: "bytes" }));
3207
+ },
3208
+ async stat(filePath) {
3209
+ const result = await sandbox.commands.run(
3210
+ `stat -c %Y ${shellQuote2(filePath)} 2>/dev/null || stat -f %m ${shellQuote2(filePath)}`
3211
+ );
3212
+ if (!("stdout" in result)) {
3213
+ throw new Error(`Unable to stat ${filePath}`);
3214
+ }
3215
+ const seconds = Number(result.stdout?.trim());
3216
+ if (!Number.isFinite(seconds)) {
3217
+ throw new Error(`Unable to stat ${filePath}`);
3218
+ }
3219
+ return { mtimeMs: seconds * 1e3 };
3220
+ }
3221
+ },
3222
+ watch(filePath, listener) {
3223
+ let closed = false;
3224
+ let stop = null;
3225
+ void sandbox.files.watchDir(path16.dirname(filePath), listener, { recursive: false }).then((handle) => {
3226
+ if (closed) {
3227
+ void handle.stop();
3228
+ return;
3229
+ }
3230
+ stop = () => {
3231
+ void handle.stop();
3232
+ };
3233
+ });
3234
+ return {
3235
+ close() {
3236
+ closed = true;
3237
+ stop?.();
3238
+ }
3239
+ };
3240
+ }
3241
+ };
3242
+ }
3243
+ function processMentionsJob(process2, jobId) {
3244
+ const needle = `/tmp/poe-jobs/${jobId}`;
3245
+ return process2.cmd.includes(needle) || process2.args.some((arg) => arg.includes(needle));
3246
+ }
3247
+ function shellQuote2(value) {
3248
+ return `'${value.replaceAll("'", "'\\''")}'`;
3249
+ }
3250
+ async function readExitCode(sandbox, jobId) {
3251
+ try {
3252
+ const contents = await sandbox.files.read(`${JOB_DIR2}/${jobId}.exit`);
3253
+ const exitCode = Number(contents.trim());
3254
+ return Number.isInteger(exitCode) ? exitCode : null;
3255
+ } catch {
3256
+ return null;
3257
+ }
3258
+ }
3259
+
3260
+ // packages/runner-e2b/src/opened-env.ts
3261
+ var REMOTE_COMMAND_STDERR_TAIL_SIZE = 30;
3262
+ function createOpenedE2bEnv(input) {
3263
+ const hostRunner = input.spec.hostRunner ?? createHostRunner();
3264
+ const hostWorkspaceDir = path17.resolve(input.spec.cwd);
3265
+ const sandboxWorkspaceDir = normalizeSandboxWorkspaceDir(input.runtime.workspace_dir);
3266
+ let lastProcess = null;
3267
+ let detachedJobContext = null;
3268
+ const mapWorkspaceCwd = (cwd) => {
3269
+ if (cwd === void 0) {
3270
+ return void 0;
3271
+ }
3272
+ if (path17.isAbsolute(cwd) && path17.resolve(cwd) === hostWorkspaceDir) {
3273
+ return sandboxWorkspaceDir;
3274
+ }
3275
+ return cwd;
3276
+ };
3277
+ const attachedJobId = input.spec.detachedJobId;
3278
+ const env = {
3279
+ id: input.sandbox.sandboxId,
3280
+ job: attachedJobId ? createE2bJobHandle({
3281
+ sandbox: input.sandbox,
3282
+ envId: input.sandbox.sandboxId,
3283
+ jobId: attachedJobId,
3284
+ tool: input.spec.jobLabel.tool,
3285
+ argv: input.spec.jobLabel.argv,
3286
+ preserveAfterExitHours: input.runtime.preserve_after_exit_hours ?? 24
3287
+ }) : null,
3288
+ fs: createE2bLogStreamFs(input.sandbox),
3289
+ setDetachedJobContext(context) {
3290
+ detachedJobContext = context;
3291
+ },
3292
+ async uploadWorkspace() {
3293
+ if (input.spec.runner?.sync === "none") {
3294
+ return { files: 0, bytes: 0, skipped: [] };
3295
+ }
3296
+ const tempDir = mkdtempSync2(path17.join(tmpdir2(), "poe-e2b-upload-"));
3297
+ const archivePath = path17.join(tempDir, "workspace.tar");
3298
+ try {
3299
+ await runOrThrow2(hostRunner, {
3300
+ command: "tar",
3301
+ args: [
3302
+ ...input.spec.uploadIgnoreFiles.flatMap((ignored) => ["--exclude", ignored]),
3303
+ "-cf",
3304
+ archivePath,
3305
+ "-C",
3306
+ input.spec.cwd,
3307
+ "."
3308
+ ],
3309
+ stdout: "pipe",
3310
+ stderr: "pipe"
3311
+ });
3312
+ await input.sandbox.files.write(
3313
+ "/tmp/poe-workspace-upload.tar",
3314
+ toArrayBuffer(await readFile4(archivePath))
3315
+ );
3316
+ await runRemoteOrThrow(
3317
+ input.sandbox,
3318
+ createUploadWorkspaceCommand(sandboxWorkspaceDir)
3319
+ );
3320
+ return { files: 0, bytes: 0, skipped: [] };
3321
+ } finally {
3322
+ rmSync2(tempDir, { recursive: true, force: true });
3323
+ }
3324
+ },
3325
+ async downloadWorkspace(opts) {
3326
+ if (input.spec.runner?.sync === "upload" || input.spec.runner?.sync === "none") {
3327
+ return { files: 0, bytes: 0, conflicts: [] };
3328
+ }
3329
+ const tempDir = mkdtempSync2(path17.join(tmpdir2(), "poe-e2b-download-"));
3330
+ const archivePath = path17.join(tempDir, "workspace.tar");
3331
+ try {
3332
+ await runRemoteOrThrow(
3333
+ input.sandbox,
3334
+ `tar -cf /tmp/poe-workspace-download.tar -C ${shellQuote3(sandboxWorkspaceDir)} .`
3335
+ );
3336
+ const archive = await input.sandbox.files.read("/tmp/poe-workspace-download.tar", {
3337
+ format: "bytes"
3338
+ });
3339
+ await writeFile(archivePath, Buffer.from(archive));
3340
+ await runOrThrow2(hostRunner, {
3341
+ command: "tar",
3342
+ args: [
3343
+ opts.conflictPolicy === "refuse" ? "-xkf" : "-xf",
3344
+ archivePath,
3345
+ "-C",
3346
+ input.spec.cwd
3347
+ ],
3348
+ stdout: "pipe",
3349
+ stderr: "pipe"
3350
+ });
3351
+ return { files: 0, bytes: archive.byteLength, conflicts: [] };
3352
+ } finally {
3353
+ rmSync2(tempDir, { recursive: true, force: true });
3354
+ }
3355
+ },
3356
+ exec(spec) {
3357
+ const handle = runE2bCommand(input.sandbox, {
3358
+ ...spec,
3359
+ cwd: mapWorkspaceCwd(spec.cwd),
3360
+ env: resolveSandboxCommandEnv(spec.env)
3361
+ });
3362
+ lastProcess = { started: handle.started };
3363
+ return handle;
3364
+ },
3365
+ async detach() {
3366
+ if (detachedJobContext === null) {
3367
+ throw new Error("Cannot detach E2B environment before a job context is registered.");
3368
+ }
3369
+ if (lastProcess === null) {
3370
+ throw new Error("Cannot detach E2B environment before a command is running.");
3371
+ }
3372
+ const command = await lastProcess.started;
3373
+ const preserveAfterExitHours = input.runtime.preserve_after_exit_hours ?? 24;
3374
+ const preserveMs = preserveAfterExitHours * 60 * 60 * 1e3;
3375
+ if (preserveMs > 0) {
3376
+ await input.sandbox.setTimeout(preserveMs);
3377
+ }
3378
+ return createE2bJobHandle({
3379
+ sandbox: input.sandbox,
3380
+ envId: input.sandbox.sandboxId,
3381
+ jobId: detachedJobContext.id,
3382
+ tool: detachedJobContext.tool,
3383
+ argv: detachedJobContext.argv,
3384
+ pid: command.pid,
3385
+ preserveAfterExitHours
3386
+ });
3387
+ },
3388
+ shell() {
3389
+ const shellSpec = input.spec.shellSpec;
3390
+ const command = shellSpec?.command ?? input.spec.env.SHELL ?? "sh";
3391
+ return runE2bPty(input.sandbox, {
3392
+ command,
3393
+ ...shellSpec?.args ? { args: shellSpec.args } : {},
3394
+ cwd: mapWorkspaceCwd(shellSpec?.cwd ?? input.spec.cwd),
3395
+ env: resolveSandboxCommandEnv(
3396
+ shellSpec && "env" in shellSpec ? shellSpec.env : input.spec.env
3397
+ ),
3398
+ stdin: "inherit",
3399
+ stdout: "inherit",
3400
+ stderr: "inherit",
3401
+ tty: true
3402
+ });
3403
+ },
3404
+ async close() {
3405
+ await input.sandbox.kill();
3406
+ }
3407
+ };
3408
+ return env;
3409
+ }
3410
+ function runE2bCommand(sandbox, spec) {
3411
+ const stdout = spec.stdout === "inherit" ? null : new PassThrough();
3412
+ const stderr = spec.stderr === "inherit" ? null : new PassThrough();
3413
+ let e2bHandle = null;
3414
+ const command = shellCommand([spec.command, ...spec.args ?? []]);
3415
+ const started = sandbox.commands.run(command, {
3416
+ background: true,
3417
+ cwd: spec.cwd,
3418
+ envs: spec.env,
3419
+ stdin: spec.stdin === "pipe",
3420
+ onStdout(data) {
3421
+ stdout?.write(data);
3422
+ if (spec.stdout === "inherit") {
3423
+ process.stdout.write(data);
3424
+ }
3425
+ },
3426
+ onStderr(data) {
3427
+ stderr?.write(data);
3428
+ if (spec.stderr === "inherit") {
3429
+ process.stderr.write(data);
3430
+ }
3431
+ }
3432
+ });
3433
+ const stdin = spec.stdin === "pipe" ? new Writable2({
3434
+ write(chunk, _encoding, callback) {
3435
+ started.then(
3436
+ (handle) => sandbox.commands.sendStdin(
3437
+ handle.pid,
3438
+ Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))
3439
+ )
3440
+ ).then(() => callback(), callback);
3441
+ },
3442
+ final(callback) {
3443
+ if (sandbox.commands.closeStdin === void 0) {
3444
+ callback();
3445
+ return;
3446
+ }
3447
+ started.then((handle) => sandbox.commands.closeStdin(handle.pid)).then(() => callback(), callback);
3448
+ }
3449
+ }) : null;
3450
+ const result = started.then((handle) => {
3451
+ e2bHandle = handle;
3452
+ return handle.wait();
3453
+ }).then(
3454
+ (result2) => {
3455
+ stdout?.end();
3456
+ stderr?.end();
3457
+ return { exitCode: result2.exitCode ?? 0 };
3458
+ },
3459
+ (error2) => {
3460
+ stdout?.end();
3461
+ stderr?.end();
3462
+ if (isExitError(error2)) {
3463
+ return { exitCode: error2.exitCode };
3464
+ }
3465
+ return { exitCode: 1 };
3466
+ }
3467
+ );
3468
+ return {
3469
+ get pid() {
3470
+ return e2bHandle?.pid ?? null;
3471
+ },
3472
+ stdin,
3473
+ stdout,
3474
+ stderr,
3475
+ result,
3476
+ kill() {
3477
+ void e2bHandle?.kill();
3478
+ },
3479
+ get e2bHandle() {
3480
+ return e2bHandle;
3481
+ },
3482
+ started
3483
+ };
3484
+ }
3485
+ function runE2bPty(sandbox, spec) {
3486
+ const stdout = new PassThrough();
3487
+ let handleRef = null;
3488
+ const stdin = new Writable2({
3489
+ write(chunk, _encoding, callback) {
3490
+ if (handleRef === null) {
3491
+ callback(new Error("E2B PTY stdin is not ready."));
3492
+ return;
3493
+ }
3494
+ sandbox.pty.sendInput(handleRef.pid, Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))).then(() => callback(), callback);
3495
+ }
3496
+ });
3497
+ const started = sandbox.pty.create({
3498
+ cols: process.stdout.columns || 80,
3499
+ rows: process.stdout.rows || 24,
3500
+ cwd: spec.cwd,
3501
+ envs: spec.env,
3502
+ onData(data) {
3503
+ stdout.write(Buffer.from(data));
3504
+ if (spec.stdout === "inherit") {
3505
+ process.stdout.write(Buffer.from(data));
3506
+ }
3507
+ }
3508
+ });
3509
+ const result = started.then((handle) => {
3510
+ handleRef = handle;
3511
+ return handle.wait();
3512
+ }).then(
3513
+ (result2) => {
3514
+ stdout.end();
3515
+ return { exitCode: result2.exitCode ?? 0 };
3516
+ },
3517
+ () => {
3518
+ stdout.end();
3519
+ return { exitCode: 1 };
3520
+ }
3521
+ );
3522
+ return {
3523
+ get pid() {
3524
+ return handleRef?.pid ?? null;
3525
+ },
3526
+ stdin: spec.stdin === "inherit" ? process.stdin : stdin,
3527
+ stdout: spec.stdout === "inherit" ? null : stdout,
3528
+ stderr: null,
3529
+ result,
3530
+ kill() {
3531
+ void (handleRef === null ? void 0 : sandbox.pty.kill(handleRef.pid));
3532
+ }
3533
+ };
3534
+ }
3535
+ async function runRemoteOrThrow(sandbox, command) {
3536
+ const stdoutTail = createLineTail(REMOTE_COMMAND_STDERR_TAIL_SIZE);
3537
+ const stderrTail = createLineTail(REMOTE_COMMAND_STDERR_TAIL_SIZE);
3538
+ let result;
3539
+ try {
3540
+ result = await sandbox.commands.run(command, {
3541
+ onStdout(data) {
3542
+ stdoutTail.push(data);
3543
+ },
3544
+ onStderr(data) {
3545
+ stderrTail.push(data);
3546
+ }
3547
+ });
3548
+ } catch (error2) {
3549
+ appendRemoteCommandOutput(error2, stdoutTail, stderrTail);
3550
+ if (isCommandExitError(error2)) {
3551
+ throw decorateRemoteCommandError(error2, command, stderrTail.values());
3552
+ }
3553
+ throw error2;
3554
+ }
3555
+ appendRemoteCommandOutput(result, stdoutTail, stderrTail);
3556
+ if ("exitCode" in result && result.exitCode !== 0) {
3557
+ throw decorateRemoteCommandError(
3558
+ new Error(`E2B command failed with exit code ${result.exitCode}`),
3559
+ command,
3560
+ stderrTail.values()
3561
+ );
3562
+ }
3563
+ }
3564
+ function appendRemoteCommandOutput(source, stdoutTail, stderrTail) {
3565
+ if (!source || typeof source !== "object") {
3566
+ return;
3567
+ }
3568
+ const output = source;
3569
+ if (typeof output.stdout === "string") {
3570
+ stdoutTail.push(output.stdout);
3571
+ }
3572
+ if (typeof output.stderr === "string") {
3573
+ stderrTail.push(output.stderr);
3574
+ }
3575
+ }
3576
+ function decorateRemoteCommandError(error2, command, stderrTail) {
3577
+ const original = error2 instanceof Error ? error2 : new Error(String(error2));
3578
+ const tail = stderrTail.length === 0 ? "" : `
3579
+
3580
+ Last stderr output:
3581
+ ${stderrTail.join("\n")}`;
3582
+ const decorated = new Error(`E2B command failed: ${command}
3583
+ ${original.message}${tail}`);
3584
+ decorated.stack = original.stack;
3585
+ decorated.cause = original;
3586
+ return decorated;
3587
+ }
3588
+ function createLineTail(maxLines) {
3589
+ const lines = [];
3590
+ let pending = "";
3591
+ const appendLine = (line) => {
3592
+ lines.push(trimTrailingCarriageReturn(line));
3593
+ while (lines.length > maxLines) {
3594
+ lines.shift();
3595
+ }
3596
+ };
3597
+ return {
3598
+ push(chunk) {
3599
+ pending += chunk;
3600
+ const parts = pending.split("\n");
3601
+ pending = parts.pop() ?? "";
3602
+ for (const line of parts) {
3603
+ appendLine(line);
3604
+ }
3605
+ },
3606
+ values() {
3607
+ const output = [...lines];
3608
+ if (pending.length > 0) {
3609
+ output.push(trimTrailingCarriageReturn(pending));
3610
+ }
3611
+ return output.slice(-maxLines);
3612
+ }
3613
+ };
3614
+ }
3615
+ function trimTrailingCarriageReturn(value) {
3616
+ return value.endsWith("\r") ? value.slice(0, -1) : value;
3617
+ }
3618
+ async function runOrThrow2(runner, spec) {
3619
+ const handle = runner.exec(spec);
3620
+ const stderr = readableToString(handle.stderr);
3621
+ const result = await handle.result;
3622
+ if (result.exitCode !== 0) {
3623
+ throw new Error(
3624
+ `Command failed with exit code ${result.exitCode}: ${spec.command} ${(spec.args ?? []).join(" ")}
3625
+ ${await stderr}`
3626
+ );
3627
+ }
3628
+ }
3629
+ function shellCommand(argv) {
3630
+ return argv.map(shellQuote3).join(" ");
3631
+ }
3632
+ function shellQuote3(value) {
3633
+ return `'${value.replaceAll("'", "'\\''")}'`;
3634
+ }
3635
+ function createUploadWorkspaceCommand(sandboxWorkspaceDir) {
3636
+ const quotedWorkspaceDir = shellQuote3(sandboxWorkspaceDir);
3637
+ return [
3638
+ `mkdir -p ${quotedWorkspaceDir} || { command -v sudo >/dev/null 2>&1 && sudo mkdir -p ${quotedWorkspaceDir} && sudo chown "$(id -u):$(id -g)" ${quotedWorkspaceDir}; }`,
3639
+ `test -w ${quotedWorkspaceDir} && tar -xf /tmp/poe-workspace-upload.tar -C ${quotedWorkspaceDir}`
3640
+ ].join("\n");
3641
+ }
3642
+ function resolveSandboxCommandEnv(env) {
3643
+ if (env === void 0) {
3644
+ return void 0;
3645
+ }
3646
+ return {
3647
+ ...env,
3648
+ HOME: "/home/user"
3649
+ };
3650
+ }
3651
+ function normalizeSandboxWorkspaceDir(workspaceDir) {
3652
+ const resolvedWorkspaceDir = workspaceDir ?? "/workspace";
3653
+ if (!path17.posix.isAbsolute(resolvedWorkspaceDir)) {
3654
+ throw new Error("E2B runtime workspace_dir must be an absolute sandbox path.");
3655
+ }
3656
+ let normalized = path17.posix.normalize(resolvedWorkspaceDir);
3657
+ while (normalized.length > 1 && normalized.endsWith("/")) {
3658
+ normalized = normalized.slice(0, -1);
3659
+ }
3660
+ return normalized;
3661
+ }
3662
+ function isExitError(error2) {
3663
+ return Boolean(
3664
+ error2 && typeof error2 === "object" && typeof error2.exitCode === "number"
3665
+ );
3666
+ }
3667
+ function isCommandExitError(error2) {
3668
+ return isExitError(error2) || Boolean(
3669
+ error2 && typeof error2 === "object" && error2.name === "CommandExitError"
3670
+ );
3671
+ }
3672
+
3673
+ // packages/runner-e2b/src/auth-scope.ts
3674
+ import os4 from "node:os";
3675
+ import { promises as nodeFs4 } from "node:fs";
3676
+ var e2bAuthScope = defineScope("e2b", {
3677
+ api_key: {
3678
+ type: "string",
3679
+ default: "",
3680
+ doc: "E2B API key",
3681
+ env: "E2B_API_KEY"
3682
+ }
3683
+ });
3684
+ async function resolveE2bApiKey(input) {
3685
+ const homeDir = input.homeDir ?? os4.homedir();
3686
+ const fs = input.fs ?? nodeFs4;
3687
+ const env = input.env ?? process.env;
3688
+ const document = await readMergedDocument(
3689
+ fs,
3690
+ resolveConfigPath(homeDir),
3691
+ resolveProjectConfigPath(input.cwd)
3692
+ );
3693
+ const resolved = resolveScope(e2bAuthScope.schema, document.e2b, env);
3694
+ if (resolved.api_key.length === 0) {
3695
+ throw new Error(
3696
+ "No E2B API key. Set E2B_API_KEY or e2b.api_key in ~/.poe-code/config.json."
3697
+ );
3698
+ }
3699
+ return resolved.api_key;
3700
+ }
3701
+
3702
+ // packages/runner-e2b/src/factory.ts
3703
+ var e2bExecutionEnvFactory = {
3704
+ type: "e2b",
3705
+ supportsDetach: true,
3706
+ async open(spec) {
3707
+ const runtime = parseE2bRuntime(spec.runtime);
3708
+ const runtimeCwd = spec.runtimeCwd ?? spec.cwd;
3709
+ const apiKey = await resolveE2bApiKey({ cwd: runtimeCwd });
3710
+ const templateId = runtime.template_id ?? (await buildE2bRuntimeTemplate({
3711
+ runtime,
3712
+ dockerfilePath: path18.resolve(
3713
+ runtimeCwd,
3714
+ runtime.dockerfile ?? path18.join(".poe-code", "Dockerfile")
3715
+ ),
3716
+ buildContext: path18.resolve(runtimeCwd, runtime.build_context ?? "."),
3717
+ state: spec.state,
3718
+ apiKey
3719
+ })).templateId;
3720
+ const sandbox = await createSandbox({
3721
+ apiKey,
3722
+ templateId,
3723
+ env: spec.env,
3724
+ timeoutMinutes: runtime.timeout_minutes
3725
+ });
3726
+ return createOpenedE2bEnv({ sandbox, spec, runtime });
3727
+ },
3728
+ async attach(envId, context) {
3729
+ const cwd = context?.cwd ?? process.cwd();
3730
+ const apiKey = await resolveE2bApiKey({ cwd });
3731
+ const sandbox = await connectSandbox(envId, apiKey);
3732
+ return createOpenedE2bEnv({
3733
+ sandbox,
3734
+ spec: {
3735
+ cwd: context?.cwd ?? "/workspace",
3736
+ runtime: {
3737
+ type: "e2b",
3738
+ build_args: {},
3739
+ mounts: [],
3740
+ workspace_dir: "/workspace",
3741
+ preserve_after_exit_hours: 24
3742
+ },
3743
+ env: {},
3744
+ uploadIgnoreFiles: [],
3745
+ jobLabel: { tool: context?.tool ?? "e2b", argv: context?.argv ?? [] },
3746
+ ...context?.jobId ? { detachedJobId: context.jobId } : {}
3747
+ },
3748
+ runtime: {
3749
+ type: "e2b",
3750
+ build_args: {},
3751
+ mounts: [],
3752
+ workspace_dir: "/workspace",
3753
+ preserve_after_exit_hours: 24
3754
+ }
3755
+ });
3756
+ }
3757
+ };
3758
+ function parseE2bRuntime(runtime) {
3759
+ if (!runtime || typeof runtime !== "object" || Array.isArray(runtime)) {
3760
+ throw new Error("e2b runtime must be an object");
3761
+ }
3762
+ const record = runtime;
3763
+ if (record.type !== "e2b") {
3764
+ throw new Error('e2b runtime type must be "e2b"');
3765
+ }
3766
+ return record;
3767
+ }
3768
+
3769
+ // packages/runner-e2b/src/index.ts
3770
+ var e2bExecutionEnvFactory2 = e2bExecutionEnvFactory;
3771
+
3772
+ // packages/agent-spawn/src/register-factories.ts
3773
+ registerExecutionEnvFactory(hostExecutionEnvFactory);
3774
+ registerExecutionEnvFactory(dockerExecutionEnvFactory);
3775
+ registerExecutionEnvFactory(e2bExecutionEnvFactory2);
3776
+ if (isVitest()) {
3777
+ registerExecutionEnvFactory(createTestHostExecutionEnvFactory());
3778
+ }
3779
+ function isVitest() {
3780
+ return process.env.VITEST !== void 0 || process.env.VITEST_POOL_ID !== void 0;
3781
+ }
3782
+ function createTestHostExecutionEnvFactory() {
3783
+ return {
3784
+ type: "host",
3785
+ supportsDetach: false,
3786
+ open: ((openSpec) => {
3787
+ return {
3788
+ id: "host",
3789
+ job: null,
3790
+ async uploadWorkspace() {
3791
+ return { files: 0, bytes: 0, skipped: [] };
3792
+ },
3793
+ async downloadWorkspace() {
3794
+ return { files: 0, bytes: 0, conflicts: [] };
3795
+ },
3796
+ exec(spec) {
3797
+ return runHost(spawnChildProcess2, spec);
3798
+ },
3799
+ async detach() {
3800
+ throw new Error(
3801
+ "host runtime does not support detach because host has no addressable env"
3802
+ );
3803
+ },
3804
+ shell() {
3805
+ return runHost(spawnChildProcess2, {
3806
+ command: openSpec.shellSpec?.command ?? openSpec.env.SHELL ?? process.env.SHELL ?? "sh",
3807
+ args: openSpec.shellSpec?.args,
3808
+ cwd: openSpec.cwd,
3809
+ env: openSpec.shellSpec && "env" in openSpec.shellSpec ? openSpec.shellSpec.env : openSpec.env,
3810
+ stdin: "inherit",
3811
+ stdout: "inherit",
3812
+ stderr: "inherit",
3813
+ tty: true
3814
+ });
3815
+ },
3816
+ async close() {
3817
+ }
3818
+ };
3819
+ }),
3820
+ async attach() {
3821
+ throw new Error("host runtime does not support reattach");
3822
+ }
3823
+ };
3824
+ }
3825
+ function runHost(spawnProcess, spec) {
3826
+ const stdin = spec.stdin ?? "ignore";
3827
+ const stdout = spec.stdout ?? "pipe";
3828
+ const stderr = spec.stderr ?? "pipe";
3829
+ const stdio = stdin === "inherit" && stdout === "inherit" && stderr === "inherit" ? "inherit" : [stdin, stdout, stderr];
3830
+ const child = spawnProcess(spec.command, spec.args ?? [], {
3831
+ cwd: spec.cwd,
3832
+ env: spec.env,
3833
+ stdio
3834
+ });
3835
+ const result = new Promise((resolve2) => {
3836
+ child.once("close", (code) => {
3837
+ resolve2({ exitCode: code ?? 1 });
3838
+ });
3839
+ child.once("error", () => {
3840
+ resolve2({ exitCode: 1 });
3841
+ });
3842
+ });
3843
+ const kill = (signal) => {
3844
+ child.kill(signal);
3845
+ };
3846
+ if (spec.signal?.aborted) {
3847
+ kill("SIGTERM");
3848
+ } else {
3849
+ spec.signal?.addEventListener("abort", () => kill("SIGTERM"), { once: true });
3850
+ }
3851
+ return {
3852
+ pid: child.pid ?? null,
3853
+ stdin: child.stdin,
3854
+ stdout: child.stdout,
3855
+ stderr: child.stderr,
3856
+ result,
3857
+ kill
3858
+ };
3859
+ }
3860
+
3861
+ // packages/agent-spawn/src/run-command.ts
3862
+ import { spawn as spawn2 } from "node:child_process";
3863
+
3864
+ // packages/agent-spawn/src/configs/mcp.ts
3865
+ function toJsonMcpServers(servers) {
3866
+ const out = {};
3867
+ for (const [name, server] of Object.entries(servers)) {
3868
+ const mapped = { command: server.command };
3869
+ if (server.args && server.args.length > 0) {
3870
+ mapped.args = server.args;
3871
+ }
3872
+ if (server.env && Object.keys(server.env).length > 0) {
3873
+ mapped.env = server.env;
3874
+ }
3875
+ if (server.timeout !== void 0) {
3876
+ mapped.timeout = server.timeout;
3877
+ }
3878
+ out[name] = mapped;
3879
+ }
3880
+ return out;
3881
+ }
3882
+ function toTomlString(value) {
3883
+ return JSON.stringify(value);
3884
+ }
3885
+ function toTomlArray(values) {
3886
+ const serialized = values.map((value) => toTomlString(value));
3887
+ return `[${serialized.join(", ")}]`;
3888
+ }
3889
+ function toTomlInlineTable(values) {
3890
+ const parts = [];
3891
+ for (const [key, value] of Object.entries(values)) {
3892
+ parts.push(`${JSON.stringify(key)}=${toTomlString(value)}`);
3893
+ }
3894
+ return `{${parts.join(", ")}}`;
3895
+ }
3896
+ function serializeJsonMcpArgs(servers) {
3897
+ return ["--mcp-config", JSON.stringify({ mcpServers: toJsonMcpServers(servers) })];
3898
+ }
3899
+ function serializeOpenCodeMcpEnv(servers) {
3900
+ const mcp = {};
3901
+ for (const [name, server] of Object.entries(servers)) {
3902
+ const entry = { type: "local", command: [server.command, ...server.args ?? []] };
3903
+ if (server.env && Object.keys(server.env).length > 0) {
3904
+ entry.environment = server.env;
3905
+ }
3906
+ mcp[name] = entry;
3907
+ }
3908
+ return { OPENCODE_CONFIG_CONTENT: JSON.stringify({ mcp }) };
3909
+ }
3910
+ function serializeCodexMcpArgs(servers) {
3911
+ const args = [];
3912
+ for (const [name, server] of Object.entries(servers)) {
3913
+ const prefix = `mcp_servers.${name}`;
3914
+ args.push("-c", `${prefix}.command=${toTomlString(server.command)}`);
3915
+ if (server.args && server.args.length > 0) {
3916
+ args.push("-c", `${prefix}.args=${toTomlArray(server.args)}`);
3917
+ }
3918
+ if (server.env && Object.keys(server.env).length > 0) {
3919
+ args.push("-c", `${prefix}.env=${toTomlInlineTable(server.env)}`);
3920
+ }
3921
+ if (server.timeout !== void 0) {
3922
+ args.push("-c", `${prefix}.timeout=${server.timeout}`);
3923
+ }
3924
+ }
3925
+ return args;
3926
+ }
3927
+ function serializeGooseMcpArgs(servers) {
3928
+ return Object.values(servers).flatMap((server) => [
3929
+ "--with-extension",
3930
+ [server.command, ...server.args ?? []].join(" ")
3931
+ ]);
3932
+ }
3933
+
3934
+ // packages/agent-spawn/src/configs/claude-code.ts
3935
+ var claudeCodeSpawnConfig = {
3936
+ kind: "cli",
3937
+ agentId: "claude-code",
3938
+ // ACP adapter support: yes (adapter: "claude")
3939
+ adapter: "claude",
3940
+ promptFlag: "-p",
3941
+ modelFlag: "--model",
3942
+ modelStripProviderPrefix: true,
3943
+ modelTransform: (model) => model.replaceAll(".", "-"),
3944
+ defaultArgs: [
3945
+ "--output-format",
3946
+ "stream-json",
3947
+ "--verbose"
3948
+ ],
3949
+ mcpArgs: serializeJsonMcpArgs,
3950
+ modes: {
3951
+ yolo: ["--dangerously-skip-permissions"],
3952
+ edit: ["--permission-mode", "acceptEdits", "--allowedTools", "Bash,Read,Write,Edit,Glob,Grep,NotebookEdit"],
3953
+ read: ["--permission-mode", "plan"]
3954
+ },
3955
+ stdinMode: {
3956
+ omitPrompt: true,
3957
+ extraArgs: ["--input-format", "text"]
3958
+ },
3959
+ interactive: {
3960
+ defaultArgs: []
3961
+ },
3962
+ resumeCommand: (threadId) => ["--resume", threadId]
3963
+ };
3964
+
3965
+ // packages/agent-spawn/src/configs/codex.ts
3966
+ var codexSpawnConfig = {
3967
+ kind: "cli",
3968
+ agentId: "codex",
3969
+ // ACP adapter support: yes (adapter: "codex")
3970
+ adapter: "codex",
3971
+ promptFlag: "exec",
3972
+ modelFlag: "--model",
3973
+ modelStripProviderPrefix: true,
3974
+ defaultArgs: ["--skip-git-repo-check", "--json"],
3975
+ mcpArgs: serializeCodexMcpArgs,
3976
+ mcpArgsBeforeCommand: true,
3977
+ modes: {
3978
+ yolo: ["-s", "danger-full-access"],
3979
+ edit: ["-s", "workspace-write"],
3980
+ read: ["-s", "read-only"]
3981
+ },
3982
+ stdinMode: {
3983
+ omitPrompt: true,
3984
+ extraArgs: ["-"]
3985
+ },
3986
+ interactive: {
3987
+ defaultArgs: ["-a", "never"]
3988
+ },
3989
+ resumeCommand: (threadId, cwd) => ["resume", "-C", cwd, threadId]
3990
+ };
3991
+
3992
+ // packages/agent-spawn/src/configs/opencode.ts
3993
+ var openCodeSpawnConfig = {
3994
+ kind: "cli",
3995
+ agentId: "opencode",
3996
+ // ACP adapter support: yes (adapter: "opencode").
3997
+ // OpenCode's `--format json` emits NDJSON events with `{ type, sessionID, part }`
3998
+ // (no `{ event, ... }` field), so it needs the OpenCode adapter (not "native").
3999
+ adapter: "opencode",
4000
+ promptFlag: "run",
4001
+ modelFlag: "--model",
4002
+ modelStripProviderPrefix: false,
4003
+ modelTransform: (model) => {
4004
+ return model.startsWith("poe/") ? model : `poe/${model}`;
4005
+ },
4006
+ defaultArgs: ["--format", "json"],
4007
+ modes: {
4008
+ yolo: [],
4009
+ edit: [],
4010
+ read: ["--agent", "plan"]
4011
+ },
4012
+ interactive: {
4013
+ defaultArgs: [],
4014
+ promptFlag: "--prompt"
4015
+ },
4016
+ resumeCommand: (threadId, cwd) => [cwd, "--session", threadId],
4017
+ mcpEnv: serializeOpenCodeMcpEnv
4018
+ };
4019
+ var openCodeAcpSpawnConfig = {
4020
+ kind: "acp",
4021
+ agentId: "opencode",
4022
+ acpArgs: ["acp"],
4023
+ skipAuth: true,
4024
+ mcpEnv: serializeOpenCodeMcpEnv
4025
+ };
4026
+
4027
+ // packages/agent-spawn/src/configs/kimi.ts
4028
+ var kimiSpawnConfig = {
4029
+ kind: "cli",
4030
+ agentId: "kimi",
4031
+ // ACP adapter support: yes (adapter: "kimi").
4032
+ // Kimi's `--output-format stream-json` emits OpenAI-style `{ role, content }` JSON
4033
+ // (no `{ event, ... }` field), so it needs the Kimi adapter (not "native").
4034
+ adapter: "kimi",
4035
+ promptFlag: "-p",
4036
+ modelStripProviderPrefix: true,
4037
+ defaultArgs: ["--print", "--output-format", "stream-json"],
4038
+ mcpArgs: serializeJsonMcpArgs,
4039
+ modes: {
4040
+ yolo: ["--yolo"],
4041
+ edit: [],
4042
+ read: []
4043
+ },
4044
+ stdinMode: {
4045
+ omitPrompt: true,
4046
+ extraArgs: ["--input-format", "stream-json"]
4047
+ },
4048
+ interactive: {
4049
+ defaultArgs: [],
4050
+ promptFlag: "-p"
4051
+ },
4052
+ resumeCommand: (threadId, cwd) => ["--session", threadId, "--work-dir", cwd]
4053
+ };
4054
+ var kimiAcpSpawnConfig = {
4055
+ kind: "acp",
4056
+ agentId: "kimi",
4057
+ acpArgs: ["acp"]
4058
+ };
4059
+
4060
+ // packages/agent-spawn/src/configs/goose.ts
4061
+ var gooseFileSecretsEnv = { GOOSE_DISABLE_KEYRING: "1" };
4062
+ var gooseSpawnConfig = {
4063
+ kind: "cli",
4064
+ agentId: "goose",
4065
+ adapter: "native",
4066
+ promptFlag: "--text",
4067
+ modelFlag: "--model",
4068
+ modelStripProviderPrefix: false,
4069
+ defaultArgs: ["run", "--output-format", "stream-json"],
4070
+ defaultArgsPosition: "beforePrompt",
4071
+ mcpArgs: serializeGooseMcpArgs,
4072
+ mcpArgsPosition: "beforePrompt",
4073
+ modes: {
4074
+ yolo: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "auto" } },
4075
+ edit: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "smart_approve" } },
4076
+ read: { env: { ...gooseFileSecretsEnv, GOOSE_MODE: "chat" } }
4077
+ },
4078
+ stdinMode: {
4079
+ omitPrompt: true,
4080
+ extraArgs: ["--instructions", "-"]
4081
+ },
4082
+ interactive: {
4083
+ defaultArgs: ["session"],
4084
+ defaultArgsPosition: "beforePrompt"
4085
+ },
4086
+ resumeCommand: () => ["run", "--resume", "--text", "continue"]
4087
+ };
4088
+ var gooseAcpSpawnConfig = {
4089
+ kind: "acp",
4090
+ agentId: "goose",
4091
+ acpArgs: ["acp"],
4092
+ env: gooseFileSecretsEnv,
4093
+ skipAuth: true
4094
+ };
4095
+
4096
+ // packages/agent-spawn/src/configs/index.ts
4097
+ var allSpawnConfigs = [
4098
+ claudeCodeSpawnConfig,
4099
+ codexSpawnConfig,
4100
+ openCodeSpawnConfig,
4101
+ kimiSpawnConfig,
4102
+ gooseSpawnConfig
4103
+ ];
4104
+ var lookup2 = /* @__PURE__ */ new Map();
4105
+ for (const config of allSpawnConfigs) {
4106
+ lookup2.set(config.agentId, config);
4107
+ }
4108
+ var acpLookup = /* @__PURE__ */ new Map();
4109
+ acpLookup.set(openCodeAcpSpawnConfig.agentId, openCodeAcpSpawnConfig);
4110
+ acpLookup.set(kimiAcpSpawnConfig.agentId, kimiAcpSpawnConfig);
4111
+ acpLookup.set(gooseAcpSpawnConfig.agentId, gooseAcpSpawnConfig);
4112
+
4113
+ // packages/agent-spawn/src/spawn.ts
4114
+ import { mkdirSync, openSync, writeSync, closeSync } from "node:fs";
4115
+ import path19 from "node:path";
4116
+
4117
+ // packages/design-system/src/tokens/colors.ts
4118
+ import chalk from "chalk";
4119
+ var dark = {
4120
+ header: (text4) => chalk.magentaBright.bold(text4),
4121
+ divider: (text4) => chalk.dim(text4),
4122
+ prompt: (text4) => chalk.cyan(text4),
4123
+ number: (text4) => chalk.cyanBright(text4),
4124
+ intro: (text4) => chalk.bgMagenta.white(` Poe - ${text4} `),
4125
+ resolvedSymbol: chalk.magenta("\u25C7"),
4126
+ errorSymbol: chalk.red("\u25A0"),
4127
+ accent: (text4) => chalk.cyan(text4),
4128
+ muted: (text4) => chalk.dim(text4),
4129
+ success: (text4) => chalk.green(text4),
4130
+ warning: (text4) => chalk.yellow(text4),
4131
+ error: (text4) => chalk.red(text4),
4132
+ info: (text4) => chalk.magenta(text4),
4133
+ badge: (text4) => chalk.bgYellow.black(` ${text4} `)
4134
+ };
4135
+ var light = {
4136
+ header: (text4) => chalk.hex("#a200ff").bold(text4),
4137
+ divider: (text4) => chalk.hex("#666666")(text4),
4138
+ prompt: (text4) => chalk.hex("#006699").bold(text4),
4139
+ number: (text4) => chalk.hex("#0077cc").bold(text4),
4140
+ intro: (text4) => chalk.bgHex("#a200ff").white(` Poe - ${text4} `),
4141
+ resolvedSymbol: chalk.hex("#a200ff")("\u25C7"),
4142
+ errorSymbol: chalk.hex("#cc0000")("\u25A0"),
4143
+ accent: (text4) => chalk.hex("#006699").bold(text4),
4144
+ muted: (text4) => chalk.hex("#666666")(text4),
4145
+ success: (text4) => chalk.hex("#008800")(text4),
4146
+ warning: (text4) => chalk.hex("#cc6600")(text4),
4147
+ error: (text4) => chalk.hex("#cc0000")(text4),
4148
+ info: (text4) => chalk.hex("#a200ff")(text4),
4149
+ badge: (text4) => chalk.bgHex("#cc6600").white(` ${text4} `)
4150
+ };
4151
+
4152
+ // packages/design-system/src/tokens/typography.ts
4153
+ import chalk2 from "chalk";
4154
+
4155
+ // packages/design-system/src/components/text.ts
4156
+ import chalk3 from "chalk";
4157
+
4158
+ // packages/design-system/src/internal/output-format.ts
4159
+ import { AsyncLocalStorage } from "node:async_hooks";
4160
+ var VALID_FORMATS = /* @__PURE__ */ new Set(["terminal", "markdown", "json"]);
4161
+ var formatStorage = new AsyncLocalStorage();
4162
+ var cached;
4163
+ function resolveOutputFormat(env = process.env) {
4164
+ const scoped = formatStorage.getStore();
4165
+ if (scoped) {
4166
+ return scoped;
4167
+ }
4168
+ if (cached) {
4169
+ return cached;
4170
+ }
4171
+ const raw = env.OUTPUT_FORMAT?.toLowerCase();
4172
+ cached = VALID_FORMATS.has(raw) ? raw : "terminal";
4173
+ return cached;
4174
+ }
4175
+
4176
+ // packages/design-system/src/internal/theme-detect.ts
4177
+ function detectThemeFromEnv(env) {
4178
+ const apple = env.APPLE_INTERFACE_STYLE;
4179
+ if (typeof apple === "string") {
4180
+ return apple.toLowerCase() === "dark" ? "dark" : "light";
4181
+ }
4182
+ const vscodeKind = env.VSCODE_COLOR_THEME_KIND;
4183
+ if (typeof vscodeKind === "string") {
4184
+ const normalized = vscodeKind.toLowerCase();
4185
+ if (normalized.includes("light")) {
4186
+ return "light";
4187
+ }
4188
+ if (normalized.includes("dark")) {
4189
+ return "dark";
4190
+ }
4191
+ }
4192
+ const colorFGBG = env.COLORFGBG;
4193
+ if (typeof colorFGBG === "string") {
4194
+ const parts = colorFGBG.split(";").map((part) => Number.parseInt(part, 10));
4195
+ const background = parts.at(-1);
4196
+ if (Number.isFinite(background)) {
4197
+ return background >= 8 ? "light" : "dark";
4198
+ }
4199
+ }
4200
+ return void 0;
4201
+ }
4202
+ function resolveThemeName(env = process.env) {
4203
+ const raw = (env.POE_CODE_THEME ?? env.POE_THEME)?.toLowerCase();
4204
+ if (raw === "light" || raw === "dark") {
4205
+ return raw;
4206
+ }
4207
+ const detected = detectThemeFromEnv(env);
4208
+ if (detected) {
4209
+ return detected;
4210
+ }
4211
+ return "dark";
4212
+ }
4213
+ var cachedTheme;
4214
+ function getTheme(env) {
4215
+ if (cachedTheme) {
4216
+ return cachedTheme;
4217
+ }
4218
+ const themeName = resolveThemeName(env);
4219
+ cachedTheme = themeName === "light" ? light : dark;
4220
+ return cachedTheme;
4221
+ }
4222
+
4223
+ // packages/design-system/src/components/symbols.ts
4224
+ import chalk4 from "chalk";
4225
+ var symbols = {
4226
+ get info() {
4227
+ const format = resolveOutputFormat();
4228
+ if (format === "json") return "info";
4229
+ if (format === "markdown") return "(i)";
4230
+ return chalk4.magenta("\u25CF");
4231
+ },
4232
+ get success() {
4233
+ const format = resolveOutputFormat();
4234
+ if (format === "json") return "success";
4235
+ if (format === "markdown") return "[ok]";
4236
+ return chalk4.magenta("\u25C6");
4237
+ },
4238
+ get resolved() {
4239
+ const format = resolveOutputFormat();
4240
+ if (format === "json") return "resolved";
4241
+ if (format === "markdown") return ">";
4242
+ return getTheme().resolvedSymbol;
4243
+ },
4244
+ get errorResolved() {
4245
+ const format = resolveOutputFormat();
4246
+ if (format === "json") return "error";
4247
+ if (format === "markdown") return "[!]";
4248
+ return getTheme().errorSymbol;
4249
+ },
4250
+ get bar() {
4251
+ const format = resolveOutputFormat();
4252
+ if (format === "json") return "";
4253
+ if (format === "markdown") return "|";
4254
+ return "\u2502";
4255
+ },
4256
+ cornerTopRight: "\u256E",
4257
+ cornerBottomRight: "\u256F",
4258
+ get warning() {
4259
+ const format = resolveOutputFormat();
4260
+ if (format === "json") return "warning";
4261
+ if (format === "markdown") return "[!]";
4262
+ return "\u25B2";
4263
+ },
4264
+ get active() {
4265
+ const format = resolveOutputFormat();
4266
+ if (format === "json") return "active";
4267
+ if (format === "markdown") return "[x]";
4268
+ return "\u25C6";
4269
+ },
4270
+ get inactive() {
4271
+ const format = resolveOutputFormat();
4272
+ if (format === "json") return "inactive";
4273
+ if (format === "markdown") return "[ ]";
4274
+ return "\u25CB";
4275
+ }
4276
+ };
4277
+
4278
+ // packages/design-system/src/components/logger.ts
4279
+ import chalk6 from "chalk";
4280
+
4281
+ // packages/design-system/src/prompts/primitives/log.ts
4282
+ import chalk5 from "chalk";
4283
+
4284
+ // packages/design-system/src/internal/strip-ansi.ts
4285
+ function stripAnsi(value) {
4286
+ return value.replace(/\u001b\[[0-9;]*m/g, "");
4287
+ }
4288
+
4289
+ // packages/design-system/src/prompts/primitives/log.ts
4290
+ function writeTerminalMessage(msg, {
4291
+ symbol = chalk5.gray("\u2502"),
4292
+ secondarySymbol = chalk5.gray("\u2502"),
4293
+ spacing: spacing2 = 1,
4294
+ withGuide = true
4295
+ } = {}) {
4296
+ const lines = [];
4297
+ const showGuide = withGuide !== false;
4298
+ const contentLines = msg.split("\n");
4299
+ const prefix = showGuide ? `${symbol} ` : "";
4300
+ const continuationPrefix = showGuide ? `${secondarySymbol} ` : "";
4301
+ const emptyGuide = showGuide ? secondarySymbol : "";
4302
+ for (let index = 0; index < spacing2; index += 1) {
4303
+ lines.push(emptyGuide);
4304
+ }
4305
+ if (contentLines.length === 0) {
4306
+ process.stdout.write("\n");
4307
+ return;
4308
+ }
4309
+ const [firstLine = "", ...continuationLines] = contentLines;
4310
+ if (firstLine.length > 0) {
4311
+ lines.push(`${prefix}${firstLine}`);
4312
+ } else {
4313
+ lines.push(showGuide ? symbol : "");
4314
+ }
4315
+ for (const line of continuationLines) {
4316
+ if (line.length > 0) {
4317
+ lines.push(`${continuationPrefix}${line}`);
4318
+ continue;
4319
+ }
4320
+ lines.push(emptyGuide);
4321
+ }
4322
+ process.stdout.write(`${lines.join("\n")}
4323
+ `);
4324
+ }
4325
+ function message(msg, options) {
4326
+ const format = resolveOutputFormat();
4327
+ if (format === "markdown") {
4328
+ process.stdout.write(`- ${stripAnsi(msg)}
4329
+ `);
4330
+ return;
4331
+ }
4332
+ if (format === "json") {
4333
+ process.stdout.write(
4334
+ `${JSON.stringify({ level: "message", message: stripAnsi(msg) })}
4335
+ `
4336
+ );
4337
+ return;
4338
+ }
4339
+ writeTerminalMessage(msg, options);
4340
+ }
4341
+ function info(msg) {
4342
+ const format = resolveOutputFormat();
4343
+ if (format === "markdown") {
4344
+ process.stdout.write(`- **info:** ${stripAnsi(msg)}
4345
+ `);
4346
+ return;
4347
+ }
4348
+ if (format === "json") {
4349
+ process.stdout.write(
4350
+ `${JSON.stringify({ level: "info", message: stripAnsi(msg) })}
4351
+ `
4352
+ );
4353
+ return;
4354
+ }
4355
+ message(msg, { symbol: symbols.info });
4356
+ }
4357
+ function success(msg) {
4358
+ const format = resolveOutputFormat();
4359
+ if (format === "markdown") {
4360
+ process.stdout.write(`- **success:** ${stripAnsi(msg)}
4361
+ `);
4362
+ return;
4363
+ }
4364
+ if (format === "json") {
4365
+ process.stdout.write(
4366
+ `${JSON.stringify({ level: "success", message: stripAnsi(msg) })}
4367
+ `
4368
+ );
4369
+ return;
4370
+ }
4371
+ message(msg, { symbol: symbols.success });
4372
+ }
4373
+ function warn(msg) {
4374
+ const format = resolveOutputFormat();
4375
+ if (format === "markdown") {
4376
+ process.stdout.write(`- **warning:** ${stripAnsi(msg)}
4377
+ `);
4378
+ return;
4379
+ }
4380
+ if (format === "json") {
4381
+ process.stdout.write(
4382
+ `${JSON.stringify({ level: "warn", message: stripAnsi(msg) })}
4383
+ `
4384
+ );
4385
+ return;
4386
+ }
4387
+ message(msg, { symbol: chalk5.yellow("\u25B2") });
4388
+ }
4389
+ function error(msg) {
4390
+ const format = resolveOutputFormat();
4391
+ if (format === "markdown") {
4392
+ process.stdout.write(`- **error:** ${stripAnsi(msg)}
4393
+ `);
4394
+ return;
4395
+ }
4396
+ if (format === "json") {
4397
+ process.stdout.write(
4398
+ `${JSON.stringify({ level: "error", message: stripAnsi(msg) })}
4399
+ `
4400
+ );
4401
+ return;
4402
+ }
4403
+ message(msg, { symbol: chalk5.red("\u25A0") });
4404
+ }
4405
+ var log = {
4406
+ info,
4407
+ success,
4408
+ message,
4409
+ warn,
4410
+ error
4411
+ };
4412
+
4413
+ // packages/design-system/src/components/logger.ts
4414
+ function createLogger(emitter) {
4415
+ const emit = (level, message2) => {
4416
+ if (emitter) {
4417
+ emitter(message2);
4418
+ return;
4419
+ }
4420
+ if (level === "success") {
4421
+ log.success(message2);
4422
+ return;
4423
+ }
4424
+ if (level === "warn") {
4425
+ log.warn(message2);
4426
+ return;
4427
+ }
4428
+ if (level === "error") {
4429
+ log.error(message2);
4430
+ return;
4431
+ }
4432
+ log.info(message2);
4433
+ };
4434
+ return {
4435
+ info(message2) {
4436
+ emit("info", message2);
4437
+ },
4438
+ success(message2) {
4439
+ emit("success", message2);
4440
+ },
4441
+ warn(message2) {
4442
+ emit("warn", message2);
4443
+ },
4444
+ error(message2) {
4445
+ emit("error", message2);
4446
+ },
4447
+ resolved(label, value) {
4448
+ if (emitter) {
4449
+ emitter(`${label}: ${value}`);
4450
+ return;
4451
+ }
4452
+ log.message(`${label}
4453
+ ${value}`, { symbol: symbols.resolved });
4454
+ },
4455
+ errorResolved(label, value) {
4456
+ if (emitter) {
4457
+ emitter(`${label}: ${value}`);
4458
+ return;
4459
+ }
4460
+ log.message(`${label}
4461
+ ${value}`, { symbol: symbols.errorResolved });
4462
+ },
4463
+ message(message2, symbol) {
4464
+ if (emitter) {
4465
+ emitter(message2);
4466
+ return;
4467
+ }
4468
+ log.message(message2, { symbol: symbol ?? chalk6.gray("\u2502") });
4469
+ }
4470
+ };
4471
+ }
4472
+ var logger = createLogger();
4473
+
4474
+ // packages/design-system/src/components/table.ts
4475
+ import { Table } from "console-table-printer";
4476
+
4477
+ // packages/design-system/src/acp/components.ts
4478
+ import chalk7 from "chalk";
4479
+
4480
+ // packages/design-system/src/acp/writer.ts
4481
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
4482
+ var storage = new AsyncLocalStorage2();
4483
+
4484
+ // packages/design-system/src/acp/components.ts
4485
+ var AGENT_PREFIX = `${chalk7.green.bold("\u2713")} agent: `;
4486
+
4487
+ // packages/design-system/src/dashboard/buffer.ts
4488
+ import chalk8 from "chalk";
4489
+
4490
+ // packages/design-system/src/dashboard/terminal.ts
4491
+ import readline from "node:readline";
4492
+ import { PassThrough as PassThrough2 } from "node:stream";
4493
+
4494
+ // packages/design-system/src/prompts/index.ts
4495
+ import chalk15 from "chalk";
4496
+ import * as clack from "@clack/prompts";
4497
+
4498
+ // packages/design-system/src/prompts/primitives/cancel.ts
4499
+ import chalk9 from "chalk";
4500
+ import { isCancel } from "@clack/prompts";
4501
+
4502
+ // packages/design-system/src/prompts/primitives/intro.ts
4503
+ import chalk10 from "chalk";
4504
+
4505
+ // packages/design-system/src/prompts/primitives/note.ts
4506
+ import chalk11 from "chalk";
4507
+
4508
+ // packages/design-system/src/prompts/primitives/outro.ts
4509
+ import chalk12 from "chalk";
4510
+
4511
+ // packages/design-system/src/prompts/primitives/spinner.ts
4512
+ import chalk14 from "chalk";
4513
+
4514
+ // packages/design-system/src/static/spinner.ts
4515
+ import chalk13 from "chalk";
4516
+
4517
+ // packages/design-system/src/static/menu.ts
4518
+ import chalk16 from "chalk";
4519
+
4520
+ // packages/agent-spawn/src/autonomous.ts
4521
+ var DEFAULT_ACTIVITY_TIMEOUT_MS = 10 * 60 * 1e3;
4522
+
4523
+ // packages/agent-spawn/src/acp/replay.ts
4524
+ import path20 from "node:path";
4525
+ import { homedir as homedir2 } from "node:os";
4526
+ import { open as open2, readdir as readdir2 } from "node:fs/promises";
4527
+ import { createInterface } from "node:readline";
4528
+
4529
+ // packages/poe-acp-client/src/acp-client.ts
4530
+ import { isAbsolute } from "node:path";
4531
+
4532
+ // packages/poe-acp-client/src/acp-transport.ts
4533
+ import {
4534
+ spawn as spawnChildProcess3
4535
+ } from "node:child_process";
4536
+
4537
+ // packages/poe-acp-client/src/run-report.ts
4538
+ import * as fsPromises2 from "node:fs/promises";
4539
+ import { homedir } from "node:os";
4540
+ import { join } from "node:path";
4541
+
4542
+ // packages/agent-spawn/src/acp/middlewares/spawn-log.ts
4543
+ import path21 from "node:path";
4544
+ import { homedir as homedir3 } from "node:os";
4545
+ import { mkdir, open as open3 } from "node:fs/promises";
4546
+
4547
+ // src/utils/command-checks.ts
4548
+ function formatCommandRunnerResult(result) {
4549
+ const stdout = result.stdout.length > 0 ? result.stdout : "<empty>";
4550
+ const stderr = result.stderr.length > 0 ? result.stderr : "<empty>";
4551
+ return `stdout:
4552
+ ${stdout}
4553
+ stderr:
4554
+ ${stderr}`;
4555
+ }
4556
+ function describeCommandExpectation(command, args, expectedOutput) {
4557
+ return `${renderCommandLine(command, args)} (expecting "${expectedOutput}")`;
4558
+ }
4559
+ function createCommandExpectationCheck(options) {
4560
+ return {
4561
+ id: options.id,
4562
+ description: describeCommandExpectation(
4563
+ options.command,
4564
+ options.args,
4565
+ options.expectedOutput
4566
+ ),
4567
+ async run(context) {
4568
+ await runAndMatchOutput(context, options);
4569
+ }
4570
+ };
4571
+ }
4572
+ async function runAndMatchOutput(context, options) {
4573
+ const rendered = renderCommandLine(options.command, options.args);
4574
+ if (options.skipOnDryRun !== false && context.isDryRun) {
4575
+ if (context.logDryRun) {
4576
+ context.logDryRun(
4577
+ `Dry run: ${rendered} (expecting "${options.expectedOutput}")`
4578
+ );
4579
+ }
4580
+ return;
4581
+ }
4582
+ const result = options.commandOptions ? await context.runCommand(options.command, options.args, options.commandOptions) : await context.runCommand(options.command, options.args);
4583
+ if (result.exitCode !== 0) {
4584
+ const detail = formatCommandRunnerResult(result);
4585
+ throw new Error(
4586
+ [`Command ${rendered} failed with exit code ${result.exitCode}.`, detail].join("\n")
4587
+ );
4588
+ }
4589
+ if (!stdoutMatchesExpected(result.stdout, options.expectedOutput)) {
4590
+ const detail = formatCommandRunnerResult(result);
4591
+ const received = result.stdout.trim();
4592
+ throw new Error(
4593
+ [
4594
+ `Command ${rendered} failed: expected "${options.expectedOutput}" but received "${received}".`,
4595
+ detail
4596
+ ].join("\n")
4597
+ );
4598
+ }
4599
+ }
4600
+ function stdoutMatchesExpected(stdout, expected) {
4601
+ const trimmed = stdout.trim();
4602
+ if (trimmed === expected) {
4603
+ return true;
4604
+ }
4605
+ const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
4606
+ if (lines.some((line) => line === expected)) {
4607
+ return true;
4608
+ }
4609
+ for (const line of lines) {
4610
+ if (line[0] !== "{") continue;
4611
+ try {
4612
+ const parsed = JSON.parse(line);
4613
+ if (parsed.type === "result" && parsed.result === expected) {
4614
+ return true;
4615
+ }
4616
+ } catch {
4617
+ continue;
4618
+ }
4619
+ }
4620
+ return false;
4621
+ }
4622
+ function renderCommandLine(command, args) {
4623
+ return [command, ...args].map(quoteIfNeeded).join(" ").trim();
4624
+ }
4625
+ function quoteIfNeeded(value) {
4626
+ if (value.length === 0) {
4627
+ return '""';
4628
+ }
4629
+ if (needsQuoting(value)) {
4630
+ return `"${value.replaceAll('"', '\\"')}"`;
4631
+ }
4632
+ return value;
4633
+ }
4634
+ function needsQuoting(value) {
4635
+ return value.includes(" ") || value.includes(" ") || value.includes("\n");
4636
+ }
4637
+ function createBinaryExistsCheck(binaryName, id, description) {
4638
+ return {
4639
+ id,
4640
+ description,
4641
+ async run({ runCommand: runCommand2 }) {
4642
+ for (const detector of createBinaryExistsDetectors(binaryName)) {
4643
+ const result = await runCommand2(detector.command, detector.args);
4644
+ if (detector.validate(result)) {
4645
+ return;
4646
+ }
4647
+ }
4648
+ throw new Error(`${binaryName} CLI binary not found on PATH.`);
4649
+ }
4650
+ };
4651
+ }
4652
+
2019
4653
  // src/services/service-install.ts
2020
4654
  async function runServiceInstall(definition, context) {
2021
4655
  const checkContext = {