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/cli/commands/ralph-worktree.d.ts +3 -0
- package/dist/cli/commands/ralph-worktree.js +73 -0
- package/dist/cli/commands/ralph-worktree.js.map +1 -0
- package/dist/cli/commands/ralph.js +2 -0
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/constants.d.ts +3 -3
- package/dist/cli/constants.js +2 -2
- package/dist/index.js +200 -100
- package/dist/index.js.map +4 -4
- package/dist/services/model-strategy.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -352,16 +352,16 @@ function getConfigFormat(pathOrFormat) {
|
|
|
352
352
|
}
|
|
353
353
|
return formatRegistry[formatName];
|
|
354
354
|
}
|
|
355
|
-
function detectFormat(
|
|
356
|
-
const ext = getExtension(
|
|
355
|
+
function detectFormat(path17) {
|
|
356
|
+
const ext = getExtension(path17);
|
|
357
357
|
return extensionMap[ext];
|
|
358
358
|
}
|
|
359
|
-
function getExtension(
|
|
360
|
-
const lastDot =
|
|
359
|
+
function getExtension(path17) {
|
|
360
|
+
const lastDot = path17.lastIndexOf(".");
|
|
361
361
|
if (lastDot === -1) {
|
|
362
362
|
return "";
|
|
363
363
|
}
|
|
364
|
-
return
|
|
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(
|
|
1258
|
+
async readFile(path17, encoding) {
|
|
1259
1259
|
if (encoding) {
|
|
1260
|
-
return base.readFile(
|
|
1260
|
+
return base.readFile(path17, encoding);
|
|
1261
1261
|
}
|
|
1262
|
-
return base.readFile(
|
|
1262
|
+
return base.readFile(path17);
|
|
1263
1263
|
},
|
|
1264
|
-
async writeFile(
|
|
1265
|
-
const previousContent = await tryReadText(base,
|
|
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:
|
|
1269
|
+
path: path17,
|
|
1270
1270
|
nextContent,
|
|
1271
1271
|
previousContent
|
|
1272
1272
|
});
|
|
1273
1273
|
},
|
|
1274
|
-
async mkdir(
|
|
1275
|
-
recorder.record({ type: "mkdir", path:
|
|
1274
|
+
async mkdir(path17, options) {
|
|
1275
|
+
recorder.record({ type: "mkdir", path: path17, options });
|
|
1276
1276
|
},
|
|
1277
|
-
async stat(
|
|
1278
|
-
return base.stat(
|
|
1277
|
+
async stat(path17) {
|
|
1278
|
+
return base.stat(path17);
|
|
1279
1279
|
},
|
|
1280
|
-
async unlink(
|
|
1281
|
-
recorder.record({ type: "unlink", path:
|
|
1280
|
+
async unlink(path17) {
|
|
1281
|
+
recorder.record({ type: "unlink", path: path17 });
|
|
1282
1282
|
},
|
|
1283
|
-
async readdir(
|
|
1284
|
-
return base.readdir(
|
|
1283
|
+
async readdir(path17) {
|
|
1284
|
+
return base.readdir(path17);
|
|
1285
1285
|
}
|
|
1286
1286
|
};
|
|
1287
1287
|
if (typeof base.rm === "function") {
|
|
1288
|
-
proxy.rm = async (
|
|
1289
|
-
recorder.record({ type: "rm", path:
|
|
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(
|
|
1380
|
-
const command = `cat > ${
|
|
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,
|
|
1542
|
+
async function tryReadText(base, path17) {
|
|
1543
1543
|
try {
|
|
1544
|
-
return await base.readFile(
|
|
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.
|
|
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.
|
|
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(
|
|
5442
|
-
let input =
|
|
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 [
|
|
5642
|
-
wsComponent.path =
|
|
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
|
|
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
|
|
16518
|
+
let path17 = "";
|
|
16512
16519
|
if (typeof item.content === "string") {
|
|
16513
|
-
|
|
16520
|
+
path17 = item.content;
|
|
16514
16521
|
} else {
|
|
16515
16522
|
try {
|
|
16516
|
-
|
|
16523
|
+
path17 = JSON.stringify(item.content);
|
|
16517
16524
|
} catch {
|
|
16518
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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: ((
|
|
18346
|
+
readFile: ((path17, encoding) => {
|
|
18340
18347
|
if (encoding) {
|
|
18341
|
-
return fs2.readFile(
|
|
18348
|
+
return fs2.readFile(path17, encoding);
|
|
18342
18349
|
}
|
|
18343
|
-
return fs2.readFile(
|
|
18350
|
+
return fs2.readFile(path17);
|
|
18344
18351
|
}),
|
|
18345
|
-
writeFile: (
|
|
18346
|
-
mkdir: (
|
|
18352
|
+
writeFile: (path17, data, opts) => fs2.writeFile(path17, data, opts),
|
|
18353
|
+
mkdir: (path17, opts) => fs2.mkdir(path17, opts).then(() => {
|
|
18347
18354
|
}),
|
|
18348
|
-
stat: (
|
|
18349
|
-
rm: (
|
|
18350
|
-
unlink: (
|
|
18351
|
-
readdir: (
|
|
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: (
|
|
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:
|
|
20770
|
-
const fullPath = [...
|
|
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,
|
|
20892
|
+
constructor(parent, value, path17, key) {
|
|
20886
20893
|
this._cachedPath = [];
|
|
20887
20894
|
this.parent = parent;
|
|
20888
20895
|
this.data = value;
|
|
20889
|
-
this._path =
|
|
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,
|
|
24534
|
-
if (!
|
|
24540
|
+
function getElementAtPath(obj, path17) {
|
|
24541
|
+
if (!path17)
|
|
24535
24542
|
return obj;
|
|
24536
|
-
return
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
34152
|
+
let path17 = line.slice(3).trim();
|
|
34124
34153
|
const renameArrow = " -> ";
|
|
34125
|
-
const arrowIndex =
|
|
34154
|
+
const arrowIndex = path17.lastIndexOf(renameArrow);
|
|
34126
34155
|
if (arrowIndex >= 0) {
|
|
34127
|
-
|
|
34156
|
+
path17 = path17.slice(arrowIndex + renameArrow.length).trim();
|
|
34128
34157
|
}
|
|
34129
|
-
if (
|
|
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(
|
|
34273
|
-
return lockFile(
|
|
34301
|
+
function lockPlanFile(path17) {
|
|
34302
|
+
return lockFile(path17, { retries: 20, minTimeout: 25, maxTimeout: 250 });
|
|
34274
34303
|
}
|
|
34275
|
-
async function writePlan(
|
|
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(
|
|
34279
|
-
const release = await lock(
|
|
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(
|
|
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(
|
|
34355
|
-
return lockFile(
|
|
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(
|
|
34457
|
+
async function writeRunMeta(path17, metadata, options = {}) {
|
|
34429
34458
|
const fs3 = options.fs ?? fsPromises4;
|
|
34430
|
-
await fs3.mkdir(dirname5(
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
34568
|
-
if (!
|
|
34569
|
-
return
|
|
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(
|
|
34620
|
-
return lockFile(
|
|
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,
|
|
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(
|
|
35198
|
-
if (typeof
|
|
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(
|
|
35229
|
+
`Invalid activity log path: expected a non-empty string, got ${String(path17)}`
|
|
35201
35230
|
);
|
|
35202
35231
|
}
|
|
35203
|
-
if (
|
|
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(
|
|
35208
|
-
validateLogPath(
|
|
35236
|
+
async function logActivity(path17, message, options = {}) {
|
|
35237
|
+
validateLogPath(path17);
|
|
35209
35238
|
const fs3 = options.fs ?? fsPromises8;
|
|
35210
|
-
const parent = dirname7(
|
|
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(
|
|
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(
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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."
|