poe-code 3.0.26 → 3.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -352,16 +352,16 @@ function getConfigFormat(pathOrFormat) {
352
352
  }
353
353
  return formatRegistry[formatName];
354
354
  }
355
- function detectFormat(path16) {
356
- const ext = getExtension(path16);
355
+ function detectFormat(path17) {
356
+ const ext = getExtension(path17);
357
357
  return extensionMap[ext];
358
358
  }
359
- function getExtension(path16) {
360
- const lastDot = path16.lastIndexOf(".");
359
+ function getExtension(path17) {
360
+ const lastDot = path17.lastIndexOf(".");
361
361
  if (lastDot === -1) {
362
362
  return "";
363
363
  }
364
- return path16.slice(lastDot).toLowerCase();
364
+ return path17.slice(lastDot).toLowerCase();
365
365
  }
366
366
  var formatRegistry, extensionMap;
367
367
  var init_formats = __esm({
@@ -1255,38 +1255,38 @@ import { createTwoFilesPatch } from "diff";
1255
1255
  import chalk from "chalk";
1256
1256
  function createDryRunFileSystem(base, recorder) {
1257
1257
  const proxy = {
1258
- async readFile(path16, encoding) {
1258
+ async readFile(path17, encoding) {
1259
1259
  if (encoding) {
1260
- return base.readFile(path16, encoding);
1260
+ return base.readFile(path17, encoding);
1261
1261
  }
1262
- return base.readFile(path16);
1262
+ return base.readFile(path17);
1263
1263
  },
1264
- async writeFile(path16, data, options) {
1265
- const previousContent = await tryReadText(base, path16);
1264
+ async writeFile(path17, data, options) {
1265
+ const previousContent = await tryReadText(base, path17);
1266
1266
  const nextContent = formatData(data, options?.encoding);
1267
1267
  recorder.record({
1268
1268
  type: "writeFile",
1269
- path: path16,
1269
+ path: path17,
1270
1270
  nextContent,
1271
1271
  previousContent
1272
1272
  });
1273
1273
  },
1274
- async mkdir(path16, options) {
1275
- recorder.record({ type: "mkdir", path: path16, options });
1274
+ async mkdir(path17, options) {
1275
+ recorder.record({ type: "mkdir", path: path17, options });
1276
1276
  },
1277
- async stat(path16) {
1278
- return base.stat(path16);
1277
+ async stat(path17) {
1278
+ return base.stat(path17);
1279
1279
  },
1280
- async unlink(path16) {
1281
- recorder.record({ type: "unlink", path: path16 });
1280
+ async unlink(path17) {
1281
+ recorder.record({ type: "unlink", path: path17 });
1282
1282
  },
1283
- async readdir(path16) {
1284
- return base.readdir(path16);
1283
+ async readdir(path17) {
1284
+ return base.readdir(path17);
1285
1285
  }
1286
1286
  };
1287
1287
  if (typeof base.rm === "function") {
1288
- proxy.rm = async (path16, options) => {
1289
- recorder.record({ type: "rm", path: path16, options });
1288
+ proxy.rm = async (path17, options) => {
1289
+ recorder.record({ type: "rm", path: path17, options });
1290
1290
  };
1291
1291
  }
1292
1292
  if (typeof base.copyFile === "function") {
@@ -1376,8 +1376,8 @@ function describeWriteChange(previous, next) {
1376
1376
  }
1377
1377
  return "update";
1378
1378
  }
1379
- function renderWriteCommand(path16, change) {
1380
- const command = `cat > ${path16}`;
1379
+ function renderWriteCommand(path17, change) {
1380
+ const command = `cat > ${path17}`;
1381
1381
  if (change === "create") {
1382
1382
  return renderOperationCommand(command, chalk.green, "# create");
1383
1383
  }
@@ -1539,9 +1539,9 @@ function redactTomlLine(line) {
1539
1539
  }
1540
1540
  return line;
1541
1541
  }
1542
- async function tryReadText(base, path16) {
1542
+ async function tryReadText(base, path17) {
1543
1543
  try {
1544
- return await base.readFile(path16, "utf8");
1544
+ return await base.readFile(path17, "utf8");
1545
1545
  } catch (error2) {
1546
1546
  if (isNotFound(error2)) {
1547
1547
  return null;
@@ -1597,7 +1597,7 @@ var init_constants = __esm({
1597
1597
  "src/cli/constants.ts"() {
1598
1598
  "use strict";
1599
1599
  FRONTIER_MODELS = [
1600
- "anthropic/claude-opus-4.5",
1600
+ "anthropic/claude-opus-4.6",
1601
1601
  "anthropic/claude-sonnet-4.5",
1602
1602
  "openai/gpt-5.2",
1603
1603
  "google/gemini-3-pro"
@@ -1610,7 +1610,7 @@ var init_constants = __esm({
1610
1610
  CLAUDE_CODE_VARIANTS = {
1611
1611
  haiku: "anthropic/claude-haiku-4.5",
1612
1612
  sonnet: "anthropic/claude-sonnet-4.5",
1613
- opus: "anthropic/claude-opus-4.5"
1613
+ opus: "anthropic/claude-opus-4.6"
1614
1614
  };
1615
1615
  DEFAULT_CLAUDE_CODE_MODEL = CLAUDE_CODE_VARIANTS.opus;
1616
1616
  CODEX_MODELS = [
@@ -5438,8 +5438,8 @@ var require_utils = __commonJS({
5438
5438
  }
5439
5439
  return ind;
5440
5440
  }
5441
- function removeDotSegments(path16) {
5442
- let input = path16;
5441
+ function removeDotSegments(path17) {
5442
+ let input = path17;
5443
5443
  const output = [];
5444
5444
  let nextSlash = -1;
5445
5445
  let len = 0;
@@ -5638,8 +5638,8 @@ var require_schemes = __commonJS({
5638
5638
  wsComponent.secure = void 0;
5639
5639
  }
5640
5640
  if (wsComponent.resourceName) {
5641
- const [path16, query] = wsComponent.resourceName.split("?");
5642
- wsComponent.path = path16 && path16 !== "/" ? path16 : void 0;
5641
+ const [path17, query] = wsComponent.resourceName.split("?");
5642
+ wsComponent.path = path17 && path17 !== "/" ? path17 : void 0;
5643
5643
  wsComponent.query = query;
5644
5644
  wsComponent.resourceName = void 0;
5645
5645
  }
@@ -14691,10 +14691,17 @@ var require_dist = __commonJS({
14691
14691
  }
14692
14692
  });
14693
14693
 
14694
+ // src/templates/ralph/PROMPT_worktree_merge.md
14695
+ var require_PROMPT_worktree_merge = __commonJS({
14696
+ "src/templates/ralph/PROMPT_worktree_merge.md"(exports, module) {
14697
+ module.exports = "# Worktree Merge\n\nYou are an autonomous coding agent. Your task is to merge worktree `{{WORKTREE_NAME}}` into `{{BASE_BRANCH}}`.\n\n## Worktree\n\n| Key | Value |\n|-----|-------|\n| Path | `{{WORKTREE_PATH}}` |\n| Branch | `{{WORKTREE_BRANCH}}` |\n| Base branch | `{{BASE_BRANCH}}` |\n| Main cwd | `{{MAIN_CWD}}` |\n| Plan file | `{{PLAN_PATH}}` |\n| Story ID | `{{STORY_ID}}` |\n\n## Steps\n\n1. Understand what the worktree branch changed \u2014 read the plan file (if present), inspect `git log` and `git diff` in the worktree.\n2. `cd {{WORKTREE_PATH}}` and `git rebase {{BASE_BRANCH}}`. Resolve any conflicts preserving both sides' intent.\n3. Run the quality gates from the plan file (if present), otherwise run the project's default test/lint commands.\n4. `cd {{MAIN_CWD}}` and `git merge --ff-only {{WORKTREE_BRANCH}}`.\n5. `git worktree remove {{WORKTREE_PATH}}` and `git branch -D {{WORKTREE_BRANCH}}`.\n\nIf the rebase fails or conflicts cannot be resolved, run `git rebase --abort` and exit with a non-zero status.\n";
14698
+ }
14699
+ });
14700
+
14694
14701
  // src/templates/ralph/PROMPT_PARTIAL_plan.md
14695
14702
  var require_PROMPT_PARTIAL_plan = __commonJS({
14696
14703
  "src/templates/ralph/PROMPT_PARTIAL_plan.md"(exports, module) {
14697
- module.exports = "# Plan Generation\n\nYou are an agent that generates a Ralph PRD file (YAML) based on a user request. Your ONLY output is a plan file \u2014 do NOT write or modify any code. Follow these phases in order. Keep each phase tight\u2014write only what's needed to move forward.\n\n---\n\n## Phase 1: Understand\n\nBefore touching code, understand the problem and the codebase.\n\n- **Read first.** Never propose changes to code you haven't read. Search for existing patterns, utilities, and conventions.\n- **Ask why.** What problem does this solve? Why now? What happens if we don't do it?\n- **Challenge assumptions.** Question the framing. Restate the problem in your own words.\n- **Visualize.** Use ASCII diagrams for architecture, data flow, state machines\u2014whenever structure aids clarity.\n- **Surface unknowns.** What could go wrong? What don't we know yet? What needs investigation?\n\nStay here until the problem shape is clear. Don't rush to solutions.\n\n---\n\n## Phase 2: Propose\n\nEstablish scope and intent. Write a short proposal:\n\n- **Why**: 1-2 sentences. The problem or opportunity.\n- **What changes**: Bullet list of concrete changes. Be specific.\n- **Impact**: What code, APIs, systems, or users are affected.\n\nKeep it to half a page. Focus on the \"why\" not the \"how.\"\n\n---\n\n## Phase 3: Specify\n\nDefine **what** the system should do in testable terms.\n\nFor each new or changed behavior, write requirements:\n\n```\n### Requirement: <name>\n<Description using precise language \u2014 SHALL, MUST for normative statements>\n\n#### Scenario: <name>\n- WHEN <condition>\n- THEN <expected outcome>\n```\n\nRules:\n\n- Every requirement needs at least one scenario.\n- Scenarios are test cases. If you can't write a scenario, the requirement isn't clear enough.\n- For modifications to existing behavior, state the full updated requirement, not just the diff.\n\n---\n\n## Phase 4: Design\n\nExplain **how** you'll build it. Only include this for non-trivial changes (cross-cutting, new dependencies, architectural decisions, ambiguity worth resolving upfront).\n\n- **Context**: Current state, constraints.\n- **Goals / Non-goals**: What's in scope and what's explicitly out.\n- **Decisions**: Key technical choices. For each: what you chose, what you rejected, and why.\n- **Risks / Trade-offs**: What could go wrong \u2192 how you'll mitigate it.\n\nFocus on architecture and approach. Don't describe every line of code.\n\n---\n\n## Phase 5: Tasks\n\nBreak the work into stories and write the plan YAML file.\n\n### YAML Structure\n\n- Create (or overwrite) the file at the output path.\n- The file must be valid YAML.\n- Use this structure (minimum):\n - version: 1\n - project: <short name>\n - overview: <1-3 paragraphs \u2014 include the proposal from Phase 2 and key design decisions from Phase 4>\n - goals: [ ... ]\n - nonGoals: [ ... ]\n - qualityGates:\n - npm run test\n - npm run lint\n - requirements: [ ... ] (from Phase 3, each with scenarios)\n - stories: [ ... ]\n\n### Stories\n\n- Stories should be actionable, small, and testable. Keep it to one story per atomic feature.\n- Each story must include:\n - id: \"US-###\" (sequential, starting at US-001)\n - title\n - status: open\n - dependsOn: [] (or list of story IDs)\n - description: \"As a user, I want ...\"\n - acceptanceCriteria: [\"...\", \"...\"] (derived from Phase 3 scenarios)\n\n---\n\n## Validation\n\nAfter writing the plan file, validate it by running:\n\n```\npoe-code ralph agent validate-plan --plan <output-path>\n```\n\nIf validation fails, fix the errors and re-validate until the plan passes.\n\n## Done Signal\n\nAfter the plan is validated, print a single line confirming the path, e.g.:\n\n```\nWrote plan to <output-path>\n\nRun `poe-code ralph build`\n\n```\n";
14704
+ module.exports = "# Plan Generation\n\nYou are an agent that generates a plan file (YAML) based on a user request. Your ONLY output is a plan file \u2014 do NOT write or modify any code.\n\nYou MUST follow these phases in the order and make sure that you communicate to user.\n\nKeep each phase concise only what's needed to move forward.\n\n---\n\n## Phase 1: Understand\n\nBefore touching code, understand the problem and the codebase.\n\n- **Read first.** Never propose changes to code you haven't read. Search for existing patterns, utilities, and conventions.\n- **Ask why.** What problem does this solve? Why now? What happens if we don't do it?\n- **Challenge assumptions.** Question the framing. Restate the problem in your own words.\n- **Visualize.** Use ASCII diagrams for architecture, data flow, state machines\u2014whenever structure aids clarity.\n- **Surface unknowns.** What could go wrong? What don't we know yet? What needs investigation?\n\nStay here until the problem shape is clear. Don't rush to solutions.\n\n---\n\n## Phase 2: Propose\n\nEstablish scope and intent. Write a short proposal:\n\n- **Why**: 1-2 sentences. The problem or opportunity.\n- **What changes**: Bullet list of concrete changes. Be specific.\n- **Impact**: What code, APIs, systems, or users are affected.\n\nKeep it to half a page. Focus on the \"why\" not the \"how.\"\n\n---\n\n## Phase 3: Specify\n\nDefine **what** the system should do in testable terms.\n\nFor each new or changed behavior, write requirements:\n\n```\n### Requirement: <name>\n<Description using precise language \u2014 SHALL, MUST for normative statements>\n\n#### Scenario: <name>\n- WHEN <condition>\n- THEN <expected outcome>\n```\n\nRules:\n\n- Every requirement needs at least one scenario.\n- Scenarios are test cases. If you can't write a scenario, the requirement isn't clear enough.\n- For modifications to existing behavior, state the full updated requirement, not just the diff.\n\n---\n\n## Phase 4: Design\n\nExplain **how** you'll build it. Only include this for non-trivial changes (cross-cutting, new dependencies, architectural decisions, ambiguity worth resolving upfront).\n\n- **Context**: Current state, constraints.\n- **Goals / Non-goals**: What's in scope and what's explicitly out.\n- **Decisions**: Key technical choices. For each: what you chose, what you rejected, and why.\n- **Risks / Trade-offs**: What could go wrong \u2192 how you'll mitigate it.\n\nFocus on architecture and approach. Don't describe every line of code.\n\n---\n\n## Phase 5: Tasks\n\nBreak the work into stories and write the plan YAML file.\n\n### YAML Structure\n\n- Create (or overwrite) the file at the output path.\n- The file must be valid YAML.\n- Use this structure (minimum):\n - version: 1\n - project: <short name>\n - overview: <1-3 paragraphs \u2014 include the proposal from Phase 2 and key design decisions from Phase 4>\n - goals: [ ... ]\n - nonGoals: [ ... ]\n - qualityGates:\n - npm run test\n - npm run lint\n - requirements: [ ... ] (from Phase 3, each with scenarios)\n - stories: [ ... ]\n\n### Stories\n\n- Stories should be actionable, small, and testable. Keep it to one story per atomic feature.\n- Each story must include:\n - id: \"US-###\" (sequential, starting at US-001)\n - title\n - status: open\n - dependsOn: [] (or list of story IDs)\n - description: \"As a user, I want ...\"\n - acceptanceCriteria: [\"...\", \"...\"] (derived from Phase 3 scenarios)\n\n---\n\n## Validation\n\nAfter writing the plan file, validate it by running:\n\n```\npoe-code ralph agent validate-plan --plan <output-path>\n```\n\nIf validation fails, fix the errors and re-validate until the plan passes.\n\n## Done Signal\n\nAfter the plan is validated, print a single line confirming the path, e.g.:\n\n```\nWrote plan to <output-path>\n\nRun `poe-code ralph build`\n\n```\n";
14698
14705
  }
14699
14706
  });
14700
14707
 
@@ -16508,21 +16515,21 @@ async function* adaptClaude(lines) {
16508
16515
  if (blockType !== "tool_result") continue;
16509
16516
  const kind = toolKindsById.get(item.tool_use_id);
16510
16517
  toolKindsById.delete(item.tool_use_id);
16511
- let path16 = "";
16518
+ let path17 = "";
16512
16519
  if (typeof item.content === "string") {
16513
- path16 = item.content;
16520
+ path17 = item.content;
16514
16521
  } else {
16515
16522
  try {
16516
- path16 = JSON.stringify(item.content);
16523
+ path17 = JSON.stringify(item.content);
16517
16524
  } catch {
16518
- path16 = String(item.content);
16525
+ path17 = String(item.content);
16519
16526
  }
16520
16527
  }
16521
16528
  yield {
16522
16529
  event: "tool_complete",
16523
16530
  id: item.tool_use_id,
16524
16531
  kind,
16525
- path: path16
16532
+ path: path17
16526
16533
  };
16527
16534
  }
16528
16535
  }
@@ -16617,10 +16624,10 @@ async function* adaptCodex(lines) {
16617
16624
  const kindFromStart = toolKindById.get(item.id);
16618
16625
  const kind = kindFromStart ?? (itemType === "command_execution" ? "exec" : itemType === "file_edit" ? "edit" : "other");
16619
16626
  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;
16620
- const path16 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
16627
+ const path17 = titleFromEvent ?? toolTitleById.get(item.id) ?? "";
16621
16628
  toolTitleById.delete(item.id);
16622
16629
  toolKindById.delete(item.id);
16623
- yield { event: "tool_complete", id: item.id, kind, path: path16 };
16630
+ yield { event: "tool_complete", id: item.id, kind, path: path17 };
16624
16631
  }
16625
16632
  }
16626
16633
  }
@@ -18336,21 +18343,21 @@ function createSdkContainer(options) {
18336
18343
  });
18337
18344
  loggerFactory.setErrorLogger(errorLogger);
18338
18345
  const asyncFs = {
18339
- readFile: ((path16, encoding) => {
18346
+ readFile: ((path17, encoding) => {
18340
18347
  if (encoding) {
18341
- return fs2.readFile(path16, encoding);
18348
+ return fs2.readFile(path17, encoding);
18342
18349
  }
18343
- return fs2.readFile(path16);
18350
+ return fs2.readFile(path17);
18344
18351
  }),
18345
- writeFile: (path16, data, opts) => fs2.writeFile(path16, data, opts),
18346
- mkdir: (path16, opts) => fs2.mkdir(path16, opts).then(() => {
18352
+ writeFile: (path17, data, opts) => fs2.writeFile(path17, data, opts),
18353
+ mkdir: (path17, opts) => fs2.mkdir(path17, opts).then(() => {
18347
18354
  }),
18348
- stat: (path16) => fs2.stat(path16),
18349
- rm: (path16, opts) => fs2.rm(path16, opts),
18350
- unlink: (path16) => fs2.unlink(path16),
18351
- readdir: (path16) => fs2.readdir(path16),
18355
+ stat: (path17) => fs2.stat(path17),
18356
+ rm: (path17, opts) => fs2.rm(path17, opts),
18357
+ unlink: (path17) => fs2.unlink(path17),
18358
+ readdir: (path17) => fs2.readdir(path17),
18352
18359
  copyFile: (src, dest) => fs2.copyFile(src, dest),
18353
- chmod: (path16, mode) => fs2.chmod(path16, mode)
18360
+ chmod: (path17, mode) => fs2.chmod(path17, mode)
18354
18361
  };
18355
18362
  const contextFactory = createCommandContextFactory({ fs: asyncFs });
18356
18363
  const noopPrompts = async () => {
@@ -20766,8 +20773,8 @@ function getErrorMap() {
20766
20773
 
20767
20774
  // node_modules/zod/v3/helpers/parseUtil.js
20768
20775
  var makeIssue = (params) => {
20769
- const { data, path: path16, errorMaps, issueData } = params;
20770
- const fullPath = [...path16, ...issueData.path || []];
20776
+ const { data, path: path17, errorMaps, issueData } = params;
20777
+ const fullPath = [...path17, ...issueData.path || []];
20771
20778
  const fullIssue = {
20772
20779
  ...issueData,
20773
20780
  path: fullPath
@@ -20882,11 +20889,11 @@ var errorUtil;
20882
20889
 
20883
20890
  // node_modules/zod/v3/types.js
20884
20891
  var ParseInputLazyPath = class {
20885
- constructor(parent, value, path16, key) {
20892
+ constructor(parent, value, path17, key) {
20886
20893
  this._cachedPath = [];
20887
20894
  this.parent = parent;
20888
20895
  this.data = value;
20889
- this._path = path16;
20896
+ this._path = path17;
20890
20897
  this._key = key;
20891
20898
  }
20892
20899
  get path() {
@@ -24530,10 +24537,10 @@ function mergeDefs(...defs) {
24530
24537
  function cloneDef(schema) {
24531
24538
  return mergeDefs(schema._zod.def);
24532
24539
  }
24533
- function getElementAtPath(obj, path16) {
24534
- if (!path16)
24540
+ function getElementAtPath(obj, path17) {
24541
+ if (!path17)
24535
24542
  return obj;
24536
- return path16.reduce((acc, key) => acc?.[key], obj);
24543
+ return path17.reduce((acc, key) => acc?.[key], obj);
24537
24544
  }
24538
24545
  function promiseAllObject(promisesObj) {
24539
24546
  const keys = Object.keys(promisesObj);
@@ -24916,11 +24923,11 @@ function aborted(x, startIndex = 0) {
24916
24923
  }
24917
24924
  return false;
24918
24925
  }
24919
- function prefixIssues(path16, issues) {
24926
+ function prefixIssues(path17, issues) {
24920
24927
  return issues.map((iss) => {
24921
24928
  var _a2;
24922
24929
  (_a2 = iss).path ?? (_a2.path = []);
24923
- iss.path.unshift(path16);
24930
+ iss.path.unshift(path17);
24924
24931
  return iss;
24925
24932
  });
24926
24933
  }
@@ -33891,7 +33898,7 @@ async function displayVersion(container, currentVersion) {
33891
33898
  }
33892
33899
 
33893
33900
  // src/cli/commands/ralph.ts
33894
- import path15 from "node:path";
33901
+ import path16 from "node:path";
33895
33902
 
33896
33903
  // packages/ralph/src/build/loop.ts
33897
33904
  import { basename as basename2, dirname as dirname6, resolve as resolvePath2 } from "node:path";
@@ -34046,6 +34053,28 @@ async function createWorktree(opts) {
34046
34053
  return entry;
34047
34054
  }
34048
34055
 
34056
+ // packages/worktree/src/list.ts
34057
+ async function listWorktrees(cwd, registryFile, deps) {
34058
+ const registry2 = await readRegistry(registryFile, deps.fs);
34059
+ const gitOutput = await deps.exec("git worktree list --porcelain", {
34060
+ cwd
34061
+ });
34062
+ const gitPaths = parseGitWorktreeList(gitOutput.stdout);
34063
+ return registry2.worktrees.map((entry) => ({
34064
+ ...entry,
34065
+ gitExists: gitPaths.has(entry.path)
34066
+ }));
34067
+ }
34068
+ function parseGitWorktreeList(output) {
34069
+ const paths = /* @__PURE__ */ new Set();
34070
+ for (const line of output.split("\n")) {
34071
+ if (line.startsWith("worktree ")) {
34072
+ paths.add(line.slice("worktree ".length));
34073
+ }
34074
+ }
34075
+ return paths;
34076
+ }
34077
+
34049
34078
  // packages/ralph/src/completion/detector.ts
34050
34079
  function detectCompletion(output) {
34051
34080
  return output.includes("<promise>COMPLETE</promise>");
@@ -34120,13 +34149,13 @@ function getDirtyFiles(cwd) {
34120
34149
  for (const line of lines) {
34121
34150
  if (!line) continue;
34122
34151
  if (line.length < 4) continue;
34123
- let path16 = line.slice(3).trim();
34152
+ let path17 = line.slice(3).trim();
34124
34153
  const renameArrow = " -> ";
34125
- const arrowIndex = path16.lastIndexOf(renameArrow);
34154
+ const arrowIndex = path17.lastIndexOf(renameArrow);
34126
34155
  if (arrowIndex >= 0) {
34127
- path16 = path16.slice(arrowIndex + renameArrow.length).trim();
34156
+ path17 = path17.slice(arrowIndex + renameArrow.length).trim();
34128
34157
  }
34129
- if (path16) files.push(path16);
34158
+ if (path17) files.push(path17);
34130
34159
  }
34131
34160
  return files;
34132
34161
  }
@@ -34269,17 +34298,17 @@ function serializePlan(prd) {
34269
34298
  return yaml.endsWith("\n") ? yaml : `${yaml}
34270
34299
  `;
34271
34300
  }
34272
- function lockPlanFile(path16) {
34273
- return lockFile(path16, { retries: 20, minTimeout: 25, maxTimeout: 250 });
34301
+ function lockPlanFile(path17) {
34302
+ return lockFile(path17, { retries: 20, minTimeout: 25, maxTimeout: 250 });
34274
34303
  }
34275
- async function writePlan(path16, prd, options = {}) {
34304
+ async function writePlan(path17, prd, options = {}) {
34276
34305
  const fs3 = options.fs ?? fsPromises2;
34277
34306
  const lock = options.lock ?? lockPlanFile;
34278
- await fs3.mkdir(dirname3(path16), { recursive: true });
34279
- const release = await lock(path16);
34307
+ await fs3.mkdir(dirname3(path17), { recursive: true });
34308
+ const release = await lock(path17);
34280
34309
  try {
34281
34310
  const yaml = serializePlan(prd);
34282
- await fs3.writeFile(path16, yaml, { encoding: "utf8" });
34311
+ await fs3.writeFile(path17, yaml, { encoding: "utf8" });
34283
34312
  } finally {
34284
34313
  await release();
34285
34314
  }
@@ -34351,8 +34380,8 @@ function selectStory(prd, options = {}) {
34351
34380
  // packages/ralph/src/story/updater.ts
34352
34381
  import { dirname as dirname4 } from "node:path";
34353
34382
  import * as fsPromises3 from "node:fs/promises";
34354
- function lockPlanFile2(path16) {
34355
- return lockFile(path16, { retries: 20, minTimeout: 25, maxTimeout: 250 });
34383
+ function lockPlanFile2(path17) {
34384
+ return lockFile(path17, { retries: 20, minTimeout: 25, maxTimeout: 250 });
34356
34385
  }
34357
34386
  function assertStoryStatus(value) {
34358
34387
  if (value === "open") return;
@@ -34425,9 +34454,9 @@ function appendSection(lines, title, items, options) {
34425
34454
  }
34426
34455
  lines.push("");
34427
34456
  }
34428
- async function writeRunMeta(path16, metadata, options = {}) {
34457
+ async function writeRunMeta(path17, metadata, options = {}) {
34429
34458
  const fs3 = options.fs ?? fsPromises4;
34430
- await fs3.mkdir(dirname5(path16), { recursive: true });
34459
+ await fs3.mkdir(dirname5(path17), { recursive: true });
34431
34460
  const lines = [];
34432
34461
  lines.push("# Ralph Run Summary", "");
34433
34462
  lines.push(`- Run ID: ${metadata.runId}`);
@@ -34456,7 +34485,7 @@ async function writeRunMeta(path16, metadata, options = {}) {
34456
34485
  const git = metadata.git ?? null;
34457
34486
  if (!git) {
34458
34487
  lines.push("");
34459
- await fs3.writeFile(path16, lines.join("\n"), { encoding: "utf8" });
34488
+ await fs3.writeFile(path17, lines.join("\n"), { encoding: "utf8" });
34460
34489
  return;
34461
34490
  }
34462
34491
  lines.push("", "## Git");
@@ -34471,7 +34500,7 @@ async function writeRunMeta(path16, metadata, options = {}) {
34471
34500
  lines.push("");
34472
34501
  } else {
34473
34502
  lines.push("");
34474
- await fs3.writeFile(path16, lines.join("\n"), { encoding: "utf8" });
34503
+ await fs3.writeFile(path17, lines.join("\n"), { encoding: "utf8" });
34475
34504
  return;
34476
34505
  }
34477
34506
  if (git.commits !== void 0 && git.commits !== null) {
@@ -34491,7 +34520,7 @@ async function writeRunMeta(path16, metadata, options = {}) {
34491
34520
  appendSection(lines, "### Uncommitted Changes", git.dirtyFiles, {
34492
34521
  emptyLabel: "(none)"
34493
34522
  });
34494
- await fs3.writeFile(path16, lines.join("\n"), { encoding: "utf8" });
34523
+ await fs3.writeFile(path17, lines.join("\n"), { encoding: "utf8" });
34495
34524
  }
34496
34525
 
34497
34526
  // packages/ralph/src/build/overbaking.ts
@@ -34564,9 +34593,9 @@ async function defaultStreamingSpawn(agentId, options) {
34564
34593
  exitCode: result.exitCode
34565
34594
  };
34566
34595
  }
34567
- function absPath(cwd, path16) {
34568
- if (!path16) return resolvePath2(cwd);
34569
- return path16.startsWith("/") ? path16 : resolvePath2(cwd, path16);
34596
+ function absPath(cwd, path17) {
34597
+ if (!path17) return resolvePath2(cwd);
34598
+ return path17.startsWith("/") ? path17 : resolvePath2(cwd, path17);
34570
34599
  }
34571
34600
  function pad2(value) {
34572
34601
  return value < 10 ? `0${value}` : String(value);
@@ -34616,8 +34645,8 @@ async function appendToErrorsLog(fs3, errorsLogPath, message) {
34616
34645
  await fs3.mkdir(dirname6(errorsLogPath), { recursive: true });
34617
34646
  await fs3.writeFile(errorsLogPath, `${previous}${next}`, { encoding: "utf8" });
34618
34647
  }
34619
- function lockPlanFile3(path16) {
34620
- return lockFile(path16, { retries: 20, minTimeout: 25, maxTimeout: 250 });
34648
+ function lockPlanFile3(path17) {
34649
+ return lockFile(path17, { retries: 20, minTimeout: 25, maxTimeout: 250 });
34621
34650
  }
34622
34651
  function getCurrentBranch(cwd) {
34623
34652
  try {
@@ -34773,7 +34802,7 @@ async function buildLoop(options) {
34773
34802
  });
34774
34803
  worktreeBranch = entry.branch;
34775
34804
  const worktreePath = entry.path;
34776
- const symlinkFn = fs3.symlink ?? ((target, path16) => fsPromises5.symlink(target, path16));
34805
+ const symlinkFn = fs3.symlink ?? ((target, path17) => fsPromises5.symlink(target, path17));
34777
34806
  const exec = worktreeDeps.exec;
34778
34807
  const dirsToLink = [".poe-code-ralph", ".agents/poe-code-ralph"];
34779
34808
  for (const dir of dirsToLink) {
@@ -35194,27 +35223,27 @@ function formatTimestamp2(date4) {
35194
35223
  const seconds = pad22(date4.getSeconds());
35195
35224
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
35196
35225
  }
35197
- function validateLogPath(path16) {
35198
- if (typeof path16 !== "string" || path16.trim().length === 0) {
35226
+ function validateLogPath(path17) {
35227
+ if (typeof path17 !== "string" || path17.trim().length === 0) {
35199
35228
  throw new Error(
35200
- `Invalid activity log path: expected a non-empty string, got ${String(path16)}`
35229
+ `Invalid activity log path: expected a non-empty string, got ${String(path17)}`
35201
35230
  );
35202
35231
  }
35203
- if (path16.includes("\0")) {
35232
+ if (path17.includes("\0")) {
35204
35233
  throw new Error("Invalid activity log path: contains null byte");
35205
35234
  }
35206
35235
  }
35207
- async function logActivity(path16, message, options = {}) {
35208
- validateLogPath(path16);
35236
+ async function logActivity(path17, message, options = {}) {
35237
+ validateLogPath(path17);
35209
35238
  const fs3 = options.fs ?? fsPromises8;
35210
- const parent = dirname7(path16);
35239
+ const parent = dirname7(path17);
35211
35240
  if (parent && parent !== ".") {
35212
35241
  await fs3.mkdir(parent, { recursive: true });
35213
35242
  }
35214
35243
  const entry = `[${formatTimestamp2(/* @__PURE__ */ new Date())}] ${message}
35215
35244
  `;
35216
35245
  try {
35217
- await fs3.appendFile(path16, entry, { encoding: "utf8" });
35246
+ await fs3.appendFile(path17, entry, { encoding: "utf8" });
35218
35247
  } catch (error2) {
35219
35248
  const detail = error2 instanceof Error ? error2.message : `Unknown error: ${String(error2)}`;
35220
35249
  throw new Error(`Failed to append activity log entry: ${detail}`);
@@ -35332,6 +35361,76 @@ async function ralphBuild(options) {
35332
35361
  // src/cli/commands/ralph.ts
35333
35362
  init_src();
35334
35363
  init_shared();
35364
+
35365
+ // src/cli/commands/ralph-worktree.ts
35366
+ import path15 from "node:path";
35367
+ import { execSync as execSync3 } from "node:child_process";
35368
+ init_src();
35369
+ function registerRalphWorktreeCommand(ralph, container) {
35370
+ ralph.command("worktree").description("Merge a completed worktree back into the main branch.").argument("<name>", "Name of the worktree to merge").option("--agent <name>", "Agent to use for the merge").action(async function(name) {
35371
+ const cwd = container.env.cwd;
35372
+ const registryFile = path15.join(cwd, ".poe-code-ralph", "worktrees.yaml");
35373
+ const worktrees = await listWorktrees(cwd, registryFile, {
35374
+ fs: {
35375
+ readFile: (p, enc) => container.fs.readFile(p, enc),
35376
+ writeFile: (p, data, opts) => container.fs.writeFile(p, data, opts),
35377
+ mkdir: (p, opts) => container.fs.mkdir(p, opts)
35378
+ },
35379
+ exec: (command, opts) => Promise.resolve({
35380
+ stdout: execSync3(command, {
35381
+ cwd: opts?.cwd,
35382
+ encoding: "utf8",
35383
+ stdio: ["ignore", "pipe", "pipe"]
35384
+ }),
35385
+ stderr: ""
35386
+ })
35387
+ });
35388
+ const entry = worktrees.find((w) => w.name === name);
35389
+ if (!entry) {
35390
+ throw new ValidationError(`Worktree "${name}" not found in registry.`);
35391
+ }
35392
+ if (entry.status !== "done" && entry.status !== "failed") {
35393
+ throw new ValidationError(
35394
+ `Worktree "${name}" has status "${entry.status}" and is not mergeable. Only "done" or "failed" worktrees can be merged.`
35395
+ );
35396
+ }
35397
+ if (!entry.gitExists) {
35398
+ throw new ValidationError(
35399
+ `Worktree directory does not exist for "${name}". It may have been manually removed.`
35400
+ );
35401
+ }
35402
+ const options = this.opts();
35403
+ const { default: mergeTemplate } = await Promise.resolve().then(() => __toESM(require_PROMPT_worktree_merge(), 1));
35404
+ const renderedPrompt = renderTemplate(mergeTemplate, {
35405
+ WORKTREE_NAME: entry.name,
35406
+ WORKTREE_PATH: entry.path,
35407
+ WORKTREE_BRANCH: entry.branch,
35408
+ BASE_BRANCH: entry.baseBranch,
35409
+ MAIN_CWD: cwd,
35410
+ PLAN_PATH: entry.planPath ?? "",
35411
+ STORY_ID: entry.storyId ?? ""
35412
+ });
35413
+ const agent = options.agent?.trim() || entry.agent;
35414
+ const result = await spawnInteractive(agent, {
35415
+ prompt: renderedPrompt,
35416
+ cwd
35417
+ });
35418
+ const fsAdapter2 = {
35419
+ readFile: (p, enc) => container.fs.readFile(p, enc),
35420
+ writeFile: (p, data, opts) => container.fs.writeFile(p, data, opts),
35421
+ mkdir: (p, opts) => container.fs.mkdir(p, opts)
35422
+ };
35423
+ if (result.exitCode === 0) {
35424
+ await updateWorktreeStatus(registryFile, entry.name, "done", { fs: fsAdapter2 });
35425
+ log2.success(`Worktree "${entry.name}" merged successfully.`);
35426
+ } else {
35427
+ await updateWorktreeStatus(registryFile, entry.name, "failed", { fs: fsAdapter2 });
35428
+ log2.error(`Agent exited with code ${result.exitCode}. Worktree "${entry.name}" marked as failed.`);
35429
+ }
35430
+ });
35431
+ }
35432
+
35433
+ // src/cli/commands/ralph.ts
35335
35434
  var templateImports2 = {
35336
35435
  promptPartialPlan: () => Promise.resolve().then(() => __toESM(require_PROMPT_PARTIAL_plan(), 1)),
35337
35436
  skillPlan: () => Promise.resolve().then(() => __toESM(require_SKILL_plan(), 1)),
@@ -35415,7 +35514,7 @@ async function writeFileOrSkip(args) {
35415
35514
  args.logger.info(`Skip: ${args.displayPath} (already exists)`);
35416
35515
  return "skipped";
35417
35516
  }
35418
- await args.fs.mkdir(path15.dirname(args.filePath), { recursive: true });
35517
+ await args.fs.mkdir(path16.dirname(args.filePath), { recursive: true });
35419
35518
  await args.fs.writeFile(args.filePath, args.contents, { encoding: "utf8" });
35420
35519
  args.logger.info(`${exists ? "Overwrite" : "Create"}: ${args.displayPath}`);
35421
35520
  return "written";
@@ -35451,12 +35550,12 @@ async function installRalphTemplates(args) {
35451
35550
  const promptPlanContents = templates.promptPlan.replace("{{{PROMPT_PARTIAL_PLAN}}}", templates.promptPartialPlan);
35452
35551
  const templateWrites = [
35453
35552
  {
35454
- targetPath: path15.join(cwd, ".agents", "poe-code-ralph", "PROMPT_plan.md"),
35553
+ targetPath: path16.join(cwd, ".agents", "poe-code-ralph", "PROMPT_plan.md"),
35455
35554
  displayPath: ".agents/poe-code-ralph/PROMPT_plan.md",
35456
35555
  contents: promptPlanContents
35457
35556
  },
35458
35557
  {
35459
- targetPath: path15.join(cwd, ".agents", "poe-code-ralph", "PROMPT_build.md"),
35558
+ targetPath: path16.join(cwd, ".agents", "poe-code-ralph", "PROMPT_build.md"),
35460
35559
  displayPath: ".agents/poe-code-ralph/PROMPT_build.md",
35461
35560
  contents: templates.promptBuild
35462
35561
  }
@@ -35474,22 +35573,22 @@ async function installRalphTemplates(args) {
35474
35573
  const stateFiles = [
35475
35574
  {
35476
35575
  contents: templates.stateProgress,
35477
- targetPath: path15.join(cwd, ".poe-code-ralph", "progress.md"),
35576
+ targetPath: path16.join(cwd, ".poe-code-ralph", "progress.md"),
35478
35577
  displayPath: ".poe-code-ralph/progress.md"
35479
35578
  },
35480
35579
  {
35481
35580
  contents: templates.stateGuardrails,
35482
- targetPath: path15.join(cwd, ".poe-code-ralph", "guardrails.md"),
35581
+ targetPath: path16.join(cwd, ".poe-code-ralph", "guardrails.md"),
35483
35582
  displayPath: ".poe-code-ralph/guardrails.md"
35484
35583
  },
35485
35584
  {
35486
35585
  contents: templates.stateErrors,
35487
- targetPath: path15.join(cwd, ".poe-code-ralph", "errors.log"),
35586
+ targetPath: path16.join(cwd, ".poe-code-ralph", "errors.log"),
35488
35587
  displayPath: ".poe-code-ralph/errors.log"
35489
35588
  },
35490
35589
  {
35491
35590
  contents: templates.stateActivity,
35492
- targetPath: path15.join(cwd, ".poe-code-ralph", "activity.log"),
35591
+ targetPath: path16.join(cwd, ".poe-code-ralph", "activity.log"),
35493
35592
  displayPath: ".poe-code-ralph/activity.log"
35494
35593
  }
35495
35594
  ];
@@ -35533,7 +35632,7 @@ function registerRalphCommand(program, container) {
35533
35632
  throw new ValidationError(message2);
35534
35633
  }
35535
35634
  const rawPath = options.activityLog?.trim() || configActivityLogPath || ".poe-code-ralph/activity.log";
35536
- const resolvedPath = path15.isAbsolute(rawPath) ? rawPath : path15.resolve(container.env.cwd, rawPath);
35635
+ const resolvedPath = path16.isAbsolute(rawPath) ? rawPath : path16.resolve(container.env.cwd, rawPath);
35537
35636
  await logActivity(resolvedPath, trimmedMessage, {
35538
35637
  fs: container.fs
35539
35638
  });
@@ -35545,7 +35644,7 @@ function registerRalphCommand(program, container) {
35545
35644
  if (!planPath) {
35546
35645
  throw new ValidationError("--plan <path> is required.");
35547
35646
  }
35548
- const resolvedPath = path15.isAbsolute(planPath) ? planPath : path15.resolve(cwd, planPath);
35647
+ const resolvedPath = path16.isAbsolute(planPath) ? planPath : path16.resolve(cwd, planPath);
35549
35648
  let content;
35550
35649
  try {
35551
35650
  content = await container.fs.readFile(resolvedPath, "utf8");
@@ -35669,7 +35768,7 @@ function registerRalphCommand(program, container) {
35669
35768
  if (worktree) resources.logger.info(`Worktree: ${worktree.name ?? "(auto)"}`);
35670
35769
  try {
35671
35770
  const planContent = await container.fs.readFile(
35672
- path15.resolve(cwd, planPath),
35771
+ path16.resolve(cwd, planPath),
35673
35772
  "utf8"
35674
35773
  );
35675
35774
  const plan = parsePlan(planContent);
@@ -35700,6 +35799,7 @@ function registerRalphCommand(program, container) {
35700
35799
  resources.context.finalize();
35701
35800
  }
35702
35801
  });
35802
+ registerRalphWorktreeCommand(ralph, container);
35703
35803
  ralph.command("plan").description("Generate a plan file via an agent.").option("--out <path>", "Output path for generated plan YAML").argument("[request]", "Inline plan request").action(async function() {
35704
35804
  throw new ValidationError(
35705
35805
  "Interactive planning is not yet available. Create your plan YAML manually or use the poe-code-ralph-plan skill inside your agent."