poe-code 3.0.154 → 3.0.156

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 (53) hide show
  1. package/dist/cli/commands/auth.js +7 -2
  2. package/dist/cli/commands/auth.js.map +1 -1
  3. package/dist/cli/commands/configure.js +3 -2
  4. package/dist/cli/commands/configure.js.map +1 -1
  5. package/dist/cli/commands/experiment.js +2 -1
  6. package/dist/cli/commands/experiment.js.map +1 -1
  7. package/dist/cli/commands/generate.js +3 -3
  8. package/dist/cli/commands/generate.js.map +1 -1
  9. package/dist/cli/commands/install.js +3 -4
  10. package/dist/cli/commands/install.js.map +1 -1
  11. package/dist/cli/commands/launch.js +15 -7
  12. package/dist/cli/commands/launch.js.map +1 -1
  13. package/dist/cli/commands/logout.js +1 -1
  14. package/dist/cli/commands/logout.js.map +1 -1
  15. package/dist/cli/commands/mcp.js +11 -11
  16. package/dist/cli/commands/mcp.js.map +1 -1
  17. package/dist/cli/commands/pipeline.js +3 -2
  18. package/dist/cli/commands/pipeline.js.map +1 -1
  19. package/dist/cli/commands/plan.d.ts +3 -0
  20. package/dist/cli/commands/plan.js +285 -0
  21. package/dist/cli/commands/plan.js.map +1 -0
  22. package/dist/cli/commands/ralph.js +2 -1
  23. package/dist/cli/commands/ralph.js.map +1 -1
  24. package/dist/cli/commands/shared.d.ts +4 -0
  25. package/dist/cli/commands/shared.js +19 -3
  26. package/dist/cli/commands/shared.js.map +1 -1
  27. package/dist/cli/commands/skill.js +10 -18
  28. package/dist/cli/commands/skill.js.map +1 -1
  29. package/dist/cli/commands/spawn.js +24 -7
  30. package/dist/cli/commands/spawn.js.map +1 -1
  31. package/dist/cli/commands/test.js +3 -4
  32. package/dist/cli/commands/test.js.map +1 -1
  33. package/dist/cli/commands/unconfigure.js +2 -2
  34. package/dist/cli/commands/unconfigure.js.map +1 -1
  35. package/dist/cli/commands/usage.js +1 -1
  36. package/dist/cli/commands/usage.js.map +1 -1
  37. package/dist/cli/commands/utils.js +2 -1
  38. package/dist/cli/commands/utils.js.map +1 -1
  39. package/dist/cli/program.js +139 -188
  40. package/dist/cli/program.js.map +1 -1
  41. package/dist/index.js +1324 -443
  42. package/dist/index.js.map +4 -4
  43. package/dist/providers/claude-code.js +1 -1
  44. package/dist/providers/claude-code.js.map +2 -2
  45. package/dist/providers/codex.js +1 -1
  46. package/dist/providers/codex.js.map +2 -2
  47. package/dist/providers/kimi.js +1 -1
  48. package/dist/providers/kimi.js.map +2 -2
  49. package/dist/providers/opencode.js +1 -1
  50. package/dist/providers/opencode.js.map +2 -2
  51. package/dist/providers/poe-agent.js +18 -9
  52. package/dist/providers/poe-agent.js.map +2 -2
  53. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -925,16 +925,16 @@ function getConfigFormat(pathOrFormat) {
925
925
  }
926
926
  return formatRegistry[formatName];
927
927
  }
928
- function detectFormat(path43) {
929
- const ext = getExtension(path43);
928
+ function detectFormat(path48) {
929
+ const ext = getExtension(path48);
930
930
  return extensionMap[ext];
931
931
  }
932
- function getExtension(path43) {
933
- const lastDot = path43.lastIndexOf(".");
932
+ function getExtension(path48) {
933
+ const lastDot = path48.lastIndexOf(".");
934
934
  if (lastDot === -1) {
935
935
  return "";
936
936
  }
937
- return path43.slice(lastDot).toLowerCase();
937
+ return path48.slice(lastDot).toLowerCase();
938
938
  }
939
939
  var formatRegistry, extensionMap;
940
940
  var init_formats = __esm({
@@ -1265,8 +1265,8 @@ async function applyChmod(mutation, context, options) {
1265
1265
  };
1266
1266
  }
1267
1267
  try {
1268
- const stat13 = await context.fs.stat(targetPath);
1269
- const currentMode = typeof stat13.mode === "number" ? stat13.mode & 511 : null;
1268
+ const stat14 = await context.fs.stat(targetPath);
1269
+ const currentMode = typeof stat14.mode === "number" ? stat14.mode & 511 : null;
1270
1270
  if (currentMode === mutation.mode) {
1271
1271
  return {
1272
1272
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -1989,38 +1989,38 @@ import { createTwoFilesPatch } from "diff";
1989
1989
  import chalk from "chalk";
1990
1990
  function createDryRunFileSystem(base, recorder) {
1991
1991
  const proxy = {
1992
- async readFile(path43, encoding) {
1992
+ async readFile(path48, encoding) {
1993
1993
  if (encoding) {
1994
- return base.readFile(path43, encoding);
1994
+ return base.readFile(path48, encoding);
1995
1995
  }
1996
- return base.readFile(path43);
1996
+ return base.readFile(path48);
1997
1997
  },
1998
- async writeFile(path43, data, options) {
1999
- const previousContent = await tryReadText(base, path43);
1998
+ async writeFile(path48, data, options) {
1999
+ const previousContent = await tryReadText(base, path48);
2000
2000
  const nextContent = formatData(data, options?.encoding);
2001
2001
  recorder.record({
2002
2002
  type: "writeFile",
2003
- path: path43,
2003
+ path: path48,
2004
2004
  nextContent,
2005
2005
  previousContent
2006
2006
  });
2007
2007
  },
2008
- async mkdir(path43, options) {
2009
- recorder.record({ type: "mkdir", path: path43, options });
2008
+ async mkdir(path48, options) {
2009
+ recorder.record({ type: "mkdir", path: path48, options });
2010
2010
  },
2011
- async stat(path43) {
2012
- return base.stat(path43);
2011
+ async stat(path48) {
2012
+ return base.stat(path48);
2013
2013
  },
2014
- async unlink(path43) {
2015
- recorder.record({ type: "unlink", path: path43 });
2014
+ async unlink(path48) {
2015
+ recorder.record({ type: "unlink", path: path48 });
2016
2016
  },
2017
- async readdir(path43) {
2018
- return base.readdir(path43);
2017
+ async readdir(path48) {
2018
+ return base.readdir(path48);
2019
2019
  }
2020
2020
  };
2021
2021
  if (typeof base.rm === "function") {
2022
- proxy.rm = async (path43, options) => {
2023
- recorder.record({ type: "rm", path: path43, options });
2022
+ proxy.rm = async (path48, options) => {
2023
+ recorder.record({ type: "rm", path: path48, options });
2024
2024
  };
2025
2025
  }
2026
2026
  if (typeof base.copyFile === "function") {
@@ -2110,8 +2110,8 @@ function describeWriteChange(previous, next) {
2110
2110
  }
2111
2111
  return "update";
2112
2112
  }
2113
- function renderWriteCommand(path43, change) {
2114
- const command = `cat > ${path43}`;
2113
+ function renderWriteCommand(path48, change) {
2114
+ const command = `cat > ${path48}`;
2115
2115
  if (change === "create") {
2116
2116
  return renderOperationCommand(command, chalk.green, "# create");
2117
2117
  }
@@ -2273,9 +2273,9 @@ function redactTomlLine(line) {
2273
2273
  }
2274
2274
  return line;
2275
2275
  }
2276
- async function tryReadText(base, path43) {
2276
+ async function tryReadText(base, path48) {
2277
2277
  try {
2278
- return await base.readFile(path43, "utf8");
2278
+ return await base.readFile(path48, "utf8");
2279
2279
  } catch (error2) {
2280
2280
  if (isNotFound(error2)) {
2281
2281
  return null;
@@ -2756,7 +2756,7 @@ function toTomlInlineTable(values) {
2756
2756
  return `{${parts.join(", ")}}`;
2757
2757
  }
2758
2758
  function serializeJsonMcpArgs(servers) {
2759
- return ["--mcp-servers", JSON.stringify({ mcpServers: toJsonMcpServers(servers) })];
2759
+ return ["--mcp-config", JSON.stringify({ mcpServers: toJsonMcpServers(servers) })];
2760
2760
  }
2761
2761
  function serializeOpenCodeMcpEnv(servers) {
2762
2762
  const mcp = {};
@@ -3404,6 +3404,9 @@ function resolveOutputFormat(env = process.env) {
3404
3404
  cached = VALID_FORMATS.has(raw) ? raw : "terminal";
3405
3405
  return cached;
3406
3406
  }
3407
+ function withOutputFormat(format, fn) {
3408
+ return formatStorage.run(format, fn);
3409
+ }
3407
3410
  function resetOutputFormatCache() {
3408
3411
  cached = void 0;
3409
3412
  }
@@ -7362,6 +7365,7 @@ function renderUsage(tokens) {
7362
7365
  );
7363
7366
  return;
7364
7367
  }
7368
+ process.stdout.write("\n");
7365
7369
  writeLine(chalk8.green(`\u2713 tokens: ${tokens.input} in${cached2} \u2192 ${tokens.output} out${cost}`));
7366
7370
  }
7367
7371
  function renderError(message2) {
@@ -7751,6 +7755,14 @@ async function text3(opts) {
7751
7755
  async function confirm2(opts) {
7752
7756
  return clack.confirm(opts);
7753
7757
  }
7758
+ async function confirmOrCancel(opts) {
7759
+ const result = await confirm2(opts);
7760
+ if (Ct(result)) {
7761
+ cancel("Operation cancelled.");
7762
+ throw new PromptCancelledError();
7763
+ }
7764
+ return result === true;
7765
+ }
7754
7766
  async function password2(opts) {
7755
7767
  return clack.password(opts);
7756
7768
  }
@@ -7817,6 +7829,7 @@ async function withSpinner(options) {
7817
7829
  throw error2;
7818
7830
  }
7819
7831
  }
7832
+ var PromptCancelledError;
7820
7833
  var init_prompts = __esm({
7821
7834
  "packages/design-system/src/prompts/index.ts"() {
7822
7835
  "use strict";
@@ -7828,6 +7841,15 @@ var init_prompts = __esm({
7828
7841
  init_note();
7829
7842
  init_outro();
7830
7843
  init_spinner2();
7844
+ PromptCancelledError = class extends Error {
7845
+ constructor(message2 = "Operation cancelled.") {
7846
+ super(message2);
7847
+ this.name = "PromptCancelledError";
7848
+ if (Error.captureStackTrace) {
7849
+ Error.captureStackTrace(this, this.constructor);
7850
+ }
7851
+ }
7852
+ };
7831
7853
  }
7832
7854
  });
7833
7855
 
@@ -8088,21 +8110,21 @@ async function* adaptClaude(lines) {
8088
8110
  if (blockType !== "tool_result") continue;
8089
8111
  const kind = toolKindsById.get(item.tool_use_id);
8090
8112
  toolKindsById.delete(item.tool_use_id);
8091
- let path43;
8113
+ let path48;
8092
8114
  if (typeof item.content === "string") {
8093
- path43 = item.content;
8115
+ path48 = item.content;
8094
8116
  } else {
8095
8117
  try {
8096
- path43 = JSON.stringify(item.content);
8118
+ path48 = JSON.stringify(item.content);
8097
8119
  } catch {
8098
- path43 = String(item.content);
8120
+ path48 = String(item.content);
8099
8121
  }
8100
8122
  }
8101
8123
  yield {
8102
8124
  event: "tool_complete",
8103
8125
  id: item.tool_use_id,
8104
8126
  kind,
8105
- path: path43
8127
+ path: path48
8106
8128
  };
8107
8129
  }
8108
8130
  }
@@ -8225,10 +8247,10 @@ async function* adaptCodex(lines) {
8225
8247
  const kindFromStart = toolKindById.get(item.id);
8226
8248
  const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
8227
8249
  const titleFromEvent = isNonEmptyString(item.path) ? item.path : itemType === "mcp_tool_call" ? `${isNonEmptyString(item.server) ? item.server : "unknown"}.${isNonEmptyString(item.tool) ? item.tool : "unknown"}` : void 0;
8228
- const path43 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
8250
+ const path48 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
8229
8251
  toolTitleById.delete(item.id);
8230
8252
  toolKindById.delete(item.id);
8231
- yield { event: "tool_complete", id: item.id, kind, path: path43 };
8253
+ yield { event: "tool_complete", id: item.id, kind, path: path48 };
8232
8254
  }
8233
8255
  }
8234
8256
  }
@@ -9132,6 +9154,10 @@ var init_acp_transport = __esm({
9132
9154
  this.child.stderr.on("data", (chunk) => {
9133
9155
  this.stderrChunks.push(String(chunk));
9134
9156
  });
9157
+ this.child.stdin.on("error", (error2) => {
9158
+ const reason = error2 instanceof Error ? error2 : new Error(String(error2));
9159
+ this.close(reason, this.child.exitCode ?? null, this.child.signalCode ?? null);
9160
+ });
9135
9161
  this.layer = new JsonRpcMessageLayer({
9136
9162
  input: this.child.stdout,
9137
9163
  output: this.child.stdin,
@@ -9236,8 +9262,8 @@ function resourceNotFound(resource) {
9236
9262
  `Resource not found: ${resource}`
9237
9263
  );
9238
9264
  }
9239
- function assertAbsolutePath(path43) {
9240
- if (!isAbsolute(path43)) {
9265
+ function assertAbsolutePath(path48) {
9266
+ if (!isAbsolute(path48)) {
9241
9267
  throw invalidParams('"path" must be an absolute path');
9242
9268
  }
9243
9269
  }
@@ -9370,19 +9396,24 @@ var init_acp_client = __esm({
9370
9396
  this.permissionHandler = options.handlers?.permission ?? options.permissionHandler;
9371
9397
  this.fsHandler = options.handlers?.fs ?? options.fsHandler;
9372
9398
  this.terminalHandler = options.handlers?.terminal ?? options.terminalHandler;
9399
+ const autoApprove = options.autoApprove === true && !this.permissionHandler;
9373
9400
  this.transport.onRequest(
9374
9401
  "session/request_permission",
9375
9402
  async (params) => {
9376
- if (!this.permissionHandler) {
9377
- return {
9378
- outcome: { outcome: "cancelled" }
9379
- };
9403
+ if (this.permissionHandler) {
9404
+ const outcome = await this.permissionHandler({
9405
+ toolCall: params.toolCall,
9406
+ options: params.options
9407
+ });
9408
+ return { outcome };
9380
9409
  }
9381
- const outcome = await this.permissionHandler({
9382
- toolCall: params.toolCall,
9383
- options: params.options
9384
- });
9385
- return { outcome };
9410
+ if (autoApprove) {
9411
+ const allow = params.options.find((o) => o.kind === "allow_always") ?? params.options.find((o) => o.kind === "allow_once");
9412
+ if (allow) {
9413
+ return { outcome: { outcome: "selected", optionId: allow.optionId } };
9414
+ }
9415
+ }
9416
+ return { outcome: { outcome: "cancelled" } };
9386
9417
  }
9387
9418
  );
9388
9419
  this.registerCapabilityHandlers(this.clientCapabilities);
@@ -10002,13 +10033,19 @@ function toToolTitle(title, locations) {
10002
10033
  }
10003
10034
  function toToolOutput(value) {
10004
10035
  if (typeof value === "string") return value;
10005
- if (value === void 0) return "";
10036
+ if (value === void 0 || value === null) return "";
10006
10037
  try {
10007
10038
  return JSON.stringify(value);
10008
10039
  } catch {
10009
10040
  return String(value);
10010
10041
  }
10011
10042
  }
10043
+ function extractToolOutputText(update) {
10044
+ const raw = toToolOutput(update.rawOutput);
10045
+ if (raw) return raw;
10046
+ if (!update.content) return "";
10047
+ return update.content.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("");
10048
+ }
10012
10049
  function toEventsFromSessionUpdate(notification, state) {
10013
10050
  const update = notification.params.update;
10014
10051
  if (update.sessionUpdate === "agent_message_chunk" && update.content.type === "text") {
@@ -10081,7 +10118,7 @@ function toEventsFromSessionUpdate(notification, state) {
10081
10118
  events.push({
10082
10119
  event: "tool_complete",
10083
10120
  kind: renderKind,
10084
- path: toToolOutput(update.rawOutput),
10121
+ path: extractToolOutputText(update),
10085
10122
  id: update.toolCallId
10086
10123
  });
10087
10124
  }
@@ -10089,6 +10126,15 @@ function toEventsFromSessionUpdate(notification, state) {
10089
10126
  }
10090
10127
  return [];
10091
10128
  }
10129
+ function toAcpMcpServers(servers) {
10130
+ if (!servers) return [];
10131
+ return Object.entries(servers).map(([name, server]) => ({
10132
+ name,
10133
+ command: server.command,
10134
+ args: server.args ?? [],
10135
+ env: server.env ? Object.entries(server.env).map(([k2, v]) => ({ name: k2, value: v })) : []
10136
+ }));
10137
+ }
10092
10138
  function createAbortError3() {
10093
10139
  const error2 = new Error("Agent spawn aborted");
10094
10140
  error2.name = "AbortError";
@@ -10119,7 +10165,8 @@ function spawnAcp(options) {
10119
10165
  cwd: options.cwd ?? process.cwd(),
10120
10166
  env,
10121
10167
  requestTimeoutMs: 3e5,
10122
- skipAuth: acpConfig.skipAuth ?? false
10168
+ skipAuth: acpConfig.skipAuth ?? false,
10169
+ autoApprove: (options.mode ?? "yolo") === "yolo"
10123
10170
  });
10124
10171
  let aborted = false;
10125
10172
  const onAbort = () => {
@@ -10134,6 +10181,7 @@ function spawnAcp(options) {
10134
10181
  };
10135
10182
  let sessionId = "";
10136
10183
  let assistantText = "";
10184
+ let lastToolOutput = "";
10137
10185
  const eventQueue = [];
10138
10186
  const waiters = [];
10139
10187
  let eventsDone = false;
@@ -10176,7 +10224,7 @@ function spawnAcp(options) {
10176
10224
  if (initResult.authMethods && initResult.authMethods.length > 0 && client.state !== "ready") {
10177
10225
  await client.authenticate(initResult.authMethods[0].id);
10178
10226
  }
10179
- const session = await client.newSession(options.cwd ?? process.cwd(), []);
10227
+ const session = await client.newSession(options.cwd ?? process.cwd(), toAcpMcpServers(options.mcpServers));
10180
10228
  sessionId = session.sessionId;
10181
10229
  pushEvent({ event: "session_start", threadId: sessionId });
10182
10230
  const turn = client.prompt(sessionId, [{ type: "text", text: options.prompt }]);
@@ -10187,6 +10235,12 @@ function spawnAcp(options) {
10187
10235
  assistantText += update.content.text;
10188
10236
  }
10189
10237
  for (const event of toEventsFromSessionUpdate(notification, toolState)) {
10238
+ if (event.event === "tool_complete") {
10239
+ const output = event.path;
10240
+ if (output) {
10241
+ lastToolOutput = output;
10242
+ }
10243
+ }
10190
10244
  pushEvent(event);
10191
10245
  }
10192
10246
  }
@@ -10194,8 +10248,9 @@ function spawnAcp(options) {
10194
10248
  const stopReason = promptResponse.stopReason;
10195
10249
  const meta = promptResponse._meta ?? {};
10196
10250
  const metaUsage = meta.usage;
10251
+ const responseText = assistantText || lastToolOutput;
10197
10252
  return {
10198
- stdout: assistantText.length > 0 ? `${assistantText}
10253
+ stdout: responseText.length > 0 ? `${responseText}
10199
10254
  ` : "",
10200
10255
  stderr: "",
10201
10256
  exitCode: stopReason === "completed" || stopReason === "end_turn" ? 0 : 1,
@@ -10320,7 +10375,7 @@ function updateSessionFromEvent(ctx, event, toolCallsById) {
10320
10375
  }
10321
10376
  const id = readString(event.id);
10322
10377
  const kind = readString(event.kind);
10323
- const path43 = readString(event.path);
10378
+ const path48 = readString(event.path);
10324
10379
  let toolCall = id ? toolCallsById.get(id) : void 0;
10325
10380
  if (!toolCall) {
10326
10381
  toolCall = {};
@@ -10335,8 +10390,8 @@ function updateSessionFromEvent(ctx, event, toolCallsById) {
10335
10390
  if (kind) {
10336
10391
  toolCall.kind = kind;
10337
10392
  }
10338
- if (path43) {
10339
- toolCall.path = path43;
10393
+ if (path48) {
10394
+ toolCall.path = path48;
10340
10395
  }
10341
10396
  }
10342
10397
  var sessionCapture;
@@ -10611,7 +10666,26 @@ function createCheckRunner(resources) {
10611
10666
  };
10612
10667
  }
10613
10668
  function listIsolatedServiceIds(container) {
10614
- return container.registry.list().filter((provider2) => Boolean(provider2.isolatedEnv)).map((provider2) => provider2.name);
10669
+ return listServiceNames(
10670
+ container.registry.list().filter((provider2) => Boolean(provider2.isolatedEnv))
10671
+ );
10672
+ }
10673
+ function listServiceNames(services) {
10674
+ const names = [];
10675
+ const add = (value) => {
10676
+ const normalized = value?.trim();
10677
+ if (!normalized || names.includes(normalized)) {
10678
+ return;
10679
+ }
10680
+ names.push(normalized);
10681
+ };
10682
+ for (const service of services) {
10683
+ add(service.name);
10684
+ for (const alias of service.aliases ?? []) {
10685
+ add(alias);
10686
+ }
10687
+ }
10688
+ return names;
10615
10689
  }
10616
10690
  function resolveServiceAdapter(container, service) {
10617
10691
  const adapter = container.registry.get(service);
@@ -10806,14 +10880,14 @@ function parseDockerLocator(input) {
10806
10880
  throw new Error(`Invalid docker workspace locator "${input}".`);
10807
10881
  }
10808
10882
  const container = input.slice(0, slashIndex);
10809
- const path43 = input.slice(slashIndex);
10810
- if (container.length === 0 || path43.length === 0) {
10883
+ const path48 = input.slice(slashIndex);
10884
+ if (container.length === 0 || path48.length === 0) {
10811
10885
  throw new Error(`Invalid docker workspace locator "${input}".`);
10812
10886
  }
10813
10887
  return {
10814
10888
  scheme: "docker",
10815
10889
  container,
10816
- path: path43
10890
+ path: path48
10817
10891
  };
10818
10892
  }
10819
10893
  function splitOnce(input, separator) {
@@ -12690,21 +12764,21 @@ function createSdkContainer(options) {
12690
12764
  });
12691
12765
  loggerFactory.setErrorLogger(errorLogger);
12692
12766
  const asyncFs = {
12693
- readFile: ((path43, encoding) => {
12767
+ readFile: ((path48, encoding) => {
12694
12768
  if (encoding) {
12695
- return fs2.readFile(path43, encoding);
12769
+ return fs2.readFile(path48, encoding);
12696
12770
  }
12697
- return fs2.readFile(path43);
12771
+ return fs2.readFile(path48);
12698
12772
  }),
12699
- writeFile: (path43, data, opts) => fs2.writeFile(path43, data, opts),
12700
- mkdir: (path43, opts) => fs2.mkdir(path43, opts).then(() => {
12773
+ writeFile: (path48, data, opts) => fs2.writeFile(path48, data, opts),
12774
+ mkdir: (path48, opts) => fs2.mkdir(path48, opts).then(() => {
12701
12775
  }),
12702
- stat: (path43) => fs2.stat(path43),
12703
- rm: (path43, opts) => fs2.rm(path43, opts),
12704
- unlink: (path43) => fs2.unlink(path43),
12705
- readdir: (path43) => fs2.readdir(path43),
12776
+ stat: (path48) => fs2.stat(path48),
12777
+ rm: (path48, opts) => fs2.rm(path48, opts),
12778
+ unlink: (path48) => fs2.unlink(path48),
12779
+ readdir: (path48) => fs2.readdir(path48),
12706
12780
  copyFile: (src, dest) => fs2.copyFile(src, dest),
12707
- chmod: (path43, mode) => fs2.chmod(path43, mode)
12781
+ chmod: (path48, mode) => fs2.chmod(path48, mode)
12708
12782
  };
12709
12783
  const contextFactory = createCommandContextFactory({ fs: asyncFs });
12710
12784
  const authFs = {
@@ -13337,11 +13411,11 @@ function createDefaultFs() {
13337
13411
  readFile: fsPromises2.readFile,
13338
13412
  readdir: fsPromises2.readdir,
13339
13413
  stat: async (filePath) => {
13340
- const stat13 = await fsPromises2.stat(filePath);
13414
+ const stat14 = await fsPromises2.stat(filePath);
13341
13415
  return {
13342
- isFile: () => stat13.isFile(),
13343
- isDirectory: () => stat13.isDirectory(),
13344
- mtimeMs: stat13.mtimeMs
13416
+ isFile: () => stat14.isFile(),
13417
+ isDirectory: () => stat14.isDirectory(),
13418
+ mtimeMs: stat14.mtimeMs
13345
13419
  };
13346
13420
  }
13347
13421
  };
@@ -13368,8 +13442,8 @@ function countCompletedTasks(planPath, content) {
13368
13442
  async function ensurePlanExists(fs3, cwd, planPath) {
13369
13443
  const absolutePath = path15.isAbsolute(planPath) ? planPath : path15.resolve(cwd, planPath);
13370
13444
  try {
13371
- const stat13 = await fs3.stat(absolutePath);
13372
- if (!stat13.isFile()) {
13445
+ const stat14 = await fs3.stat(absolutePath);
13446
+ if (!stat14.isFile()) {
13373
13447
  throw new Error(`Plan not found at "${planPath}".`);
13374
13448
  }
13375
13449
  } catch (error2) {
@@ -13395,8 +13469,8 @@ async function scanPlansDir(fs3, plansDir, displayPrefix) {
13395
13469
  continue;
13396
13470
  }
13397
13471
  const absolutePath = path15.join(plansDir, entry);
13398
- const stat13 = await fs3.stat(absolutePath);
13399
- if (!stat13.isFile()) {
13472
+ const stat14 = await fs3.stat(absolutePath);
13473
+ if (!stat14.isFile()) {
13400
13474
  continue;
13401
13475
  }
13402
13476
  const displayPath = path15.join(displayPrefix, entry);
@@ -13438,8 +13512,8 @@ async function resolvePlanDirectory(options) {
13438
13512
  const fs3 = options.fs ?? createDefaultFs();
13439
13513
  const projectDir = path15.join(options.cwd, ".poe-code");
13440
13514
  try {
13441
- const stat13 = await fs3.stat(projectDir);
13442
- if (stat13.isDirectory()) {
13515
+ const stat14 = await fs3.stat(projectDir);
13516
+ if (stat14.isDirectory()) {
13443
13517
  return path15.join(options.cwd, ".poe-code", "pipeline", "plans");
13444
13518
  }
13445
13519
  } catch {
@@ -13654,11 +13728,11 @@ function createDefaultFs2() {
13654
13728
  },
13655
13729
  rmdir: fsPromises3.rmdir,
13656
13730
  stat: async (filePath) => {
13657
- const stat13 = await fsPromises3.stat(filePath);
13731
+ const stat14 = await fsPromises3.stat(filePath);
13658
13732
  return {
13659
- isFile: () => stat13.isFile(),
13660
- isDirectory: () => stat13.isDirectory(),
13661
- mtimeMs: stat13.mtimeMs
13733
+ isFile: () => stat14.isFile(),
13734
+ isDirectory: () => stat14.isDirectory(),
13735
+ mtimeMs: stat14.mtimeMs
13662
13736
  };
13663
13737
  }
13664
13738
  };
@@ -13691,8 +13765,8 @@ async function lockFile(filePath, options = {}) {
13691
13765
  if (!error2 || typeof error2 !== "object" || !("code" in error2) || error2.code !== "EEXIST") {
13692
13766
  throw error2;
13693
13767
  }
13694
- const stat13 = await fs3.stat(lockPath);
13695
- if (Date.now() - stat13.mtimeMs > staleMs) {
13768
+ const stat14 = await fs3.stat(lockPath);
13769
+ if (Date.now() - stat14.mtimeMs > staleMs) {
13696
13770
  await fs3.rmdir(lockPath);
13697
13771
  continue;
13698
13772
  }
@@ -13718,11 +13792,11 @@ function createDefaultFs3() {
13718
13792
  writeFile: fsPromises4.writeFile,
13719
13793
  readdir: fsPromises4.readdir,
13720
13794
  stat: async (filePath) => {
13721
- const stat13 = await fsPromises4.stat(filePath);
13795
+ const stat14 = await fsPromises4.stat(filePath);
13722
13796
  return {
13723
- isFile: () => stat13.isFile(),
13724
- isDirectory: () => stat13.isDirectory(),
13725
- mtimeMs: stat13.mtimeMs
13797
+ isFile: () => stat14.isFile(),
13798
+ isDirectory: () => stat14.isDirectory(),
13799
+ mtimeMs: stat14.mtimeMs
13726
13800
  };
13727
13801
  },
13728
13802
  mkdir: async (filePath, options) => {
@@ -14184,8 +14258,8 @@ async function removeDirectory2(fs3, directoryPath) {
14184
14258
  }
14185
14259
  for (const entry of entries) {
14186
14260
  const entryPath = path18.join(directoryPath, entry);
14187
- const stat13 = await fs3.stat(entryPath);
14188
- if (stat13.isFile()) {
14261
+ const stat14 = await fs3.stat(entryPath);
14262
+ if (stat14.isFile()) {
14189
14263
  await fs3.rm(entryPath, { force: true });
14190
14264
  continue;
14191
14265
  }
@@ -14231,8 +14305,8 @@ function createStateStore(stateDir, fs3 = nodeFs2) {
14231
14305
  for (const entry of [...entries].sort()) {
14232
14306
  const entryPath = path18.join(stateDir, entry);
14233
14307
  try {
14234
- const stat13 = await fs3.stat(entryPath);
14235
- if (stat13.isFile()) {
14308
+ const stat14 = await fs3.stat(entryPath);
14309
+ if (stat14.isFile()) {
14236
14310
  continue;
14237
14311
  }
14238
14312
  } catch (error2) {
@@ -15638,8 +15712,8 @@ async function listIds(fs3, baseDir) {
15638
15712
  for (const entry of entries) {
15639
15713
  const entryPath = path22.join(baseDir, entry);
15640
15714
  try {
15641
- const stat13 = await fs3.stat(entryPath);
15642
- if (!stat13.isFile()) {
15715
+ const stat14 = await fs3.stat(entryPath);
15716
+ if (!stat14.isFile()) {
15643
15717
  ids.push(entry);
15644
15718
  }
15645
15719
  } catch (error2) {
@@ -15892,10 +15966,10 @@ function createDefaultFs4() {
15892
15966
  return {
15893
15967
  readdir: fsPromises5.readdir,
15894
15968
  stat: async (filePath) => {
15895
- const stat13 = await fsPromises5.stat(filePath);
15969
+ const stat14 = await fsPromises5.stat(filePath);
15896
15970
  return {
15897
- isFile: () => stat13.isFile(),
15898
- mtimeMs: stat13.mtimeMs
15971
+ isFile: () => stat14.isFile(),
15972
+ mtimeMs: stat14.mtimeMs
15899
15973
  };
15900
15974
  }
15901
15975
  };
@@ -15922,8 +15996,8 @@ async function scanDir(fs3, absoluteDir, displayDir) {
15922
15996
  continue;
15923
15997
  }
15924
15998
  const absolutePath = path23.join(absoluteDir, entry);
15925
- const stat13 = await fs3.stat(absolutePath);
15926
- if (!stat13.isFile()) {
15999
+ const stat14 = await fs3.stat(absolutePath);
16000
+ if (!stat14.isFile()) {
15927
16001
  continue;
15928
16002
  }
15929
16003
  const displayPath = path23.join(displayDir, entry);
@@ -16096,10 +16170,10 @@ function createDefaultFs5() {
16096
16170
  writeFile: (filePath, content) => fsPromises6.writeFile(filePath, content, "utf8"),
16097
16171
  readdir: fsPromises6.readdir,
16098
16172
  stat: async (filePath) => {
16099
- const stat13 = await fsPromises6.stat(filePath);
16173
+ const stat14 = await fsPromises6.stat(filePath);
16100
16174
  return {
16101
- isFile: () => stat13.isFile(),
16102
- mtimeMs: stat13.mtimeMs
16175
+ isFile: () => stat14.isFile(),
16176
+ mtimeMs: stat14.mtimeMs
16103
16177
  };
16104
16178
  },
16105
16179
  mkdir: async (filePath, options) => {
@@ -16626,10 +16700,10 @@ function createDefaultFs6() {
16626
16700
  writeFile: (filePath, content) => fsPromises7.writeFile(filePath, content, "utf8"),
16627
16701
  readdir: fsPromises7.readdir,
16628
16702
  stat: async (filePath) => {
16629
- const stat13 = await fsPromises7.stat(filePath);
16703
+ const stat14 = await fsPromises7.stat(filePath);
16630
16704
  return {
16631
- isFile: () => stat13.isFile(),
16632
- mtimeMs: stat13.mtimeMs
16705
+ isFile: () => stat14.isFile(),
16706
+ mtimeMs: stat14.mtimeMs
16633
16707
  };
16634
16708
  },
16635
16709
  mkdir: async (filePath, options) => {
@@ -16947,10 +17021,10 @@ function createDefaultFs7() {
16947
17021
  },
16948
17022
  readdir: fsPromises8.readdir,
16949
17023
  stat: async (filePath) => {
16950
- const stat13 = await fsPromises8.stat(filePath);
17024
+ const stat14 = await fsPromises8.stat(filePath);
16951
17025
  return {
16952
- isFile: () => stat13.isFile(),
16953
- mtimeMs: stat13.mtimeMs
17026
+ isFile: () => stat14.isFile(),
17027
+ mtimeMs: stat14.mtimeMs
16954
17028
  };
16955
17029
  },
16956
17030
  mkdir: async (filePath, options) => {
@@ -18564,11 +18638,11 @@ var init_commands = __esm({
18564
18638
  description: "Run a GitHub automation.",
18565
18639
  positional: ["name"],
18566
18640
  params: S.Object({
18567
- name: S.Optional(S.String()),
18568
- agent: S.Optional(S.String()),
18569
- model: S.Optional(S.String()),
18570
- mode: S.Optional(S.Enum(["yolo", "edit", "read"])),
18571
- cwd: S.Optional(S.String())
18641
+ name: S.Optional(S.String({ description: "Automation name to run" })),
18642
+ agent: S.Optional(S.String({ description: "Agent to run the automation with" })),
18643
+ model: S.Optional(S.String({ description: "Model override for the agent" })),
18644
+ mode: S.Optional(S.Enum(["yolo", "edit", "read"], { description: "Permission mode (yolo | edit | read)" })),
18645
+ cwd: S.Optional(S.String({ description: "Working directory for the automation" }))
18572
18646
  }),
18573
18647
  secrets: {
18574
18648
  poeApiKey: { env: "POE_API_KEY" },
@@ -23880,11 +23954,11 @@ function formatSegment(segment, casing) {
23880
23954
  const separator = casing === "snake" ? "_" : "-";
23881
23955
  return splitWords(segment).join(separator);
23882
23956
  }
23883
- function toOptionFlag(path43, casing) {
23884
- return `--${path43.map((segment) => formatSegment(segment, casing)).join(".")}`;
23957
+ function toOptionFlag(path48, casing) {
23958
+ return `--${path48.map((segment) => formatSegment(segment, casing)).join(".")}`;
23885
23959
  }
23886
- function toOptionAttribute(path43, casing) {
23887
- return path43.map((segment) => {
23960
+ function toOptionAttribute(path48, casing) {
23961
+ return path48.map((segment) => {
23888
23962
  const formatted = formatSegment(segment, casing);
23889
23963
  if (casing === "snake") {
23890
23964
  return formatted;
@@ -23895,13 +23969,13 @@ function toOptionAttribute(path43, casing) {
23895
23969
  ).join("");
23896
23970
  }).join(".");
23897
23971
  }
23898
- function toDisplayPath(path43) {
23899
- return path43.join(".");
23972
+ function toDisplayPath(path48) {
23973
+ return path48.join(".");
23900
23974
  }
23901
- function collectFields(schema, casing, path43 = [], inheritedOptional = false) {
23975
+ function collectFields(schema, casing, path48 = [], inheritedOptional = false) {
23902
23976
  const fields = [];
23903
23977
  for (const [key, rawChildSchema] of Object.entries(schema.shape)) {
23904
- const nextPath = [...path43, key];
23978
+ const nextPath = [...path48, key];
23905
23979
  const optional = inheritedOptional || rawChildSchema.kind === "optional";
23906
23980
  const childSchema = unwrapOptional(rawChildSchema);
23907
23981
  if (childSchema.kind === "object") {
@@ -23924,9 +23998,9 @@ function collectFields(schema, casing, path43 = [], inheritedOptional = false) {
23924
23998
  }
23925
23999
  return fields;
23926
24000
  }
23927
- function toCommanderOptionAttribute(path43, casing) {
23928
- const optionAttribute = toOptionAttribute(path43, casing);
23929
- const optionFlag = toOptionFlag(path43, casing);
24001
+ function toCommanderOptionAttribute(path48, casing) {
24002
+ const optionAttribute = toOptionAttribute(path48, casing);
24003
+ const optionFlag = toOptionFlag(path48, casing);
23930
24004
  if (!GLOBAL_LONG_OPTION_FLAGS.has(optionFlag)) {
23931
24005
  return optionAttribute;
23932
24006
  }
@@ -24117,8 +24191,8 @@ function findVisibleChild(group, token, scope) {
24117
24191
  (child) => child.name === token || child.aliases.includes(token)
24118
24192
  );
24119
24193
  }
24120
- function resolveHelpTarget(root, argv, scope) {
24121
- const breadcrumb = [root.name];
24194
+ function resolveHelpTarget(root, argv, scope, rootDisplayName) {
24195
+ const breadcrumb = [rootDisplayName ?? root.name];
24122
24196
  let current = root;
24123
24197
  for (const token of argv.slice(2)) {
24124
24198
  if (token.startsWith("-") || token === "help") {
@@ -24209,7 +24283,7 @@ function formatCommandRows(group, scope) {
24209
24283
  function formatGlobalOptionRows(showVersion) {
24210
24284
  const rows = [
24211
24285
  {
24212
- flags: "--preset",
24286
+ flags: "--preset <path>",
24213
24287
  description: "Load parameter defaults from a JSON file"
24214
24288
  },
24215
24289
  {
@@ -24217,11 +24291,11 @@ function formatGlobalOptionRows(showVersion) {
24217
24291
  description: "Accept defaults, skip prompts"
24218
24292
  },
24219
24293
  {
24220
- flags: "--output",
24294
+ flags: "--output <format>",
24221
24295
  description: "Output format (rich, md, json)"
24222
24296
  },
24223
24297
  {
24224
- flags: "--help",
24298
+ flags: "-h, --help",
24225
24299
  description: "Show help"
24226
24300
  }
24227
24301
  ];
@@ -24236,7 +24310,14 @@ function formatGlobalOptionRows(showVersion) {
24236
24310
  function renderHelpSections(sections) {
24237
24311
  return sections.filter((section) => section.length > 0).join("\n\n");
24238
24312
  }
24239
- function renderGroupHelp(group, breadcrumb, scope, showVersion) {
24313
+ function buildUsageLine(breadcrumb, rootUsageName, suffix) {
24314
+ if (rootUsageName === void 0) {
24315
+ return void 0;
24316
+ }
24317
+ const subPath = breadcrumb.slice(1).join(" ");
24318
+ return subPath ? `${rootUsageName} ${subPath} ${suffix}` : `${rootUsageName} ${suffix}`;
24319
+ }
24320
+ function renderGroupHelp(group, breadcrumb, scope, showVersion, rootUsageName) {
24240
24321
  const sections = [];
24241
24322
  const commandRows = formatCommandRows(group, scope);
24242
24323
  if (commandRows.length > 0) {
@@ -24247,12 +24328,13 @@ ${formatCommandList(commandRows)}`);
24247
24328
  ${formatOptionList(formatGlobalOptionRows(showVersion))}`);
24248
24329
  return renderHelpDocument({
24249
24330
  breadcrumb,
24331
+ usageLine: buildUsageLine(breadcrumb, rootUsageName, "[options] [command]"),
24250
24332
  description: group.description,
24251
24333
  requiresAuth: group.requires?.auth === true,
24252
24334
  sections
24253
24335
  });
24254
24336
  }
24255
- function renderLeafHelp(command, breadcrumb, casing) {
24337
+ function renderLeafHelp(command, breadcrumb, casing, rootUsageName) {
24256
24338
  const sections = [];
24257
24339
  const fields = assignPositionals(collectFields(command.params, casing), command.positional);
24258
24340
  const optionRows = fields.map((field) => ({
@@ -24270,8 +24352,11 @@ ${formatOptionList(formatGlobalOptionRows(false))}`);
24270
24352
  sections.push(`${text.section("Secrets (via environment):")}
24271
24353
  ${formatOptionList(secretRows)}`);
24272
24354
  }
24355
+ const positionalFields = fields.filter((f) => f.positionalIndex !== void 0);
24356
+ const usageSuffix = positionalFields.length > 0 ? `[options] ${positionalFields.map(formatPositionalToken).join(" ")}` : "[options]";
24273
24357
  return renderHelpDocument({
24274
24358
  breadcrumb,
24359
+ usageLine: buildUsageLine(breadcrumb, rootUsageName, usageSuffix),
24275
24360
  description: command.description,
24276
24361
  requiresAuth: command.requires?.auth === true,
24277
24362
  sections
@@ -24279,11 +24364,14 @@ ${formatOptionList(secretRows)}`);
24279
24364
  }
24280
24365
  function renderHelpDocument(input) {
24281
24366
  const lines = [text.heading(input.breadcrumb.join(" ")), ""];
24367
+ if (input.usageLine !== void 0) {
24368
+ lines.push(`${text.section("Usage:")} ${text.usageCommand(input.usageLine)}`, "");
24369
+ }
24282
24370
  if (input.description !== void 0) {
24283
- lines.push(` ${input.description}`);
24371
+ lines.push(input.description);
24284
24372
  }
24285
24373
  if (input.requiresAuth) {
24286
- lines.push(" Requires: authentication");
24374
+ lines.push("Requires: authentication");
24287
24375
  }
24288
24376
  if (input.description !== void 0 || input.requiresAuth) {
24289
24377
  lines.push("");
@@ -24293,11 +24381,11 @@ function renderHelpDocument(input) {
24293
24381
  `;
24294
24382
  }
24295
24383
  async function renderGeneratedHelp(root, argv, options) {
24296
- const target = resolveHelpTarget(root, argv, "cli");
24384
+ const target = resolveHelpTarget(root, argv, "cli", options.rootDisplayName);
24297
24385
  const output = resolveHelpOutput(argv);
24298
24386
  const casing = options.casing ?? "kebab";
24299
24387
  await withOutputFormat2(output, async () => {
24300
- const rendered = target.node.kind === "group" ? renderGroupHelp(target.node, target.breadcrumb, "cli", options.version !== void 0) : renderLeafHelp(target.node, target.breadcrumb, casing);
24388
+ const rendered = target.node.kind === "group" ? renderGroupHelp(target.node, target.breadcrumb, "cli", options.version !== void 0, options.rootUsageName) : renderLeafHelp(target.node, target.breadcrumb, casing, options.rootUsageName);
24301
24389
  process.stdout.write(rendered);
24302
24390
  });
24303
24391
  }
@@ -24360,10 +24448,10 @@ function addGlobalOptions(command) {
24360
24448
  throw new InvalidArgumentError('Invalid value for "--output". Expected one of: rich, md, json.');
24361
24449
  }).option("--verbose", "Print stack traces for unexpected errors.");
24362
24450
  }
24363
- function setNestedValue(target, path43, value) {
24451
+ function setNestedValue(target, path48, value) {
24364
24452
  let cursor = target;
24365
- for (let index = 0; index < path43.length - 1; index += 1) {
24366
- const segment = path43[index] ?? "";
24453
+ for (let index = 0; index < path48.length - 1; index += 1) {
24454
+ const segment = path48[index] ?? "";
24367
24455
  const existing = cursor[segment];
24368
24456
  if (typeof existing === "object" && existing !== null) {
24369
24457
  cursor = existing;
@@ -24373,7 +24461,7 @@ function setNestedValue(target, path43, value) {
24373
24461
  cursor[segment] = next;
24374
24462
  cursor = next;
24375
24463
  }
24376
- const leaf = path43[path43.length - 1];
24464
+ const leaf = path48[path48.length - 1];
24377
24465
  if (leaf !== void 0) {
24378
24466
  cursor[leaf] = value;
24379
24467
  }
@@ -24463,13 +24551,13 @@ async function withOutputFormat2(output, fn) {
24463
24551
  }
24464
24552
  function createFs() {
24465
24553
  return {
24466
- readFile: async (path43, encoding = "utf8") => readFile12(path43, { encoding }),
24467
- writeFile: async (path43, contents) => {
24468
- await writeFile7(path43, contents);
24554
+ readFile: async (path48, encoding = "utf8") => readFile12(path48, { encoding }),
24555
+ writeFile: async (path48, contents) => {
24556
+ await writeFile7(path48, contents);
24469
24557
  },
24470
- exists: async (path43) => {
24558
+ exists: async (path48) => {
24471
24559
  try {
24472
- await access2(path43);
24560
+ await access2(path48);
24473
24561
  return true;
24474
24562
  } catch {
24475
24563
  return false;
@@ -24490,9 +24578,9 @@ function isPlainObject(value) {
24490
24578
  function hasFieldValue(value) {
24491
24579
  return value !== void 0;
24492
24580
  }
24493
- function hasNestedField(fields, path43) {
24581
+ function hasNestedField(fields, path48) {
24494
24582
  return fields.some(
24495
- (field) => path43.length < field.path.length && path43.every((segment, index) => field.path[index] === segment)
24583
+ (field) => path48.length < field.path.length && path48.every((segment, index) => field.path[index] === segment)
24496
24584
  );
24497
24585
  }
24498
24586
  function describeExpectedPresetValue(schema) {
@@ -24576,9 +24664,9 @@ async function loadPresetValues(fields, presetPath) {
24576
24664
  }
24577
24665
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
24578
24666
  const presetValues = {};
24579
- function visitObject(current, path43) {
24667
+ function visitObject(current, path48) {
24580
24668
  for (const [key, value] of Object.entries(current)) {
24581
- const nextPath = [...path43, key];
24669
+ const nextPath = [...path48, key];
24582
24670
  const displayPath = toDisplayPath(nextPath);
24583
24671
  const field = fieldByPath.get(displayPath);
24584
24672
  if (field !== void 0) {
@@ -25462,9 +25550,9 @@ var init_config3 = __esm({
25462
25550
 
25463
25551
  // src/cli/commands/configure.ts
25464
25552
  function registerConfigureCommand(program, container) {
25465
- const serviceNames = container.registry.list().map((service) => service.name);
25553
+ const serviceNames = listServiceNames(container.registry.list());
25466
25554
  const serviceDescription = `Agent to configure${formatServiceList(serviceNames)}`;
25467
- const configureCommand = program.command("configure").alias("c").description("Configure developer tooling for Poe API.").argument("[agent]", serviceDescription).option("--api-key <key>", "Poe API key").option("--model <model>", "Model identifier").option("--reasoning-effort <level>", "Reasoning effort level").action(async (service, options) => {
25555
+ const configureCommand = program.command("configure").alias("c").description("Configure developer tooling for Poe API.").argument("[agent]", serviceDescription).option("-y, --yes", "Accept defaults, skip prompts").option("--api-key <key>", "Poe API key").option("--model <model>", "Model identifier").option("--reasoning-effort <level>", "Reasoning effort level").action(async (service, options) => {
25468
25556
  const resolved = await resolveServiceArgument(program, container, service, {
25469
25557
  action: "configure"
25470
25558
  });
@@ -25689,12 +25777,13 @@ var init_agent2 = __esm({
25689
25777
  });
25690
25778
 
25691
25779
  // src/cli/commands/spawn.ts
25780
+ import { Option as Option2 } from "commander";
25692
25781
  function registerSpawnCommand(program, container, options = {}) {
25693
- const spawnServices = container.registry.list().filter((service) => typeof service.spawn === "function" || getSpawnConfig(service.name)).map((service) => service.name);
25782
+ const spawnServices = container.registry.list().filter((service) => typeof service.spawn === "function" || getSpawnConfig(service.name));
25694
25783
  const extraServices = options.extraServices ?? [];
25695
- const serviceList = [...spawnServices, ...extraServices];
25784
+ const serviceList = listSpawnServiceNames(spawnServices, extraServices);
25696
25785
  const serviceDescription = `Agent to spawn${formatServiceList(serviceList)}`;
25697
- program.command("spawn").alias("s").description("Run a single prompt through a configured agent CLI.").option("--model <model>", "Model identifier override passed to the agent CLI").option("-C, --cwd <path>", "Working directory or workspace locator for the agent CLI").option("--stdin", "Read the prompt from stdin").option("-i, --interactive", "Launch the agent in interactive TUI mode").option("--mode <mode>", "Permission mode: yolo | edit | read (default: yolo)").option("--mcp-servers <json>", "MCP server config JSON: {name: {command, args?, env?}}").option("--mcp-config <json>", "[deprecated: use --mcp-servers]").option("--log-dir <path>", "Directory override for ACP JSONL spawn logs").option(
25786
+ program.command("spawn").alias("s").description("Run a single prompt through a configured agent CLI.").option("--model <model>", "Model identifier override passed to the agent CLI").option("-C, --cwd <path>", "Working directory or workspace locator for the agent CLI").option("--stdin", "Read the prompt from stdin").option("-i, --interactive", "Launch the agent in interactive TUI mode").option("--mode <mode>", "Permission mode: yolo | edit | read (default: yolo)").option("--mcp-servers <json>", "MCP server config JSON: {name: {command, args?, env?}}").addOption(new Option2("--mcp-config <json>", "[deprecated: use --mcp-servers]").hideHelp()).option("--log-dir <path>", "Directory override for ACP JSONL spawn logs").option(
25698
25787
  "--activity-timeout-ms <ms>",
25699
25788
  "Kill the agent after N ms of inactivity",
25700
25789
  (value) => parsePositiveInt(value, "--activity-timeout-ms")
@@ -25887,8 +25976,6 @@ function registerSpawnCommand(program, container, options = {}) {
25887
25976
  const trimmedStderr = final.stderr.trim();
25888
25977
  if (trimmedStderr) {
25889
25978
  resources.logger.info(renderMarkdown(trimmedStderr).trimEnd());
25890
- } else {
25891
- resources.logger.info(`${adapter.label} spawn completed.`);
25892
25979
  }
25893
25980
  }
25894
25981
  }
@@ -25913,6 +26000,26 @@ Resume: ${resumeCommand}`));
25913
26000
  }
25914
26001
  });
25915
26002
  }
26003
+ function listSpawnServiceNames(services, extraServices) {
26004
+ const names = [];
26005
+ const add = (value) => {
26006
+ const normalized = value?.trim();
26007
+ if (!normalized || names.includes(normalized)) {
26008
+ return;
26009
+ }
26010
+ names.push(normalized);
26011
+ };
26012
+ for (const service of services) {
26013
+ add(service.name);
26014
+ for (const alias of service.aliases ?? []) {
26015
+ add(alias);
26016
+ }
26017
+ }
26018
+ for (const service of extraServices) {
26019
+ add(service);
26020
+ }
26021
+ return names;
26022
+ }
25916
26023
  async function confirmUnconfiguredService(container, service, label, flags) {
25917
26024
  const configuredServices = await loadConfiguredServices({
25918
26025
  fs: container.fs,
@@ -26283,7 +26390,7 @@ var init_login = __esm({
26283
26390
 
26284
26391
  // src/cli/commands/unconfigure.ts
26285
26392
  function registerUnconfigureCommand(program, container) {
26286
- const serviceNames = container.registry.list().map((service) => service.name);
26393
+ const serviceNames = listServiceNames(container.registry.list());
26287
26394
  const serviceDescription = `Agent to unconfigure${formatServiceList(serviceNames)}`;
26288
26395
  return program.command("unconfigure").alias("uc").description("Remove existing Poe API tooling configuration.").argument("<agent>", serviceDescription).action(async (service, options) => {
26289
26396
  await executeUnconfigure(program, container, service, options);
@@ -26400,7 +26507,7 @@ var init_unconfigure = __esm({
26400
26507
 
26401
26508
  // src/cli/commands/logout.ts
26402
26509
  function registerLogoutCommand(program, container) {
26403
- program.command("logout").description("Remove all Poe API configuration.").action(async () => {
26510
+ program.command("logout").description("Remove all configuration and credentials.").action(async () => {
26404
26511
  await executeLogout(program, container);
26405
26512
  });
26406
26513
  }
@@ -26456,10 +26563,13 @@ function registerAuthCommand(program, container) {
26456
26563
  auth.command("status").description("Show login status.").action(async () => {
26457
26564
  await executeStatus(program, container);
26458
26565
  });
26459
- auth.command("api_key").description("Display stored API key.").action(async () => {
26566
+ auth.command("api-key").description("Display stored API key.").action(async () => {
26567
+ await executeApiKey(program, container);
26568
+ });
26569
+ auth.command("api_key", { hidden: true }).action(async () => {
26460
26570
  await executeApiKey(program, container);
26461
26571
  });
26462
- auth.command("login").description("Store a Poe API key.").option("--api-key <key>", "Poe API key").action(async (options) => {
26572
+ auth.command("login").description("Store a Poe API key for reuse across commands.").option("--api-key <key>", "Poe API key").action(async (options) => {
26463
26573
  await executeLogin(program, container, options);
26464
26574
  });
26465
26575
  auth.command("logout").description("Remove all configuration and credentials.").action(async () => {
@@ -26657,7 +26767,7 @@ var init_config4 = __esm({
26657
26767
 
26658
26768
  // src/cli/commands/utils.ts
26659
26769
  function registerUtilsCommand(program, container) {
26660
- const utils = program.command("utils").description("Utility commands for inspecting and managing poe-code.");
26770
+ const utils = program.command("utils").description("Utility commands for inspecting and managing poe-code.").addHelpCommand(false);
26661
26771
  registerConfigCommand(utils, container);
26662
26772
  }
26663
26773
  var init_utils3 = __esm({
@@ -26669,8 +26779,8 @@ var init_utils3 = __esm({
26669
26779
 
26670
26780
  // src/cli/commands/install.ts
26671
26781
  function registerInstallCommand(program, container) {
26672
- const serviceNames = container.registry.list().filter((service) => typeof service.install === "function").map((service) => service.name);
26673
- const serviceDescription = `Agent to install${formatServiceList(serviceNames)}`;
26782
+ const serviceNames = container.registry.list().filter((service) => typeof service.install === "function");
26783
+ const serviceDescription = `Agent to install${formatServiceList(listServiceNames(serviceNames))}`;
26674
26784
  return program.command("install").alias("i").description("Install agent binary for a configured agent.").argument(
26675
26785
  "[agent]",
26676
26786
  serviceDescription
@@ -26722,8 +26832,8 @@ var init_install = __esm({
26722
26832
 
26723
26833
  // src/cli/commands/test.ts
26724
26834
  function registerTestCommand(program, container) {
26725
- const serviceNames = container.registry.list().filter((service) => typeof service.test === "function").map((service) => service.name);
26726
- const serviceDescription = `Agent to test${formatServiceList(serviceNames)}`;
26835
+ const serviceNames = container.registry.list().filter((service) => typeof service.test === "function");
26836
+ const serviceDescription = `Agent to test${formatServiceList(listServiceNames(serviceNames))}`;
26727
26837
  return program.command("test").description("Run agent health checks.").argument(
26728
26838
  "[agent]",
26729
26839
  serviceDescription
@@ -26865,7 +26975,7 @@ var init_media_download = __esm({
26865
26975
  // src/cli/commands/generate.ts
26866
26976
  import path37 from "node:path";
26867
26977
  function registerGenerateCommand(program, container) {
26868
- const generate2 = program.command("generate").alias("g").description("Generate content via Poe API").option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
26978
+ const generate2 = program.command("generate").alias("g").description("Generate content via Poe API.").option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
26869
26979
  "--param <key=value>",
26870
26980
  "Additional parameters (repeatable)",
26871
26981
  collectParam,
@@ -26896,7 +27006,7 @@ function registerGenerateCommand(program, container) {
26896
27006
  }
26897
27007
  outro("");
26898
27008
  });
26899
- generate2.command("text").description(`Generate text (default model: ${DEFAULT_TEXT_MODEL})`).option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
27009
+ generate2.command("text").description("Generate text content.").option("--model <model>", `Model identifier (default: ${DEFAULT_TEXT_MODEL})`).option(
26900
27010
  "--param <key=value>",
26901
27011
  "Additional parameters (repeatable)",
26902
27012
  collectParam,
@@ -26933,7 +27043,7 @@ function registerGenerateCommand(program, container) {
26933
27043
  }
26934
27044
  function registerMediaSubcommand(generate2, program, container, type) {
26935
27045
  const defaultModel = DEFAULT_MODELS2[type];
26936
- generate2.command(type).description(`Generate ${type} (default model: ${defaultModel})`).option("--model <model>", `Model identifier (default: ${defaultModel})`).option(
27046
+ generate2.command(type).description(`Generate ${type} content.`).option("--model <model>", `Model identifier (default: ${defaultModel})`).option(
26937
27047
  "--param <key=value>",
26938
27048
  "Additional parameters (repeatable)",
26939
27049
  collectParam,
@@ -28617,14 +28727,12 @@ function buildHelpText() {
28617
28727
  const lines = [
28618
28728
  "",
28619
28729
  "Configuration:",
28620
- JSON.stringify({ [server.name]: server.config }, null, 2),
28621
- "",
28622
- formatMcpToolsDocs()
28730
+ JSON.stringify({ [server.name]: server.config }, null, 2)
28623
28731
  ];
28624
28732
  return lines.join("\n");
28625
28733
  }
28626
28734
  function registerMcpCommand(program, container) {
28627
- const mcp = program.command("mcp").description("MCP server commands").addHelpText("after", buildHelpText()).allowExcessArguments().action(function() {
28735
+ const mcp = program.command("mcp").description("MCP server commands.").addHelpText("after", buildHelpText()).allowExcessArguments().action(function() {
28628
28736
  if (this.args.length > 0) {
28629
28737
  throwCommandNotFound({
28630
28738
  container,
@@ -28636,13 +28744,15 @@ function registerMcpCommand(program, container) {
28636
28744
  }
28637
28745
  this.help();
28638
28746
  });
28639
- mcp.command("serve").description("Run MCP server on stdin/stdout").option(
28747
+ mcp.command("serve").description("Run MCP server on stdin/stdout.").option(
28640
28748
  "--output-format <format>",
28641
28749
  'Preferred MCP media output format(s): "url", "base64", "markdown", or comma-separated list (default: "url"). Note: "markdown" cannot be combined with other formats.'
28642
- ).addHelpText("after", buildHelpText()).action(async (options) => {
28750
+ ).addHelpText("after", `${buildHelpText()}
28751
+
28752
+ ${formatMcpToolsDocs()}`).action(async (options) => {
28643
28753
  await runMcpServer(container, { outputFormat: options.outputFormat });
28644
28754
  });
28645
- mcp.command("configure [agent]").description("Configure MCP client to use poe-code").option("-y, --yes", "Skip prompt, use claude-code").action(async (agentArg, options) => {
28755
+ mcp.command("configure").description("Configure MCP client to use poe-code.").argument("[agent]", `Agent to configure (${supportedAgents.join(" | ")})`).option("-y, --yes", "Accept defaults, skip prompts").action(async (agentArg, options) => {
28646
28756
  const flags = resolveCommandFlags(program);
28647
28757
  const resources = createExecutionResources(container, flags, "mcp");
28648
28758
  const existingKey = await container.readApiKey();
@@ -28702,7 +28812,7 @@ function registerMcpCommand(program, container) {
28702
28812
  });
28703
28813
  resources.context.finalize();
28704
28814
  });
28705
- mcp.command("unconfigure <agent>").description("Remove poe-code from MCP client").action(async (agent2) => {
28815
+ mcp.command("unconfigure").description("Remove poe-code from MCP client.").argument("<agent>", `Agent to unconfigure (${supportedAgents.join(" | ")})`).action(async (agent2) => {
28706
28816
  const flags = resolveCommandFlags(program);
28707
28817
  const resources = createExecutionResources(container, flags, "mcp");
28708
28818
  resources.logger.intro(`mcp unconfigure ${agent2}`);
@@ -28810,23 +28920,24 @@ var init_configs3 = __esm({
28810
28920
  }
28811
28921
  });
28812
28922
 
28923
+ // packages/agent-skill-config/src/templates/poe-generate.md
28924
+ var poe_generate_default;
28925
+ var init_poe_generate = __esm({
28926
+ "packages/agent-skill-config/src/templates/poe-generate.md"() {
28927
+ poe_generate_default = '---\nname: poe-generate\ndescription: \'Poe code generation skill\'\n---\n\n# poe-code generate\n\nUse `poe-code generate` to create text, images, audio, or video via the Poe API.\n\n## Text generation\n\n```bash\npoe-code generate "Write a short function that parses a JSON string safely."\n```\n\nSpecify the model/bot:\n\n```bash\n# CLI option\npoe-code generate --model "gpt-4.1" "Summarize this codebase change."\n\n# Some agent runtimes call the model selector `--bot`\npoe-code generate --bot "gpt-4.1" "Summarize this codebase change."\n```\n\n## Media generation\n\nThe CLI supports media generation as subcommands:\n\n```bash\npoe-code generate image "A 3D render of a rubber duck wearing sunglasses" --model "gpt-image-1" -o duck.png\npoe-code generate video "A cinematic timelapse of a city at night" --model "veo" -o city.mp4\npoe-code generate audio "A calm 10 second lo-fi beat" --model "audio-model" -o beat.wav\n```\n\nSome agent runtimes expose the same media types as flags. If available, these are equivalent:\n\n```bash\npoe-code generate --image "A 3D render of a rubber duck wearing sunglasses" --bot "gpt-image-1" -o duck.png\npoe-code generate --video "A cinematic timelapse of a city at night" --bot "veo" -o city.mp4\npoe-code generate --audio "A calm 10 second lo-fi beat" --bot "audio-model" -o beat.wav\n```\n\n## Tips\n\n- Use `--param key=value` to pass provider/model parameters (repeatable).\n- Use `--output <path>` (or `-o`) for media outputs.\n';
28928
+ }
28929
+ });
28930
+
28931
+ // packages/agent-skill-config/src/templates/terminal-pilot.md
28932
+ var terminal_pilot_default;
28933
+ var init_terminal_pilot = __esm({
28934
+ "packages/agent-skill-config/src/templates/terminal-pilot.md"() {
28935
+ terminal_pilot_default = "---\nname: terminal-pilot\ndescription: 'Terminal automation skill using the terminal-pilot CLI'\n---\n\n# Terminal Pilot\n\nUse the `terminal-pilot` CLI when you need to automate or inspect interactive\nCLI applications through a real PTY session.\n\n## Commands\n\n- `terminal-pilot create-session` - start a PTY-backed command\n- `terminal-pilot fill` - paste text into a session\n- `terminal-pilot type` - type character-by-character for TUIs and readline\n- `terminal-pilot press-key` - send named keys such as `Enter` or `ArrowDown`\n- `terminal-pilot wait-for` - wait for terminal output to match a pattern\n- `terminal-pilot wait-for-exit` - block until a session exits\n- `terminal-pilot read-screen` - inspect the current visible terminal screen\n- `terminal-pilot read-history` - read scrollback output\n- `terminal-pilot list-sessions` - list active sessions\n- `terminal-pilot close-session` - close a session and return its exit code\n\n## Examples\n\n```bash\nterminal-pilot --help\nterminal-pilot create-session --help\nterminal-pilot read-screen --help\n```\n\nUse JSON output when another tool or script needs to read the result:\n\n```bash\nterminal-pilot list-sessions --output json\nterminal-pilot read-screen --session s1 --output json\n```\n\n## Tips\n\n- Use `fill` for pasted text and multi-line input.\n- Use `type` when the app reacts to individual keystrokes.\n- Use `press-key` for Enter, Tab, arrow keys, Escape, and control-key chords.\n- Use `wait-for --literal` for exact string matching.\n- Default terminal size is 120x40.\n";
28936
+ }
28937
+ });
28938
+
28813
28939
  // packages/agent-skill-config/src/templates.ts
28814
- import { readFile as readFile13 } from "node:fs/promises";
28815
- async function getTemplates() {
28816
- if (templatesCache) {
28817
- return templatesCache;
28818
- }
28819
- const entries = await Promise.all(
28820
- TEMPLATE_NAMES.map(async (name) => {
28821
- const url = new URL(`./templates/${name}`, import.meta.url);
28822
- return [name, await readFile13(url, "utf8")];
28823
- })
28824
- );
28825
- templatesCache = Object.fromEntries(entries);
28826
- return templatesCache;
28827
- }
28828
28940
  async function loadTemplate2(templateId) {
28829
- const templates = await getTemplates();
28830
28941
  const template = templates[templateId];
28831
28942
  if (!template) {
28832
28943
  throw new Error(`Template not found: ${templateId}`);
@@ -28836,12 +28947,16 @@ async function loadTemplate2(templateId) {
28836
28947
  function createTemplateLoader() {
28837
28948
  return loadTemplate2;
28838
28949
  }
28839
- var TEMPLATE_NAMES, templatesCache;
28950
+ var templates;
28840
28951
  var init_templates = __esm({
28841
28952
  "packages/agent-skill-config/src/templates.ts"() {
28842
28953
  "use strict";
28843
- TEMPLATE_NAMES = ["poe-generate.md", "terminal-pilot.md"];
28844
- templatesCache = null;
28954
+ init_poe_generate();
28955
+ init_terminal_pilot();
28956
+ templates = {
28957
+ "poe-generate.md": poe_generate_default,
28958
+ "terminal-pilot.md": terminal_pilot_default
28959
+ };
28845
28960
  }
28846
28961
  });
28847
28962
 
@@ -28976,16 +29091,8 @@ var init_src22 = __esm({
28976
29091
  });
28977
29092
 
28978
29093
  // src/cli/commands/skill.ts
28979
- function buildHelpText2() {
28980
- return [
28981
- "",
28982
- "Skill directories:",
28983
- "- poe-code skill configure installs skill directories for supported agents.",
28984
- "- poe-code skill unconfigure removes skill directories."
28985
- ].join("\n");
28986
- }
28987
29094
  function registerSkillCommand(program, container) {
28988
- const skill = program.command("skill").description("Skill directory commands").addHelpText("after", buildHelpText2()).allowExcessArguments().action(function() {
29095
+ const skill = program.command("skill").description("Skill directory commands.").allowExcessArguments().action(function() {
28989
29096
  if (this.args.length > 0) {
28990
29097
  throwCommandNotFound({
28991
29098
  container,
@@ -28997,14 +29104,14 @@ function registerSkillCommand(program, container) {
28997
29104
  }
28998
29105
  this.help();
28999
29106
  });
29000
- skill.command("configure [agent]").description("Install skill directories for an agent").option("--agent <name>", "Agent to configure skills for").option("--local", "Use local scope (in the current project)").option("--global", "Use global scope (in the user home directory)").action(async (agentArg, options) => {
29107
+ skill.command("configure").description("Install skill directories for an agent.").argument("[agent]", `Agent to configure skills for (${supportedAgents2.join(" | ")})`).option("-y, --yes", "Accept defaults, skip prompts").option("--local", "Use local scope (in the current project)").option("--global", "Use global scope (in the user home directory)").action(async (agentArg, options) => {
29001
29108
  const flags = resolveCommandFlags(program);
29002
29109
  const resources = createExecutionResources(container, flags, "skill");
29003
29110
  if (options.local && options.global) {
29004
29111
  resources.logger.error("Use either --local or --global, not both.");
29005
29112
  return;
29006
29113
  }
29007
- let agent2 = options.agent ?? agentArg;
29114
+ let agent2 = agentArg;
29008
29115
  if (!agent2) {
29009
29116
  if (flags.assumeYes) {
29010
29117
  agent2 = DEFAULT_SKILL_AGENT;
@@ -29079,14 +29186,14 @@ function registerSkillCommand(program, container) {
29079
29186
  });
29080
29187
  resources.context.finalize();
29081
29188
  });
29082
- skill.command("unconfigure [agent]").description("Remove skill directories for an agent").option("--agent <name>", "Agent to unconfigure skills for").option("--local", "Use local scope (in the current project)").option("--global", "Use global scope (in the user home directory)").option("--force", "Remove directory even if it contains files").action(async (agentArg, options) => {
29189
+ skill.command("unconfigure").description("Remove skill directories for an agent.").argument("[agent]", `Agent to unconfigure skills for (${supportedAgents2.join(" | ")})`).option("--local", "Use local scope (in the current project)").option("--global", "Use global scope (in the user home directory)").option("--force", "Remove directory even if it contains files").action(async (agentArg, options) => {
29083
29190
  const flags = resolveCommandFlags(program);
29084
29191
  const resources = createExecutionResources(container, flags, "skill");
29085
29192
  if (options.local && options.global) {
29086
29193
  resources.logger.error("Use either --local or --global, not both.");
29087
29194
  return;
29088
29195
  }
29089
- let agent2 = options.agent ?? agentArg;
29196
+ let agent2 = agentArg;
29090
29197
  if (!agent2) {
29091
29198
  const selected = await select2({
29092
29199
  message: "Select agent to unconfigure:",
@@ -29375,7 +29482,7 @@ function registerUsageCommand(program, container) {
29375
29482
  const usage = program.command("usage").alias("u").description("Check Poe API usage information.").action(async () => {
29376
29483
  await executeBalance(program, container);
29377
29484
  });
29378
- usage.command("balance").description("Display current point balance.").action(async () => {
29485
+ usage.command("balance", { hidden: true }).description("Display current point balance.").action(async () => {
29379
29486
  await executeBalance(program, container);
29380
29487
  });
29381
29488
  usage.command("list").description("Display usage history.").option("--filter <model>", "Filter results by model name").option("--pages <count>", "Number of pages to load automatically", parseInt).action(async function() {
@@ -29862,7 +29969,7 @@ var init_models2 = __esm({
29862
29969
 
29863
29970
  // src/cli/commands/pipeline.ts
29864
29971
  import path40 from "node:path";
29865
- import { readFile as readFile14, stat as stat11 } from "node:fs/promises";
29972
+ import { readFile as readFile13, stat as stat11 } from "node:fs/promises";
29866
29973
  import { fileURLToPath as fileURLToPath7 } from "node:url";
29867
29974
  async function resolvePipelinePlanDirectory(container) {
29868
29975
  const configDoc = await readMergedDocument(
@@ -29932,8 +30039,8 @@ async function loadPipelineTemplates() {
29932
30039
  continue;
29933
30040
  }
29934
30041
  const [skillPlan, steps] = await Promise.all([
29935
- readFile14(path40.join(templateRoot, "SKILL_plan.md"), "utf8"),
29936
- readFile14(path40.join(templateRoot, "steps.yaml.hbs"), "utf8")
30042
+ readFile13(path40.join(templateRoot, "SKILL_plan.md"), "utf8"),
30043
+ readFile13(path40.join(templateRoot, "steps.yaml.hbs"), "utf8")
29937
30044
  ]);
29938
30045
  pipelineTemplatesCache = { skillPlan, steps };
29939
30046
  return pipelineTemplatesCache;
@@ -29976,8 +30083,8 @@ async function pathExists3(fs3, targetPath) {
29976
30083
  }
29977
30084
  }
29978
30085
  function registerPipelineCommand(program, container) {
29979
- const pipeline = program.command("pipeline").description("Run a fixed-step task pipeline plan.");
29980
- pipeline.command("run").description("Run the selected pipeline plan until completion, failure, cancellation, or cap.").option("--agent <name>", "Agent to run each pipeline step with").option("--model <model>", "Model override passed to the agent").option("--task <id>", "Run only the specified task").option("--plan <path>", "Path to the pipeline plan file").option("--max-runs <n>", "Maximum number of agent executions to perform").action(async function() {
30086
+ const pipeline = program.command("pipeline").description("Run a fixed-step task pipeline plan.").addHelpCommand(false);
30087
+ pipeline.command("run").description("Run the selected pipeline plan until completion, failure, cancellation, or max runs.").option("--agent <name>", "Agent to run each pipeline step with").option("--model <model>", "Model override passed to the agent").option("--task <id>", "Run only the specified task").option("--plan <path>", "Path to the pipeline plan file").option("--max-runs <n>", "Maximum number of agent executions to perform").action(async function() {
29981
30088
  const flags = resolveCommandFlags(program);
29982
30089
  const resources = createExecutionResources(
29983
30090
  container,
@@ -30267,12 +30374,12 @@ function registerPipelineCommand(program, container) {
30267
30374
  scope = selected;
30268
30375
  }
30269
30376
  resources.logger.intro(`pipeline install (${support.id}, ${scope})`);
30270
- const templates = await loadPipelineTemplates();
30377
+ const templates2 = await loadPipelineTemplates();
30271
30378
  const skillResult = await installSkill(
30272
30379
  support.id,
30273
30380
  {
30274
30381
  name: "poe-code-pipeline-plan",
30275
- content: templates.skillPlan
30382
+ content: templates2.skillPlan
30276
30383
  },
30277
30384
  {
30278
30385
  fs: container.fs,
@@ -30313,7 +30420,7 @@ function registerPipelineCommand(program, container) {
30313
30420
  await container.fs.mkdir(path40.dirname(pipelinePaths.stepsPath), {
30314
30421
  recursive: true
30315
30422
  });
30316
- await container.fs.writeFile(pipelinePaths.stepsPath, templates.steps, {
30423
+ await container.fs.writeFile(pipelinePaths.stepsPath, templates2.steps, {
30317
30424
  encoding: "utf8"
30318
30425
  });
30319
30426
  resources.logger.info(
@@ -30348,8 +30455,828 @@ var init_pipeline3 = __esm({
30348
30455
  }
30349
30456
  });
30350
30457
 
30351
- // src/cli/commands/ralph.ts
30458
+ // packages/plan-browser/src/format.ts
30352
30459
  import path41 from "node:path";
30460
+ function isPipelineTaskDone(task) {
30461
+ if (typeof task.status === "string") {
30462
+ return task.status === "done";
30463
+ }
30464
+ return Object.values(task.status).every((status) => status === "done");
30465
+ }
30466
+ function formatPipelineProgress(content) {
30467
+ const plan = parsePlan(content);
30468
+ const done = plan.tasks.filter((task) => isPipelineTaskDone(task)).length;
30469
+ return `${done}/${plan.tasks.length} done`;
30470
+ }
30471
+ function formatRalphDetail(frontmatter) {
30472
+ const parts = [];
30473
+ if (frontmatter.agent !== void 0) {
30474
+ parts.push(Array.isArray(frontmatter.agent) ? frontmatter.agent.join(", ") : frontmatter.agent);
30475
+ }
30476
+ if (frontmatter.iterations !== void 0) {
30477
+ parts.push(`\xD7${frontmatter.iterations}`);
30478
+ }
30479
+ if (frontmatter.status.state !== "open" || frontmatter.status.iteration > 0) {
30480
+ parts.push(`${frontmatter.status.state} ${frontmatter.status.iteration}`);
30481
+ } else {
30482
+ parts.push("open");
30483
+ }
30484
+ return parts.join(" \xB7 ");
30485
+ }
30486
+ function formatExperimentDetail(frontmatter, state) {
30487
+ const parts = [];
30488
+ if (frontmatter.agent !== void 0) {
30489
+ parts.push(Array.isArray(frontmatter.agent) ? frontmatter.agent.join(", ") : frontmatter.agent);
30490
+ }
30491
+ const metrics = frontmatter.metric === void 0 ? [] : Array.isArray(frontmatter.metric) ? frontmatter.metric : [frontmatter.metric];
30492
+ if (metrics.length > 0) {
30493
+ const directions = Array.from(new Set(metrics.map((metric) => metric.direction)));
30494
+ parts.push(directions.join("/"));
30495
+ }
30496
+ parts.push(state);
30497
+ return parts.join(" \xB7 ");
30498
+ }
30499
+ function getLastExperimentState(journalContent) {
30500
+ const lines = journalContent.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
30501
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
30502
+ try {
30503
+ const parsed = JSON.parse(lines[index]);
30504
+ if (typeof parsed.status === "string" && parsed.status.length > 0) {
30505
+ return parsed.status;
30506
+ }
30507
+ } catch {
30508
+ continue;
30509
+ }
30510
+ }
30511
+ return "open";
30512
+ }
30513
+ function deriveMarkdownTitle(content, fallbackName) {
30514
+ const heading = content.split("\n").map((line) => line.trim()).find((line) => line.startsWith("# "));
30515
+ return heading ? heading.slice(2).trim() || fallbackName : fallbackName;
30516
+ }
30517
+ function formatPipelineTaskDetails(task) {
30518
+ if (typeof task.status === "string") {
30519
+ return null;
30520
+ }
30521
+ const entries = Object.entries(task.status).map(([name, status]) => `${name}=${status}`);
30522
+ return entries.length > 0 ? `Step status: ${entries.join(", ")}` : null;
30523
+ }
30524
+ function formatPipelinePlanMarkdown(options) {
30525
+ const plan = parsePlan(options.content);
30526
+ const lines = [
30527
+ `# ${options.title}`,
30528
+ "",
30529
+ `Status: ${formatPipelineProgress(options.content)}`,
30530
+ "",
30531
+ "## Tasks",
30532
+ ""
30533
+ ];
30534
+ for (const task of plan.tasks) {
30535
+ const mark = isPipelineTaskDone(task) ? "x" : " ";
30536
+ lines.push(`- [${mark}] ${task.title} (\`${task.id}\`)`);
30537
+ const detail = formatPipelineTaskDetails(task);
30538
+ if (detail) {
30539
+ lines.push(` - ${detail}`);
30540
+ }
30541
+ for (const promptLine of task.prompt.split("\n")) {
30542
+ lines.push(` > ${promptLine}`);
30543
+ }
30544
+ lines.push("");
30545
+ }
30546
+ return lines.join("\n").trimEnd();
30547
+ }
30548
+ function resolveExperimentJournalPath(absolutePath) {
30549
+ return path41.join(
30550
+ path41.dirname(absolutePath),
30551
+ `${path41.basename(absolutePath, path41.extname(absolutePath))}.journal.jsonl`
30552
+ );
30553
+ }
30554
+ async function readExperimentState(fs3, absolutePath) {
30555
+ try {
30556
+ const content = await fs3.readFile(resolveExperimentJournalPath(absolutePath), "utf8");
30557
+ return getLastExperimentState(content);
30558
+ } catch {
30559
+ return "open";
30560
+ }
30561
+ }
30562
+ async function loadPlanPreviewMarkdown(entry, fs3) {
30563
+ const content = await fs3.readFile(entry.absolutePath, "utf8");
30564
+ if (entry.source === "pipeline") {
30565
+ return formatPipelinePlanMarkdown({
30566
+ title: entry.title,
30567
+ content
30568
+ });
30569
+ }
30570
+ return content;
30571
+ }
30572
+ async function readPlanMetadata(options) {
30573
+ const content = await options.fs.readFile(options.absolutePath, "utf8");
30574
+ const fallbackName = path41.basename(options.path);
30575
+ if (options.source === "pipeline") {
30576
+ return {
30577
+ title: fallbackName,
30578
+ status: formatPipelineProgress(content),
30579
+ format: "yaml"
30580
+ };
30581
+ }
30582
+ if (options.source === "ralph") {
30583
+ const parsed2 = parseFrontmatter(content);
30584
+ return {
30585
+ title: deriveMarkdownTitle(parsed2.body, fallbackName),
30586
+ status: formatRalphDetail(parsed2.data),
30587
+ format: "markdown"
30588
+ };
30589
+ }
30590
+ const parsed = parseExperimentFrontmatter(content);
30591
+ const state = await readExperimentState(options.fs, options.absolutePath);
30592
+ return {
30593
+ title: deriveMarkdownTitle(parsed.body, fallbackName),
30594
+ status: formatExperimentDetail(parsed.frontmatter, state),
30595
+ format: "markdown"
30596
+ };
30597
+ }
30598
+ var init_format = __esm({
30599
+ "packages/plan-browser/src/format.ts"() {
30600
+ "use strict";
30601
+ init_src10();
30602
+ init_src14();
30603
+ init_src13();
30604
+ }
30605
+ });
30606
+
30607
+ // packages/plan-browser/src/discovery.ts
30608
+ import path42 from "node:path";
30609
+ import * as fsPromises10 from "node:fs/promises";
30610
+ function createDefaultFs8() {
30611
+ return {
30612
+ readFile: fsPromises10.readFile,
30613
+ writeFile: fsPromises10.writeFile,
30614
+ readdir: fsPromises10.readdir,
30615
+ stat: async (filePath) => {
30616
+ const stat14 = await fsPromises10.stat(filePath);
30617
+ return {
30618
+ isFile: () => stat14.isFile(),
30619
+ isDirectory: () => stat14.isDirectory(),
30620
+ mtimeMs: stat14.mtimeMs
30621
+ };
30622
+ },
30623
+ mkdir: async (directoryPath, mkdirOptions) => {
30624
+ await fsPromises10.mkdir(directoryPath, mkdirOptions);
30625
+ },
30626
+ rename: fsPromises10.rename,
30627
+ unlink: fsPromises10.unlink
30628
+ };
30629
+ }
30630
+ function isNotFound4(error2) {
30631
+ return !!error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT";
30632
+ }
30633
+ function resolveAbsoluteDirectory3(dir, cwd, homeDir) {
30634
+ if (dir.startsWith("~/")) {
30635
+ return path42.join(homeDir, dir.slice(2));
30636
+ }
30637
+ return path42.isAbsolute(dir) ? dir : path42.resolve(cwd, dir);
30638
+ }
30639
+ function resolveAbsoluteDisplayPath(displayPath, cwd, homeDir) {
30640
+ if (displayPath.startsWith("~/")) {
30641
+ return path42.join(homeDir, displayPath.slice(2));
30642
+ }
30643
+ return path42.isAbsolute(displayPath) ? displayPath : path42.resolve(cwd, displayPath);
30644
+ }
30645
+ function isPipelinePlanFile(name) {
30646
+ const lower = name.toLowerCase();
30647
+ return lower.startsWith("plan") && (lower.endsWith(".yaml") || lower.endsWith(".yml"));
30648
+ }
30649
+ function isMarkdownFile2(name) {
30650
+ return name.toLowerCase().endsWith(".md");
30651
+ }
30652
+ async function resolvePlanDirectorySetting(options) {
30653
+ const envValue = options.variables?.[options.envName]?.trim();
30654
+ if (envValue) {
30655
+ return envValue;
30656
+ }
30657
+ const document = await readMergedDocument(
30658
+ options.fs,
30659
+ options.configPath,
30660
+ options.projectConfigPath
30661
+ );
30662
+ const configured = document[options.scope]?.plan_directory;
30663
+ return typeof configured === "string" && configured.trim().length > 0 ? configured.trim() : void 0;
30664
+ }
30665
+ async function scanDirectory(options) {
30666
+ let entries;
30667
+ try {
30668
+ entries = await options.fs.readdir(options.absoluteDir);
30669
+ } catch (error2) {
30670
+ if (isNotFound4(error2)) {
30671
+ return [];
30672
+ }
30673
+ throw error2;
30674
+ }
30675
+ const plans = [];
30676
+ for (const name of entries) {
30677
+ if (!options.include(name)) {
30678
+ continue;
30679
+ }
30680
+ const absolutePath = path42.join(options.absoluteDir, name);
30681
+ const stat14 = await options.fs.stat(absolutePath);
30682
+ if (!stat14.isFile()) {
30683
+ continue;
30684
+ }
30685
+ const displayPath = path42.join(options.displayDir, name);
30686
+ const metadata = await readPlanMetadata({
30687
+ source: options.source,
30688
+ absolutePath,
30689
+ path: displayPath,
30690
+ fs: options.fs
30691
+ });
30692
+ plans.push({
30693
+ path: displayPath,
30694
+ absolutePath: resolveAbsoluteDisplayPath(displayPath, options.cwd, options.homeDir),
30695
+ source: options.source,
30696
+ format: metadata.format,
30697
+ title: metadata.title,
30698
+ status: metadata.status,
30699
+ updatedAt: stat14.mtimeMs
30700
+ });
30701
+ }
30702
+ return plans;
30703
+ }
30704
+ async function discoverPipelinePlans(options) {
30705
+ const configuredDir = await resolvePlanDirectorySetting({
30706
+ fs: options.fs,
30707
+ configPath: options.configPath,
30708
+ projectConfigPath: options.projectConfigPath,
30709
+ scope: "pipeline",
30710
+ envName: "POE_PIPELINE_PLAN_DIRECTORY",
30711
+ variables: options.variables
30712
+ });
30713
+ const targets = configuredDir ? [{
30714
+ absoluteDir: resolveAbsoluteDirectory3(configuredDir, options.cwd, options.homeDir),
30715
+ displayDir: configuredDir
30716
+ }] : [
30717
+ {
30718
+ absoluteDir: path42.join(options.cwd, ".poe-code", "pipeline", "plans"),
30719
+ displayDir: ".poe-code/pipeline/plans"
30720
+ },
30721
+ {
30722
+ absoluteDir: path42.join(options.homeDir, ".poe-code", "pipeline", "plans"),
30723
+ displayDir: "~/.poe-code/pipeline/plans"
30724
+ }
30725
+ ];
30726
+ const plans = await Promise.all(
30727
+ targets.map(
30728
+ (target) => scanDirectory({
30729
+ ...target,
30730
+ fs: options.fs,
30731
+ source: "pipeline",
30732
+ include: isPipelinePlanFile,
30733
+ cwd: options.cwd,
30734
+ homeDir: options.homeDir
30735
+ })
30736
+ )
30737
+ );
30738
+ return plans.flat();
30739
+ }
30740
+ async function discoverExperimentPlans(options) {
30741
+ const configuredDir = await resolvePlanDirectorySetting({
30742
+ fs: options.fs,
30743
+ configPath: options.configPath,
30744
+ projectConfigPath: options.projectConfigPath,
30745
+ scope: "experiment",
30746
+ envName: "POE_EXPERIMENT_PLAN_DIRECTORY",
30747
+ variables: options.variables
30748
+ });
30749
+ const targets = configuredDir ? [{
30750
+ absoluteDir: resolveAbsoluteDirectory3(configuredDir, options.cwd, options.homeDir),
30751
+ displayDir: configuredDir
30752
+ }] : [
30753
+ {
30754
+ absoluteDir: path42.join(options.cwd, ".poe-code", "experiments"),
30755
+ displayDir: ".poe-code/experiments"
30756
+ },
30757
+ {
30758
+ absoluteDir: path42.join(options.homeDir, ".poe-code", "experiments"),
30759
+ displayDir: "~/.poe-code/experiments"
30760
+ }
30761
+ ];
30762
+ const plans = await Promise.all(
30763
+ targets.map(
30764
+ (target) => scanDirectory({
30765
+ ...target,
30766
+ fs: options.fs,
30767
+ source: "experiment",
30768
+ include: isMarkdownFile2,
30769
+ cwd: options.cwd,
30770
+ homeDir: options.homeDir
30771
+ })
30772
+ )
30773
+ );
30774
+ return plans.flat();
30775
+ }
30776
+ async function discoverRalphPlans(options) {
30777
+ const configuredDir = await resolvePlanDirectorySetting({
30778
+ fs: options.fs,
30779
+ configPath: options.configPath,
30780
+ projectConfigPath: options.projectConfigPath,
30781
+ scope: "ralph",
30782
+ envName: "POE_RALPH_PLAN_DIRECTORY",
30783
+ variables: options.variables
30784
+ });
30785
+ const docs = await discoverDocs({
30786
+ cwd: options.cwd,
30787
+ homeDir: options.homeDir,
30788
+ planDirectory: configuredDir,
30789
+ fs: {
30790
+ readdir: options.fs.readdir,
30791
+ stat: async (filePath) => {
30792
+ const stat14 = await options.fs.stat(filePath);
30793
+ return {
30794
+ isFile: () => stat14.isFile(),
30795
+ mtimeMs: stat14.mtimeMs
30796
+ };
30797
+ }
30798
+ }
30799
+ });
30800
+ const plans = await Promise.all(
30801
+ docs.map(async (doc) => {
30802
+ const absolutePath = resolveAbsoluteDisplayPath(doc.path, options.cwd, options.homeDir);
30803
+ const stat14 = await options.fs.stat(absolutePath);
30804
+ const metadata = await readPlanMetadata({
30805
+ source: "ralph",
30806
+ absolutePath,
30807
+ path: doc.path,
30808
+ fs: options.fs
30809
+ });
30810
+ return {
30811
+ path: doc.path,
30812
+ absolutePath,
30813
+ source: "ralph",
30814
+ format: metadata.format,
30815
+ title: metadata.title,
30816
+ status: metadata.status,
30817
+ updatedAt: stat14.mtimeMs
30818
+ };
30819
+ })
30820
+ );
30821
+ return plans;
30822
+ }
30823
+ async function discoverAllPlans(options) {
30824
+ const fs3 = options.fs ?? createDefaultFs8();
30825
+ const discoverers = {
30826
+ pipeline: () => discoverPipelinePlans({ ...options, fs: fs3 }),
30827
+ experiment: () => discoverExperimentPlans({ ...options, fs: fs3 }),
30828
+ ralph: () => discoverRalphPlans({ ...options, fs: fs3 })
30829
+ };
30830
+ const sources = options.source ? [options.source] : Object.keys(discoverers);
30831
+ const results = (await Promise.all(sources.map((source) => discoverers[source]()))).flat();
30832
+ const deduped = /* @__PURE__ */ new Map();
30833
+ for (const result of results) {
30834
+ if (!deduped.has(result.absolutePath)) {
30835
+ deduped.set(result.absolutePath, result);
30836
+ }
30837
+ }
30838
+ return [...deduped.values()].sort((left, right) => {
30839
+ if (right.updatedAt !== left.updatedAt) {
30840
+ return right.updatedAt - left.updatedAt;
30841
+ }
30842
+ return left.path.localeCompare(right.path);
30843
+ });
30844
+ }
30845
+ var init_discovery3 = __esm({
30846
+ "packages/plan-browser/src/discovery.ts"() {
30847
+ "use strict";
30848
+ init_src13();
30849
+ init_src4();
30850
+ init_format();
30851
+ }
30852
+ });
30853
+
30854
+ // packages/plan-browser/src/actions.ts
30855
+ import path43 from "node:path";
30856
+ import { spawnSync as nodeSpawnSync } from "node:child_process";
30857
+ function resolveEditor2(env = process.env) {
30858
+ const editor = env.EDITOR?.trim() || env.VISUAL?.trim() || "vi";
30859
+ return editor.length > 0 ? editor : "vi";
30860
+ }
30861
+ function editPlan(absolutePath, options = {}) {
30862
+ const editor = resolveEditor2(options.env);
30863
+ const spawnSync3 = options.spawnSync ?? nodeSpawnSync;
30864
+ spawnSync3(editor, [absolutePath], { stdio: "inherit" });
30865
+ }
30866
+ async function archivePlan3(entry, fs3) {
30867
+ const archiveDir = path43.join(path43.dirname(entry.absolutePath), "archive");
30868
+ const archivedPath = path43.join(archiveDir, path43.basename(entry.absolutePath));
30869
+ await fs3.mkdir(archiveDir, { recursive: true });
30870
+ await fs3.rename(entry.absolutePath, archivedPath);
30871
+ return archivedPath;
30872
+ }
30873
+ async function deletePlan(entry, fs3) {
30874
+ await fs3.unlink(entry.absolutePath);
30875
+ }
30876
+ var init_actions = __esm({
30877
+ "packages/plan-browser/src/actions.ts"() {
30878
+ "use strict";
30879
+ }
30880
+ });
30881
+
30882
+ // packages/plan-browser/src/browser.ts
30883
+ import path44 from "node:path";
30884
+ async function runPlanBrowser(options) {
30885
+ const renderPlanPreview = async (entry) => {
30886
+ const markdown = await loadPlanPreviewMarkdown(entry, options.fs);
30887
+ process.stdout.write(`${renderMarkdown(markdown).trimEnd()}
30888
+ `);
30889
+ };
30890
+ while (true) {
30891
+ const plans = await discoverAllPlans({
30892
+ cwd: options.cwd,
30893
+ homeDir: options.homeDir,
30894
+ configPath: options.configPath,
30895
+ projectConfigPath: options.projectConfigPath,
30896
+ fs: options.fs,
30897
+ source: options.source,
30898
+ variables: options.variables
30899
+ });
30900
+ if (plans.length === 0) {
30901
+ process.stdout.write("No plans found.\n");
30902
+ return;
30903
+ }
30904
+ if (options.assumeYes) {
30905
+ const selectedPlan2 = plans[0];
30906
+ await renderPlanPreview(selectedPlan2);
30907
+ return;
30908
+ }
30909
+ const selectedPath = await select2({
30910
+ message: "Select a plan",
30911
+ options: plans.map((plan) => ({
30912
+ label: text.selectLabel(path44.basename(plan.path), plan.status),
30913
+ hint: plan.source,
30914
+ value: plan.absolutePath
30915
+ }))
30916
+ });
30917
+ if (Ct(selectedPath)) {
30918
+ return;
30919
+ }
30920
+ const selectedPlan = plans.find((plan) => plan.absolutePath === selectedPath);
30921
+ if (!selectedPlan) {
30922
+ cancel("Plan selection cancelled.");
30923
+ return;
30924
+ }
30925
+ await renderPlanPreview(selectedPlan);
30926
+ process.stdout.write("\n");
30927
+ const action = await select2({
30928
+ message: "Action",
30929
+ options: [
30930
+ { label: "Back to list", value: "back" },
30931
+ { label: "Edit in $EDITOR", value: "edit" },
30932
+ { label: "Archive", value: "archive" },
30933
+ { label: "Delete", value: "delete" }
30934
+ ]
30935
+ });
30936
+ if (Ct(action) || action === "back") {
30937
+ continue;
30938
+ }
30939
+ if (action === "edit") {
30940
+ editPlan(selectedPlan.absolutePath, {
30941
+ env: options.variables ?? process.env
30942
+ });
30943
+ continue;
30944
+ }
30945
+ if (action === "archive") {
30946
+ try {
30947
+ const confirmed = options.assumeYes || await confirmOrCancel({
30948
+ message: `Archive ${path44.basename(selectedPlan.path)}?`,
30949
+ initialValue: true
30950
+ });
30951
+ if (confirmed) {
30952
+ await archivePlan3(selectedPlan, options.fs);
30953
+ }
30954
+ } catch (error2) {
30955
+ if (!(error2 instanceof PromptCancelledError)) {
30956
+ throw error2;
30957
+ }
30958
+ }
30959
+ continue;
30960
+ }
30961
+ try {
30962
+ const confirmed = options.assumeYes || await confirmOrCancel({
30963
+ message: `Permanently delete ${path44.basename(selectedPlan.path)}?`,
30964
+ initialValue: true
30965
+ });
30966
+ if (confirmed) {
30967
+ await deletePlan(selectedPlan, options.fs);
30968
+ }
30969
+ } catch (error2) {
30970
+ if (!(error2 instanceof PromptCancelledError)) {
30971
+ throw error2;
30972
+ }
30973
+ }
30974
+ }
30975
+ }
30976
+ var init_browser = __esm({
30977
+ "packages/plan-browser/src/browser.ts"() {
30978
+ "use strict";
30979
+ init_src5();
30980
+ init_src5();
30981
+ init_actions();
30982
+ init_discovery3();
30983
+ init_format();
30984
+ }
30985
+ });
30986
+
30987
+ // packages/plan-browser/src/index.ts
30988
+ var init_src23 = __esm({
30989
+ "packages/plan-browser/src/index.ts"() {
30990
+ "use strict";
30991
+ init_discovery3();
30992
+ init_actions();
30993
+ init_format();
30994
+ init_browser();
30995
+ }
30996
+ });
30997
+
30998
+ // src/cli/commands/plan.ts
30999
+ import path45 from "node:path";
31000
+ function resolvePlanCommandOptions(command) {
31001
+ const localOptions = command.opts();
31002
+ const parentOptions = command.parent?.opts() ?? {};
31003
+ return {
31004
+ source: localOptions.source ?? parentOptions.source,
31005
+ output: localOptions.output ?? parentOptions.output
31006
+ };
31007
+ }
31008
+ function resolveOutputOption(value) {
31009
+ if (!value || value.trim().length === 0) {
31010
+ return "terminal";
31011
+ }
31012
+ const normalized = value.trim().toLowerCase();
31013
+ if (normalized === "json") {
31014
+ return "json";
31015
+ }
31016
+ if (normalized === "md" || normalized === "markdown") {
31017
+ return "markdown";
31018
+ }
31019
+ if (normalized === "terminal") {
31020
+ return "terminal";
31021
+ }
31022
+ throw new ValidationError(`Invalid --output value "${value}". Expected one of: terminal, md, json.`);
31023
+ }
31024
+ function resolveSource(value) {
31025
+ if (!value || value.trim().length === 0) {
31026
+ return void 0;
31027
+ }
31028
+ if (value === "pipeline" || value === "experiment" || value === "ralph") {
31029
+ return value;
31030
+ }
31031
+ throw new ValidationError(`Invalid --source value "${value}". Expected pipeline, experiment, or ralph.`);
31032
+ }
31033
+ function formatDate2(timestamp) {
31034
+ return new Date(timestamp).toISOString().slice(0, 10);
31035
+ }
31036
+ async function discoverPlans(container, source) {
31037
+ return discoverAllPlans({
31038
+ cwd: container.env.cwd,
31039
+ homeDir: container.env.homeDir,
31040
+ configPath: container.env.configPath,
31041
+ projectConfigPath: container.env.projectConfigPath,
31042
+ fs: container.fs,
31043
+ source,
31044
+ variables: container.env.variables
31045
+ });
31046
+ }
31047
+ async function resolveSelectedPlan(options) {
31048
+ const providedPath = options.providedPath?.trim();
31049
+ if (providedPath) {
31050
+ const resolvedAbsolute = providedPath.startsWith("~/") ? path45.join(options.container.env.homeDir, providedPath.slice(2)) : path45.isAbsolute(providedPath) ? providedPath : path45.resolve(options.container.env.cwd, providedPath);
31051
+ const matched2 = options.plans.find(
31052
+ (plan) => plan.path === providedPath || plan.absolutePath === providedPath || plan.absolutePath === resolvedAbsolute
31053
+ );
31054
+ if (!matched2) {
31055
+ throw new ValidationError(`Plan not found: ${providedPath}`);
31056
+ }
31057
+ return matched2;
31058
+ }
31059
+ if (options.plans.length === 0) {
31060
+ throw new ValidationError("No plans found.");
31061
+ }
31062
+ if (options.assumeYes) {
31063
+ return options.plans[0];
31064
+ }
31065
+ const selected = await select2({
31066
+ message: options.promptMessage,
31067
+ options: options.plans.map((plan) => ({
31068
+ label: text.selectLabel(path45.basename(plan.path), plan.status),
31069
+ hint: plan.source,
31070
+ value: plan.absolutePath
31071
+ }))
31072
+ });
31073
+ if (Ct(selected)) {
31074
+ throw new ValidationError("Plan selection cancelled.");
31075
+ }
31076
+ const matched = options.plans.find((plan) => plan.absolutePath === selected);
31077
+ if (!matched) {
31078
+ throw new ValidationError("Plan selection cancelled.");
31079
+ }
31080
+ return matched;
31081
+ }
31082
+ function writeOutput(format, value) {
31083
+ if (format === "terminal") {
31084
+ process.stdout.write(value.endsWith("\n") ? value : `${value}
31085
+ `);
31086
+ return;
31087
+ }
31088
+ const scopedFormat = format === "markdown" ? "markdown" : "json";
31089
+ withOutputFormat(scopedFormat, () => {
31090
+ process.stdout.write(value.endsWith("\n") ? value : `${value}
31091
+ `);
31092
+ });
31093
+ }
31094
+ async function renderPlanList(container, options) {
31095
+ const format = resolveOutputOption(options.output);
31096
+ const source = resolveSource(options.source);
31097
+ const plans = await discoverPlans(container, source);
31098
+ if (format === "json") {
31099
+ writeOutput(
31100
+ format,
31101
+ JSON.stringify(
31102
+ plans.map((plan) => ({
31103
+ source: plan.source,
31104
+ name: path45.basename(plan.path),
31105
+ path: plan.path,
31106
+ detail: plan.status,
31107
+ updated: formatDate2(plan.updatedAt)
31108
+ })),
31109
+ null,
31110
+ 2
31111
+ )
31112
+ );
31113
+ return;
31114
+ }
31115
+ const table = withOutputFormat(
31116
+ format,
31117
+ () => renderTable({
31118
+ theme: getTheme(),
31119
+ columns: [
31120
+ { name: "source", title: "Source", alignment: "left", maxLen: 12 },
31121
+ { name: "name", title: "Name", alignment: "left", maxLen: 32 },
31122
+ { name: "detail", title: "Detail", alignment: "left", maxLen: 40 },
31123
+ { name: "updated", title: "Updated", alignment: "left", maxLen: 12 }
31124
+ ],
31125
+ rows: plans.map((plan) => ({
31126
+ source: plan.source,
31127
+ name: path45.basename(plan.path),
31128
+ detail: plan.status,
31129
+ updated: formatDate2(plan.updatedAt)
31130
+ }))
31131
+ })
31132
+ );
31133
+ writeOutput(format, table);
31134
+ }
31135
+ async function executePlanAction(options) {
31136
+ intro(`plan ${options.action}`);
31137
+ const flags = resolveCommandFlags(options.program);
31138
+ const format = resolveOutputOption(options.output);
31139
+ const plans = await discoverPlans(options.container, resolveSource(options.source));
31140
+ const plan = await resolveSelectedPlan({
31141
+ container: options.container,
31142
+ plans,
31143
+ providedPath: options.pathArg,
31144
+ assumeYes: flags.assumeYes,
31145
+ promptMessage: `Select a plan to ${options.action}`
31146
+ });
31147
+ if (options.action === "edit") {
31148
+ editPlan(plan.absolutePath, {
31149
+ env: options.container.env.variables
31150
+ });
31151
+ writeOutput(
31152
+ format,
31153
+ format === "json" ? JSON.stringify({ action: "edit", path: plan.path }, null, 2) : `Edited ${plan.path}`
31154
+ );
31155
+ return;
31156
+ }
31157
+ if (!flags.assumeYes) {
31158
+ const confirmed = await confirmOrCancel({
31159
+ message: options.action === "archive" ? `Archive ${path45.basename(plan.path)}?` : `Permanently delete ${path45.basename(plan.path)}?`,
31160
+ initialValue: true
31161
+ });
31162
+ if (!confirmed) {
31163
+ return;
31164
+ }
31165
+ }
31166
+ if (options.action === "archive") {
31167
+ const archivedPath = await archivePlan3(
31168
+ plan,
31169
+ options.container.fs
31170
+ );
31171
+ writeOutput(
31172
+ format,
31173
+ format === "json" ? JSON.stringify({ action: "archive", path: plan.path, archivedPath }, null, 2) : `Archived ${plan.path}`
31174
+ );
31175
+ return;
31176
+ }
31177
+ await deletePlan(
31178
+ plan,
31179
+ options.container.fs
31180
+ );
31181
+ writeOutput(
31182
+ format,
31183
+ format === "json" ? JSON.stringify({ action: "delete", path: plan.path }, null, 2) : `Deleted ${plan.path}`
31184
+ );
31185
+ }
31186
+ function registerPlanCommand(program, container) {
31187
+ const plan = program.command("plan").description("Browse, view, and manage plans across pipeline, experiment, and Ralph.").option("--source <source>", "Filter by plan source: pipeline, experiment, or ralph").action(async function() {
31188
+ const opts = this.opts();
31189
+ const flags = resolveCommandFlags(this);
31190
+ intro("plan browser");
31191
+ await runPlanBrowser({
31192
+ cwd: container.env.cwd,
31193
+ homeDir: container.env.homeDir,
31194
+ configPath: container.env.configPath,
31195
+ projectConfigPath: container.env.projectConfigPath,
31196
+ fs: container.fs,
31197
+ source: resolveSource(opts.source),
31198
+ variables: container.env.variables,
31199
+ assumeYes: flags.assumeYes
31200
+ });
31201
+ });
31202
+ plan.command("list").description("List plans across all plan systems.").option("--source <source>", "Filter by plan source: pipeline, experiment, or ralph").option("--output <format>", "Output format: terminal, md, or json").action(async function() {
31203
+ intro("plan list");
31204
+ await renderPlanList(container, resolvePlanCommandOptions(this));
31205
+ });
31206
+ plan.command("view").description("Render a single plan to the terminal.").argument("[path]", "Plan path").option("--source <source>", "Filter by plan source: pipeline, experiment, or ralph").option("--output <format>", "Output format: terminal, md, or json").action(async function(pathArg) {
31207
+ intro("plan view");
31208
+ const flags = resolveCommandFlags(program);
31209
+ const options = resolvePlanCommandOptions(this);
31210
+ const format = resolveOutputOption(options.output);
31211
+ const plans = await discoverPlans(container, resolveSource(options.source));
31212
+ const plan2 = await resolveSelectedPlan({
31213
+ container,
31214
+ plans,
31215
+ providedPath: pathArg,
31216
+ assumeYes: flags.assumeYes,
31217
+ promptMessage: "Select a plan to view"
31218
+ });
31219
+ const markdown = await loadPlanPreviewMarkdown(plan2, container.fs);
31220
+ if (format === "json") {
31221
+ writeOutput(
31222
+ format,
31223
+ JSON.stringify(
31224
+ {
31225
+ source: plan2.source,
31226
+ path: plan2.path,
31227
+ title: plan2.title,
31228
+ detail: plan2.status,
31229
+ content: markdown
31230
+ },
31231
+ null,
31232
+ 2
31233
+ )
31234
+ );
31235
+ return;
31236
+ }
31237
+ const output = format === "markdown" ? markdown : renderMarkdown(markdown);
31238
+ writeOutput(format, output.trimEnd());
31239
+ });
31240
+ plan.command("edit").description("Open a plan in $EDITOR.").argument("[path]", "Plan path").option("--source <source>", "Filter by plan source: pipeline, experiment, or ralph").option("--output <format>", "Output format: terminal, md, or json").action(async function(pathArg) {
31241
+ await executePlanAction({
31242
+ program,
31243
+ container,
31244
+ action: "edit",
31245
+ pathArg,
31246
+ ...resolvePlanCommandOptions(this)
31247
+ });
31248
+ });
31249
+ plan.command("archive").description("Move a plan into archive/.").argument("[path]", "Plan path").option("--source <source>", "Filter by plan source: pipeline, experiment, or ralph").option("--output <format>", "Output format: terminal, md, or json").action(async function(pathArg) {
31250
+ await executePlanAction({
31251
+ program,
31252
+ container,
31253
+ action: "archive",
31254
+ pathArg,
31255
+ ...resolvePlanCommandOptions(this)
31256
+ });
31257
+ });
31258
+ plan.command("delete").description("Delete a plan file.").argument("[path]", "Plan path").option("--source <source>", "Filter by plan source: pipeline, experiment, or ralph").option("--output <format>", "Output format: terminal, md, or json").action(async function(pathArg) {
31259
+ await executePlanAction({
31260
+ program,
31261
+ container,
31262
+ action: "delete",
31263
+ pathArg,
31264
+ ...resolvePlanCommandOptions(this)
31265
+ });
31266
+ });
31267
+ }
31268
+ var init_plan = __esm({
31269
+ "src/cli/commands/plan.ts"() {
31270
+ "use strict";
31271
+ init_src5();
31272
+ init_src23();
31273
+ init_errors();
31274
+ init_shared();
31275
+ }
31276
+ });
31277
+
31278
+ // src/cli/commands/ralph.ts
31279
+ import path46 from "node:path";
30353
31280
  function formatDuration2(ms) {
30354
31281
  const totalSeconds = Math.round(ms / 1e3);
30355
31282
  const minutes = Math.floor(totalSeconds / 60);
@@ -30385,9 +31312,9 @@ function normalizeConfiguredIterations(value) {
30385
31312
  }
30386
31313
  function resolveAbsoluteDocPath4(container, docPath) {
30387
31314
  if (docPath.startsWith("~/")) {
30388
- return path41.join(container.env.homeDir, docPath.slice(2));
31315
+ return path46.join(container.env.homeDir, docPath.slice(2));
30389
31316
  }
30390
- return path41.isAbsolute(docPath) ? docPath : path41.resolve(container.env.cwd, docPath);
31317
+ return path46.isAbsolute(docPath) ? docPath : path46.resolve(container.env.cwd, docPath);
30391
31318
  }
30392
31319
  async function resolvePlanDirectory2(container) {
30393
31320
  const configDoc = await readMergedDocument(
@@ -30607,7 +31534,7 @@ function expandAgentList(agent2, iterations) {
30607
31534
  return Array.from({ length: count }, (_2, index) => agent2[index % agent2.length]);
30608
31535
  }
30609
31536
  function registerRalphCommand(program, container) {
30610
- const ralph = program.command("ralph").description("Run a simple iterative markdown loop.");
31537
+ const ralph = program.command("ralph").description("Run a simple iterative markdown loop.").addHelpCommand(false);
30611
31538
  ralph.command("init").description("Write Ralph config into an existing markdown doc frontmatter.").argument("[doc]", "Markdown doc path").option("--agent <name>", "Agent to write into frontmatter").option("--iterations <n>", "Number of iterations to write into frontmatter").action(async function(docArg) {
30612
31539
  const flags = resolveCommandFlags(program);
30613
31540
  const resources = createExecutionResources(container, flags, "ralph:init");
@@ -30758,11 +31685,11 @@ var init_ralph3 = __esm({
30758
31685
  });
30759
31686
 
30760
31687
  // src/cli/commands/experiment.ts
30761
- import path42 from "node:path";
30762
- import { readFile as readFile15, stat as stat12 } from "node:fs/promises";
31688
+ import path47 from "node:path";
31689
+ import { readFile as readFile15, stat as stat13 } from "node:fs/promises";
30763
31690
  import { fileURLToPath as fileURLToPath8 } from "node:url";
30764
31691
  function resolveExperimentPaths(scope, cwd, homeDir) {
30765
- const rootPath = scope === "global" ? path42.join(homeDir, ".poe-code", "experiments") : path42.join(cwd, ".poe-code", "experiments");
31692
+ const rootPath = scope === "global" ? path47.join(homeDir, ".poe-code", "experiments") : path47.join(cwd, ".poe-code", "experiments");
30766
31693
  const displayRoot = scope === "global" ? "~/.poe-code/experiments" : ".poe-code/experiments";
30767
31694
  return {
30768
31695
  experimentsPath: rootPath,
@@ -30771,7 +31698,7 @@ function resolveExperimentPaths(scope, cwd, homeDir) {
30771
31698
  }
30772
31699
  async function pathExistsOnDisk2(targetPath) {
30773
31700
  try {
30774
- await stat12(targetPath);
31701
+ await stat13(targetPath);
30775
31702
  return true;
30776
31703
  } catch (error2) {
30777
31704
  if (error2 && typeof error2 === "object" && "code" in error2 && error2.code === "ENOENT") {
@@ -30781,12 +31708,12 @@ async function pathExistsOnDisk2(targetPath) {
30781
31708
  }
30782
31709
  }
30783
31710
  async function findPackageRoot2(entryFilePath) {
30784
- let currentPath = path42.dirname(entryFilePath);
31711
+ let currentPath = path47.dirname(entryFilePath);
30785
31712
  while (true) {
30786
- if (await pathExistsOnDisk2(path42.join(currentPath, "package.json"))) {
31713
+ if (await pathExistsOnDisk2(path47.join(currentPath, "package.json"))) {
30787
31714
  return currentPath;
30788
31715
  }
30789
- const parentPath = path42.dirname(currentPath);
31716
+ const parentPath = path47.dirname(currentPath);
30790
31717
  if (parentPath === currentPath) {
30791
31718
  throw new Error("Unable to locate package root for Experiment templates.");
30792
31719
  }
@@ -30799,16 +31726,16 @@ async function loadExperimentTemplates() {
30799
31726
  }
30800
31727
  const packageRoot = await findPackageRoot2(fileURLToPath8(import.meta.url));
30801
31728
  const templateRoots = [
30802
- path42.join(packageRoot, "src", "templates", "experiment"),
30803
- path42.join(packageRoot, "dist", "templates", "experiment")
31729
+ path47.join(packageRoot, "src", "templates", "experiment"),
31730
+ path47.join(packageRoot, "dist", "templates", "experiment")
30804
31731
  ];
30805
31732
  for (const templateRoot of templateRoots) {
30806
31733
  if (!await pathExistsOnDisk2(templateRoot)) {
30807
31734
  continue;
30808
31735
  }
30809
31736
  const [skillPlan, runYaml] = await Promise.all([
30810
- readFile15(path42.join(templateRoot, "SKILL_experiment.md"), "utf8"),
30811
- readFile15(path42.join(templateRoot, "run.yaml.hbs"), "utf8")
31737
+ readFile15(path47.join(templateRoot, "SKILL_experiment.md"), "utf8"),
31738
+ readFile15(path47.join(templateRoot, "run.yaml.hbs"), "utf8")
30812
31739
  ]);
30813
31740
  experimentTemplatesCache = { skillPlan, runYaml };
30814
31741
  return experimentTemplatesCache;
@@ -30895,15 +31822,15 @@ async function resolveExperimentPlanDirectory(container) {
30895
31822
  }
30896
31823
  function resolveAbsoluteDocPath5(container, docPath) {
30897
31824
  if (docPath.startsWith("~/")) {
30898
- return path42.join(container.env.homeDir, docPath.slice(2));
31825
+ return path47.join(container.env.homeDir, docPath.slice(2));
30899
31826
  }
30900
- return path42.isAbsolute(docPath) ? docPath : path42.resolve(container.env.cwd, docPath);
31827
+ return path47.isAbsolute(docPath) ? docPath : path47.resolve(container.env.cwd, docPath);
30901
31828
  }
30902
- function resolveAbsoluteDirectory3(dir, cwd, homeDir) {
31829
+ function resolveAbsoluteDirectory4(dir, cwd, homeDir) {
30903
31830
  if (dir.startsWith("~/")) {
30904
- return path42.join(homeDir, dir.slice(2));
31831
+ return path47.join(homeDir, dir.slice(2));
30905
31832
  }
30906
- return path42.isAbsolute(dir) ? dir : path42.resolve(cwd, dir);
31833
+ return path47.isAbsolute(dir) ? dir : path47.resolve(cwd, dir);
30907
31834
  }
30908
31835
  async function scanExperimentDir(container, absoluteDir, displayDir) {
30909
31836
  let names;
@@ -30920,12 +31847,12 @@ async function scanExperimentDir(container, absoluteDir, displayDir) {
30920
31847
  if (!name.endsWith(".md")) {
30921
31848
  continue;
30922
31849
  }
30923
- const absolutePath = path42.join(absoluteDir, name);
31850
+ const absolutePath = path47.join(absoluteDir, name);
30924
31851
  const fileStat = await container.fs.stat(absolutePath);
30925
31852
  if (!fileStat.isFile()) {
30926
31853
  continue;
30927
31854
  }
30928
- const displayPath = path42.join(displayDir, name);
31855
+ const displayPath = path47.join(displayDir, name);
30929
31856
  docs.push({ path: displayPath, displayPath });
30930
31857
  }
30931
31858
  return docs;
@@ -30933,12 +31860,12 @@ async function scanExperimentDir(container, absoluteDir, displayDir) {
30933
31860
  async function discoverExperimentDocs(container, planDirectory) {
30934
31861
  const customDir = planDirectory?.trim();
30935
31862
  if (customDir) {
30936
- const absoluteDir = resolveAbsoluteDirectory3(customDir, container.env.cwd, container.env.homeDir);
31863
+ const absoluteDir = resolveAbsoluteDirectory4(customDir, container.env.cwd, container.env.homeDir);
30937
31864
  return scanExperimentDir(container, absoluteDir, customDir);
30938
31865
  }
30939
31866
  return scanExperimentDir(
30940
31867
  container,
30941
- path42.join(container.env.cwd, EXPERIMENTS_DIRECTORY),
31868
+ path47.join(container.env.cwd, EXPERIMENTS_DIRECTORY),
30942
31869
  EXPERIMENTS_DIRECTORY
30943
31870
  );
30944
31871
  }
@@ -31029,7 +31956,7 @@ function formatJournalOutput(output) {
31029
31956
  return trimmed.split("\n").join(" \u21B5 ");
31030
31957
  }
31031
31958
  function registerExperimentCommand(program, container) {
31032
- const experiment = program.command("experiment").description("Run autonomous experiment loop workflows.");
31959
+ const experiment = program.command("experiment").description("Run autonomous experiment loop workflows.").addHelpCommand(false);
31033
31960
  experiment.command("run").description("Run an experiment doc through the autonomous experiment loop.").argument("[doc]", "Experiment doc path").option("--agent <agent>", "Override the agent from frontmatter").option("--max-experiments <n>", "Limit the number of experiments to run").action(async function(docArg) {
31034
31961
  const flags = resolveCommandFlags(program);
31035
31962
  const resources = createExecutionResources(container, flags, "experiment:run");
@@ -31315,12 +32242,12 @@ function registerExperimentCommand(program, container) {
31315
32242
  scope = selected;
31316
32243
  }
31317
32244
  resources.logger.intro(`experiment install (${support.id}, ${scope})`);
31318
- const templates = await loadExperimentTemplates();
32245
+ const templates2 = await loadExperimentTemplates();
31319
32246
  const skillResult = await installSkill(
31320
32247
  support.id,
31321
32248
  {
31322
32249
  name: "poe-code-experiment-plan",
31323
- content: templates.skillPlan
32250
+ content: templates2.skillPlan
31324
32251
  },
31325
32252
  {
31326
32253
  fs: container.fs,
@@ -31354,13 +32281,13 @@ function registerExperimentCommand(program, container) {
31354
32281
  );
31355
32282
  }
31356
32283
  }
31357
- const runYamlPath = path42.join(experimentPaths.experimentsPath, "run.yaml");
31358
- const runYamlDisplayPath = path42.join(experimentPaths.displayExperimentsPath, "run.yaml");
32284
+ const runYamlPath = path47.join(experimentPaths.experimentsPath, "run.yaml");
32285
+ const runYamlDisplayPath = path47.join(experimentPaths.displayExperimentsPath, "run.yaml");
31359
32286
  if (!await pathExists4(container.fs, runYamlPath)) {
31360
32287
  if (flags.dryRun) {
31361
32288
  resources.logger.dryRun(`Would create: ${runYamlDisplayPath}`);
31362
32289
  } else {
31363
- await container.fs.writeFile(runYamlPath, templates.runYaml);
32290
+ await container.fs.writeFile(runYamlPath, templates2.runYaml);
31364
32291
  resources.logger.info(`Create: ${runYamlDisplayPath}`);
31365
32292
  }
31366
32293
  }
@@ -31389,16 +32316,16 @@ var init_experiment2 = __esm({
31389
32316
  init_src4();
31390
32317
  DEFAULT_EXPERIMENT_AGENT = "claude-code";
31391
32318
  DEFAULT_EXPERIMENT_SCOPE = "local";
31392
- EXPERIMENTS_DIRECTORY = path42.join(".poe-code", "experiments");
32319
+ EXPERIMENTS_DIRECTORY = path47.join(".poe-code", "experiments");
31393
32320
  experimentTemplatesCache = null;
31394
32321
  }
31395
32322
  });
31396
32323
 
31397
32324
  // src/cli/commands/launch.ts
31398
- import { Option as Option2 } from "commander";
32325
+ import { Option as Option3 } from "commander";
31399
32326
  function registerLaunchCommand(program, container) {
31400
- const launch = program.command("launch").description("Manage long-running host and Docker processes.");
31401
- launch.command("start [id] [commandArgs...]").usage("<id> -- <command> [args...]").description("Start and supervise a managed process.").addOption(createChoiceOption("--restart <policy>", "Restart policy", ["never", "on-failure", "always"], "on-failure")).option("--max-restarts <n>", "Max consecutive restarts", "5").option("--ready-pattern <string>", "Log substring to wait for before reporting running").option("--ready-port <port>", "TCP port to probe for readiness").option("--cwd <dir>", "Working directory for the managed process").option("--env <entry>", "Environment variable (KEY=VALUE)", collectValues, []).option("--image <image>", "Docker image").option("--mount <src:target[:ro]>", "Docker bind mount", collectValues, []).option("--port <host:container>", "Docker port mapping", collectValues, []).option("--network <name>", "Docker network").addOption(createChoiceOption("--engine <engine>", "Container engine", ["docker", "podman"])).action(async function(id, commandArgs) {
32327
+ const launch = program.command("launch").description("Manage long-running host and Docker processes.").addHelpCommand(false);
32328
+ launch.command("start").usage("<id> -- <command> [args...]").description("Start and supervise a managed process.").argument("[id]", "Managed process identifier").argument("[command...]", "Command and arguments to run after --").addOption(createChoiceOption("--restart <policy>", "Restart policy", ["never", "on-failure", "always"], "on-failure")).option("--max-restarts <n>", "Max consecutive restarts", "5").option("--ready-pattern <string>", "Log substring to wait for before reporting running").option("--ready-port <port>", "TCP port to probe for readiness").option("--cwd <dir>", "Working directory for the managed process").option("--env <entry>", "Environment variable (KEY=VALUE)", collectValues, []).option("--image <image>", "Docker image").option("--mount <src:target[:ro]>", "Docker bind mount", collectValues, []).option("--port <host:container>", "Docker port mapping", collectValues, []).option("--network <name>", "Docker network").addOption(createChoiceOption("--engine <engine>", "Container engine", ["docker", "podman"])).action(async function(id, commandArgs) {
31402
32329
  const spec = await resolveStartSpec({
31403
32330
  commandArgs,
31404
32331
  id,
@@ -31414,7 +32341,7 @@ function registerLaunchCommand(program, container) {
31414
32341
  spec
31415
32342
  });
31416
32343
  });
31417
- launch.command("stop <id>").description("Stop a managed process.").option("--force", "Stop immediately with SIGKILL / docker kill").action(async function(id) {
32344
+ launch.command("stop").description("Stop a managed process.").argument("<id>", "Managed process identifier").option("--force", "Stop immediately with SIGKILL / docker kill").action(async function(id) {
31418
32345
  const result = await stopLaunch({
31419
32346
  force: Boolean(this.opts().force),
31420
32347
  homeDir: container.env.homeDir,
@@ -31424,7 +32351,7 @@ function registerLaunchCommand(program, container) {
31424
32351
  throw new ValidationError(`Managed process not found: ${id}`);
31425
32352
  }
31426
32353
  });
31427
- launch.command("restart <id>").description("Restart a managed process.").action(async function(id) {
32354
+ launch.command("restart").description("Restart a managed process.").argument("<id>", "Managed process identifier").action(async function(id) {
31428
32355
  await restartLaunch({ homeDir: container.env.homeDir, id });
31429
32356
  });
31430
32357
  launch.command("status").description("List managed processes.").action(async function() {
@@ -31449,7 +32376,7 @@ function registerLaunchCommand(program, container) {
31449
32376
  theme: getTheme()
31450
32377
  }));
31451
32378
  });
31452
- launch.command("logs <id>").description("Show managed process logs.").option("--follow", "Follow log output").option("--lines <n>", "Number of lines to show", "50").option("--stderr", "Show stderr instead of stdout").action(async function(id) {
32379
+ launch.command("logs").description("Show managed process logs.").argument("<id>", "Managed process identifier").option("--follow", "Follow log output").option("--lines <n>", "Number of lines to show", "50").option("--stderr", "Show stderr instead of stdout").action(async function(id) {
31453
32380
  const options = this.opts();
31454
32381
  const lines = parseNonNegativeInt2(options.lines, "lines") ?? 50;
31455
32382
  const stream = options.stderr ? "stderr" : "stdout";
@@ -31488,10 +32415,10 @@ function registerLaunchCommand(program, container) {
31488
32415
  process.removeListener("SIGTERM", stop);
31489
32416
  }
31490
32417
  });
31491
- launch.command("rm <id>").description("Remove managed process state and logs.").action(async function(id) {
32418
+ launch.command("rm").description("Remove managed process state and logs.").argument("<id>", "Managed process identifier").action(async function(id) {
31492
32419
  await removeLaunch({ homeDir: container.env.homeDir, id });
31493
32420
  });
31494
- launch.command("__run <id>", { hidden: true }).action(async function(id) {
32421
+ launch.command("__run", { hidden: true }).argument("<id>", "Managed process identifier").action(async function(id) {
31495
32422
  await runLaunchDaemon({ homeDir: container.env.homeDir, id });
31496
32423
  });
31497
32424
  return launch;
@@ -31769,7 +32696,7 @@ function formatUptime(state) {
31769
32696
  return `${seconds}s`;
31770
32697
  }
31771
32698
  function createChoiceOption(flags, description, choices, defaultValue) {
31772
- const option = new Option2(flags, description).choices(choices);
32699
+ const option = new Option3(flags, description).choices(choices);
31773
32700
  if (defaultValue !== void 0) {
31774
32701
  option.default(defaultValue);
31775
32702
  }
@@ -31821,7 +32748,7 @@ var init_package = __esm({
31821
32748
  "package.json"() {
31822
32749
  package_default = {
31823
32750
  name: "poe-code",
31824
- version: "3.0.154",
32751
+ version: "3.0.156",
31825
32752
  description: "CLI tool to configure Poe API for developer workflows.",
31826
32753
  type: "module",
31827
32754
  main: "./dist/index.js",
@@ -31836,7 +32763,7 @@ var init_package = __esm({
31836
32763
  "codegen:check:python-types": "tsx scripts/generate-agent-spawn-py-types.ts --check",
31837
32764
  "install:py-poe-spawn": "pip install -e packages/py-poe-spawn",
31838
32765
  predev: "turbo run build --output-logs=none --log-prefix=none --verbosity=0 > /dev/null 2>&1",
31839
- dev: "tsx src/index.ts",
32766
+ dev: "tsx --import ./scripts/register-hbs-loader.mjs src/index.ts",
31840
32767
  start: "node dist/bin.cjs",
31841
32768
  "dev:bundle": "npm run build && node dist/bin.cjs",
31842
32769
  test: "turbo run test:unit",
@@ -31929,6 +32856,7 @@ var init_package = __esm({
31929
32856
  "@poe-code/e2e-docker-test-runner": "*",
31930
32857
  "@poe-code/experiment-loop": "*",
31931
32858
  "@poe-code/github-workflows": "*",
32859
+ "@poe-code/plan-browser": "*",
31932
32860
  "@poe-code/pipeline": "*",
31933
32861
  "@poe-code/poe-acp-client": "*",
31934
32862
  "@poe-code/poe-agent": "*",
@@ -31996,181 +32924,106 @@ function formatCommandHeader(cmd) {
31996
32924
  }
31997
32925
  return `Poe - ${parts.reverse().join(" ")}`;
31998
32926
  }
31999
- function formatHelpText(input) {
32000
- const commandRows = [
32001
- {
32002
- name: "install",
32003
- aliases: ["i"],
32004
- args: "[agent]",
32005
- description: "Install agent binary for a configured agent"
32006
- },
32007
- {
32008
- name: "configure",
32009
- aliases: ["c"],
32010
- args: "[agent]",
32011
- description: "Configure a coding agent"
32012
- },
32013
- {
32014
- name: "unconfigure",
32015
- aliases: ["uc"],
32016
- args: "<agent>",
32017
- description: "Remove a previously applied configuration"
32018
- },
32019
- {
32020
- name: "login",
32021
- aliases: [],
32022
- args: "",
32023
- description: "Store a Poe API key"
32024
- },
32025
- {
32026
- name: "logout",
32027
- aliases: [],
32028
- args: "",
32029
- description: "Remove all configuration"
32030
- },
32031
- {
32032
- name: "auth status",
32033
- aliases: [],
32034
- args: "",
32035
- description: "Show login status"
32036
- },
32037
- {
32038
- name: "agent",
32039
- aliases: [],
32040
- args: "<prompt>",
32041
- description: "Run a one-shot Poe agent prompt"
32042
- },
32043
- {
32044
- name: "spawn",
32045
- aliases: ["s"],
32046
- args: "<agent> [prompt]",
32047
- description: "Launch a coding agent"
32048
- },
32049
- {
32050
- name: "wrap",
32051
- aliases: ["w"],
32052
- args: "<agent> [agentArgs...]",
32053
- description: "Run an agent with Poe isolated configuration"
32054
- },
32055
- {
32056
- name: "generate",
32057
- aliases: ["g"],
32058
- args: "[type]",
32059
- description: "Call Poe models via CLI (text/image/video/audio)"
32060
- },
32061
- {
32062
- name: "models",
32063
- aliases: ["m"],
32064
- args: "",
32065
- description: "List available Poe API models"
32066
- },
32067
- {
32068
- name: "mcp configure",
32069
- aliases: [],
32070
- args: "[agent]",
32071
- description: "Configure Poe MCP for your coding agent"
32072
- },
32073
- {
32074
- name: "mcp unconfigure",
32075
- aliases: [],
32076
- args: "<agent>",
32077
- description: "Remove Poe MCP configuration from your agent"
32078
- },
32079
- {
32080
- name: "experiment install",
32081
- aliases: [],
32082
- args: "[agent]",
32083
- description: "Install the experiment skill into agent configuration"
32084
- },
32085
- {
32086
- name: "skill configure",
32087
- aliases: [],
32088
- args: "[agent]",
32089
- description: "Configure agent skills to call Poe models"
32090
- },
32091
- {
32092
- name: "skill unconfigure",
32093
- aliases: [],
32094
- args: "[agent]",
32095
- description: "Remove agent skills configuration"
32096
- },
32097
- {
32098
- name: "pipeline install",
32099
- aliases: [],
32100
- args: "[agent]",
32101
- description: "Install pipeline skill into agent configuration"
32102
- },
32103
- {
32104
- name: "pipeline run",
32105
- aliases: [],
32106
- args: "",
32107
- description: "Run a fixed-step task pipeline plan"
32108
- },
32109
- {
32110
- name: "ralph init",
32111
- aliases: [],
32112
- args: "[doc]",
32113
- description: "Write Ralph config into a markdown doc frontmatter"
32114
- },
32115
- {
32116
- name: "ralph run",
32117
- aliases: [],
32118
- args: "[doc]",
32119
- description: "Run a markdown doc through repeated agent iterations"
32120
- },
32121
- {
32122
- name: "experiment run",
32123
- aliases: [],
32124
- args: "[doc]",
32125
- description: "Run an experiment doc through the autonomous experiment loop"
32126
- },
32127
- {
32128
- name: "experiment journal",
32129
- aliases: [],
32130
- args: "[doc]",
32131
- description: "Display an experiment journal as a formatted table"
32132
- },
32133
- {
32134
- name: "launch",
32135
- aliases: [],
32136
- args: "",
32137
- description: "Manage long-running host and Docker processes"
32138
- },
32139
- {
32140
- name: "github-workflows",
32141
- aliases: ["gh"],
32142
- args: "[automation]",
32143
- description: "GitHub workflow automations"
32144
- },
32145
- {
32146
- name: "usage",
32147
- aliases: ["u"],
32148
- args: "",
32149
- description: "Display current Poe compute points balance"
32150
- },
32151
- {
32152
- name: "usage list",
32153
- aliases: [],
32154
- args: "",
32155
- description: "Display usage history"
32156
- },
32157
- {
32158
- name: "utils config",
32159
- aliases: [],
32160
- args: "",
32161
- description: "Show config file paths and usage hints"
32927
+ function findCommandByPath(root, path48) {
32928
+ let current = root;
32929
+ for (const segment of path48) {
32930
+ const next = current.commands.find(
32931
+ (command) => Reflect.get(command, "_hidden") !== true && command.name() === segment
32932
+ );
32933
+ if (!next) {
32934
+ throw new Error(`Root help command is missing: ${path48.join(" ")}`);
32162
32935
  }
32163
- ];
32936
+ current = next;
32937
+ }
32938
+ return current;
32939
+ }
32940
+ function formatRootHelpCommandName(path48, command) {
32941
+ const leaf = [command.name(), ...command.aliases()].join(", ");
32942
+ return path48.length > 1 ? [...path48.slice(0, -1), leaf].join(" ") : leaf;
32943
+ }
32944
+ function splitUsageParts(usage) {
32945
+ return usage.split(" ").map((part) => part.trim()).filter((part) => part.length > 0);
32946
+ }
32947
+ function formatUsage2(usage, excludedParts) {
32948
+ return splitUsageParts(usage).filter((part) => !excludedParts.includes(part)).join(" ");
32949
+ }
32950
+ function formatRootHelpCommandArgs(command) {
32951
+ return formatUsage2(command.usage(), ["[options]", "[command]"]);
32952
+ }
32953
+ function buildRootHelpRows(root) {
32954
+ return ROOT_HELP_COMMAND_SPECS.map((spec) => {
32955
+ const command = findCommandByPath(root, spec.path);
32956
+ return {
32957
+ name: formatRootHelpCommandName(spec.path, command),
32958
+ args: spec.args ?? formatRootHelpCommandArgs(command),
32959
+ description: command.description()
32960
+ };
32961
+ });
32962
+ }
32963
+ function formatCanonicalCommandPath(cmd) {
32964
+ const parts = [];
32965
+ let current = cmd;
32966
+ while (current) {
32967
+ const name = current.name();
32968
+ if (name.length > 0) {
32969
+ parts.push(name);
32970
+ }
32971
+ if (name === "poe-code") {
32972
+ break;
32973
+ }
32974
+ current = current.parent ?? null;
32975
+ }
32976
+ return parts.reverse().join(" ");
32977
+ }
32978
+ function formatCanonicalCommandUsage(cmd) {
32979
+ const usage = formatUsage2(cmd.usage(), ["[command]"]);
32980
+ const commandPath = formatCanonicalCommandPath(cmd);
32981
+ return usage.length > 0 ? `${commandPath} ${usage}` : commandPath;
32982
+ }
32983
+ function formatHelpItem(input) {
32984
+ const itemIndent = 2;
32985
+ const spacerWidth = 2;
32986
+ const indent = " ".repeat(itemIndent);
32987
+ if (!input.description) {
32988
+ return `${indent}${input.term}`;
32989
+ }
32990
+ const paddedTerm = input.term.padEnd(
32991
+ input.termWidth + input.term.length - input.helper.displayWidth(input.term)
32992
+ );
32993
+ const remainingWidth = (input.helper.helpWidth ?? 80) - input.termWidth - spacerWidth - itemIndent;
32994
+ const descriptionIndent = `${indent}${" ".repeat(spacerWidth)}`;
32995
+ if (remainingWidth < input.helper.minWidthToWrap) {
32996
+ const descriptionWidth = Math.max(1, (input.helper.helpWidth ?? 80) - itemIndent - spacerWidth);
32997
+ const formattedDescription2 = input.helper.preformatted(input.description) ? input.description : input.helper.boxWrap(input.description, descriptionWidth);
32998
+ return `${indent}${input.term}
32999
+ ${descriptionIndent}${formattedDescription2.replace(/\n/g, `
33000
+ ${descriptionIndent}`)}`;
33001
+ }
33002
+ let formattedDescription = input.description;
33003
+ if (!input.helper.preformatted(input.description)) {
33004
+ formattedDescription = input.helper.boxWrap(input.description, remainingWidth).replace(/\n/g, `
33005
+ ${" ".repeat(input.termWidth + spacerWidth)}`);
33006
+ }
33007
+ return `${indent}${paddedTerm}${" ".repeat(spacerWidth)}${formattedDescription.replace(/\n/g, `
33008
+ ${indent}`)}`;
33009
+ }
33010
+ function formatHelpText(input) {
33011
+ const commandRows = buildRootHelpRows(input.command);
32164
33012
  const nameWidth = Math.max(
32165
33013
  0,
32166
- ...commandRows.map((row) => [row.name, ...row.aliases].join(", ").length)
33014
+ ...commandRows.map((row) => row.name.length)
32167
33015
  );
32168
33016
  const argsWidth = Math.max(0, ...commandRows.map((row) => row.args.length));
33017
+ const termWidth = nameWidth + 1 + argsWidth;
32169
33018
  const cmd = (row) => {
32170
- const displayName = [row.name, ...row.aliases].join(", ");
32171
- const name = text.command(displayName.padEnd(nameWidth));
33019
+ const name = text.command(row.name.padEnd(nameWidth));
32172
33020
  const args = row.args.length > 0 ? text.argument(row.args.padEnd(argsWidth)) : " ".repeat(argsWidth);
32173
- return ` ${name} ${args} ${row.description}`;
33021
+ return formatHelpItem({
33022
+ term: `${name} ${args}`,
33023
+ termWidth,
33024
+ description: row.description,
33025
+ helper: input.helper
33026
+ });
32174
33027
  };
32175
33028
  return [
32176
33029
  text.heading(input.heading),
@@ -32190,23 +33043,16 @@ function formatHelpText(input) {
32190
33043
  }
32191
33044
  function formatSubcommandHelp(cmd, helper) {
32192
33045
  const termWidth = helper.padWidth(cmd, helper);
32193
- const itemIndentWidth = 2;
32194
- const itemSeparatorWidth = 2;
32195
- const padWidth = termWidth + itemSeparatorWidth;
32196
- const indent = " ".repeat(itemIndentWidth);
32197
- const formatItem = (term, description, style) => {
32198
- const padding = " ".repeat(Math.max(0, padWidth - term.length));
32199
- const styledTerm = `${style(term)}${padding}`;
32200
- if (!description) {
32201
- return style(term);
32202
- }
32203
- return `${styledTerm}${description}`;
32204
- };
32205
- const indentBlock = (value) => value.split("\n").map((line) => `${indent}${line}`).join("\n");
32206
- const formatList = (items) => items.map(indentBlock).join("\n");
33046
+ const formatItem = (term, description, style) => formatHelpItem({
33047
+ term: style(term),
33048
+ termWidth,
33049
+ description,
33050
+ helper
33051
+ });
33052
+ const formatList = (items) => items.join("\n");
32207
33053
  const output = [];
32208
33054
  output.push(text.heading(formatCommandHeader(cmd)), "");
32209
- output.push(`${text.section("Usage:")} ${text.usageCommand(helper.commandUsage(cmd))}`, "");
33055
+ output.push(`${text.section("Usage:")} ${text.usageCommand(formatCanonicalCommandUsage(cmd))}`, "");
32210
33056
  const commandDescription = helper.commandDescription(cmd);
32211
33057
  if (commandDescription.length > 0) {
32212
33058
  output.push(commandDescription, "");
@@ -32289,7 +33135,7 @@ function bootstrapProgram(container) {
32289
33135
  program.name("poe-code").description("Configure Poe API integrations for local developer tooling.").option("-y, --yes", "Accept defaults without prompting.").option("--dry-run", "Simulate commands without writing changes.").option("--verbose", "Show verbose logs.").helpOption("-h, --help", "Display help for command").showHelpAfterError(false).showSuggestionAfterError(true).configureHelp({
32290
33136
  formatHelp: (cmd, helper) => {
32291
33137
  if (cmd.name() === "poe-code") {
32292
- return formatHelpText({ heading, usageCommand, helpCommand });
33138
+ return formatHelpText({ command: cmd, heading, usageCommand, helpCommand, helper });
32293
33139
  }
32294
33140
  return formatSubcommandHelp(cmd, helper);
32295
33141
  }
@@ -32310,6 +33156,7 @@ function bootstrapProgram(container) {
32310
33156
  registerMcpCommand(program, container);
32311
33157
  registerSkillCommand(program, container);
32312
33158
  registerPipelineCommand(program, container);
33159
+ registerPlanCommand(program, container);
32313
33160
  registerRalphCommand(program, container);
32314
33161
  registerExperimentCommand(program, container);
32315
33162
  registerLaunchCommand(program, container);
@@ -32317,7 +33164,7 @@ function bootstrapProgram(container) {
32317
33164
  const originalArgv = [...process.argv];
32318
33165
  process.argv = buildCmdkitArgv(originalArgv, ghGroup);
32319
33166
  try {
32320
- await runCLI(ghGroup);
33167
+ await runCLI(ghGroup, { rootDisplayName: `Poe - ${ghGroup.name}`, rootUsageName: `${usageCommand} ${ghGroup.name}` });
32321
33168
  } finally {
32322
33169
  process.argv = originalArgv;
32323
33170
  }
@@ -32356,7 +33203,7 @@ function suppressCommanderOutput(command) {
32356
33203
  suppressCommanderOutput(child);
32357
33204
  }
32358
33205
  }
32359
- var FORWARDABLE_CMDKIT_FLAGS;
33206
+ var ROOT_HELP_COMMAND_SPECS, FORWARDABLE_CMDKIT_FLAGS;
32360
33207
  var init_program = __esm({
32361
33208
  async "src/cli/program.ts"() {
32362
33209
  "use strict";
@@ -32382,12 +33229,46 @@ var init_program = __esm({
32382
33229
  init_usage();
32383
33230
  init_models2();
32384
33231
  await init_pipeline3();
33232
+ init_plan();
32385
33233
  await init_ralph3();
32386
33234
  await init_experiment2();
32387
33235
  init_launch2();
32388
33236
  init_package();
32389
33237
  init_command_not_found();
32390
33238
  init_execution_context();
33239
+ ROOT_HELP_COMMAND_SPECS = [
33240
+ { path: ["install"] },
33241
+ { path: ["configure"] },
33242
+ { path: ["unconfigure"] },
33243
+ { path: ["login"] },
33244
+ { path: ["logout"] },
33245
+ { path: ["auth"] },
33246
+ { path: ["agent"] },
33247
+ { path: ["spawn"] },
33248
+ { path: ["wrap"] },
33249
+ { path: ["test"] },
33250
+ { path: ["generate"] },
33251
+ { path: ["models"] },
33252
+ { path: ["mcp", "configure"] },
33253
+ { path: ["mcp", "unconfigure"] },
33254
+ { path: ["skill", "configure"] },
33255
+ { path: ["skill", "unconfigure"] },
33256
+ { path: ["pipeline", "install"] },
33257
+ { path: ["pipeline", "run"] },
33258
+ { path: ["pipeline", "validate"] },
33259
+ { path: ["plan"] },
33260
+ { path: ["experiment", "install"] },
33261
+ { path: ["experiment", "run"] },
33262
+ { path: ["experiment", "journal"] },
33263
+ { path: ["experiment", "validate"] },
33264
+ { path: ["ralph", "init"] },
33265
+ { path: ["ralph", "run"] },
33266
+ { path: ["launch"] },
33267
+ { path: ["github-workflows"], args: "[automation]" },
33268
+ { path: ["usage"] },
33269
+ { path: ["usage", "list"] },
33270
+ { path: ["utils", "config"] }
33271
+ ];
32391
33272
  FORWARDABLE_CMDKIT_FLAGS = /* @__PURE__ */ new Set(["-y", "--yes", "--verbose"]);
32392
33273
  }
32393
33274
  });