@neriros/ralphy 2.16.3 → 2.16.5
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/index.js +97 -67
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -35029,8 +35029,8 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
35029
35029
|
import { resolve } from "path";
|
|
35030
35030
|
function getVersion() {
|
|
35031
35031
|
try {
|
|
35032
|
-
if ("2.16.
|
|
35033
|
-
return "2.16.
|
|
35032
|
+
if ("2.16.5")
|
|
35033
|
+
return "2.16.5";
|
|
35034
35034
|
} catch {}
|
|
35035
35035
|
const dirsToTry = [];
|
|
35036
35036
|
try {
|
|
@@ -60607,57 +60607,9 @@ ${pe.stderr ?? ""}`;
|
|
|
60607
60607
|
}
|
|
60608
60608
|
}
|
|
60609
60609
|
}
|
|
60610
|
-
async function
|
|
60611
|
-
let hookFixAttempt = 0;
|
|
60612
|
-
while (true) {
|
|
60613
|
-
ctx.emit("committing", "git status");
|
|
60614
|
-
let dirty = "";
|
|
60615
|
-
try {
|
|
60616
|
-
const status = await ctx.cmd.run(["git", "status", "--porcelain"], ctx.cwd);
|
|
60617
|
-
dirty = status.stdout.trim();
|
|
60618
|
-
} catch (err) {
|
|
60619
|
-
ctx.log(`! git status failed for ${ctx.changeName}: ${err.message}`, "yellow");
|
|
60620
|
-
break;
|
|
60621
|
-
}
|
|
60622
|
-
if (!dirty)
|
|
60623
|
-
break;
|
|
60624
|
-
try {
|
|
60625
|
-
ctx.emit("committing", "git add -A");
|
|
60626
|
-
await ctx.cmd.run(["git", "add", "-A"], ctx.cwd);
|
|
60627
|
-
ctx.emit("committing", "git commit");
|
|
60628
|
-
await ctx.cmd.run(["git", "commit", "-m", `chore(ralph): residual changes for ${ctx.changeName}`], ctx.cwd);
|
|
60629
|
-
ctx.log(` committed residual changes for ${ctx.changeName}`, "gray");
|
|
60630
|
-
break;
|
|
60631
|
-
} catch (err) {
|
|
60632
|
-
const e = err;
|
|
60633
|
-
const detail = e.stderr?.trim() || e.message;
|
|
60634
|
-
const combined = `${e.stdout ?? ""}
|
|
60635
|
-
${e.stderr ?? ""}`;
|
|
60636
|
-
if (/nothing to commit/i.test(combined) || /empty git commit/i.test(combined))
|
|
60637
|
-
break;
|
|
60638
|
-
if (hookFixAttempt >= maxAttempts) {
|
|
60639
|
-
ctx.log(`! commit rejected for ${ctx.changeName} after ${hookFixAttempt} hook-fix attempts (host pre-commit hook still failing) \u2014 worktree preserved at ${ctx.cwd}`, "red");
|
|
60640
|
-
ctx.log(` detail: ${detail}`, "red");
|
|
60641
|
-
return { gaveUp: true, hookFixAttempt };
|
|
60642
|
-
}
|
|
60643
|
-
hookFixAttempt += 1;
|
|
60644
|
-
ctx.emit("commit-retry", `${hookFixAttempt}/${maxAttempts}`);
|
|
60645
|
-
ctx.log(`! commit rejected for ${ctx.changeName} \u2014 prepending fix task and re-running loop (attempt ${hookFixAttempt}/${maxAttempts})`, "yellow");
|
|
60646
|
-
ctx.log(` detail: ${detail}`, "yellow");
|
|
60647
|
-
const retryCode = await runWorkerWithFixTask(ctx, "Fix host pre-commit hook rejection", `Committing residual changes was rejected by the host repo's pre-commit hook. ` + `Fix the underlying problem, then the commit will be retried.
|
|
60648
|
-
|
|
60649
|
-
` + combined.trim());
|
|
60650
|
-
if (retryCode !== 0) {
|
|
60651
|
-
ctx.log(`! worker re-run after commit rejection exited code ${retryCode} \u2014 giving up`, "red");
|
|
60652
|
-
return { gaveUp: true, hookFixAttempt };
|
|
60653
|
-
}
|
|
60654
|
-
}
|
|
60655
|
-
}
|
|
60656
|
-
return { gaveUp: false, hookFixAttempt };
|
|
60657
|
-
}
|
|
60658
|
-
async function createPrWithRetry(ctx, issue, initialHookFixAttempt) {
|
|
60610
|
+
async function createPrWithRetry(ctx, issue) {
|
|
60659
60611
|
const maxAttempts = ctx.cfg.maxCiFixAttempts;
|
|
60660
|
-
let hookFixAttempt =
|
|
60612
|
+
let hookFixAttempt = 0;
|
|
60661
60613
|
let nonFfRebaseAttempted = false;
|
|
60662
60614
|
let pr = null;
|
|
60663
60615
|
while (true) {
|
|
@@ -60693,12 +60645,16 @@ ${re.stderr ?? ""}`;
|
|
|
60693
60645
|
ctx.emit("rebasing", "conflicts detected \u2014 aborting + queueing fix task");
|
|
60694
60646
|
try {
|
|
60695
60647
|
await ctx.cmd.run(["git", "rebase", "--abort"], ctx.cwd);
|
|
60696
|
-
} catch {
|
|
60648
|
+
} catch (err2) {
|
|
60649
|
+
ctx.log(`! git rebase --abort failed (worktree may already be clean): ${err2.message}`, "yellow");
|
|
60650
|
+
}
|
|
60697
60651
|
let conflictedFiles = "";
|
|
60698
60652
|
try {
|
|
60699
60653
|
const r = await ctx.cmd.run(["git", "diff", "--name-only", `HEAD..origin/${ctx.branch}`], ctx.cwd);
|
|
60700
60654
|
conflictedFiles = r.stdout.trim();
|
|
60701
|
-
} catch {
|
|
60655
|
+
} catch (err2) {
|
|
60656
|
+
ctx.log(`! could not list conflicted files: ${err2.message}`, "yellow");
|
|
60657
|
+
}
|
|
60702
60658
|
if (hookFixAttempt >= maxAttempts) {
|
|
60703
60659
|
ctx.log(`! merge conflict on rebase of ${ctx.branch} after ${hookFixAttempt} attempts \u2014 worktree preserved at ${ctx.cwd}`, "red");
|
|
60704
60660
|
ctx.log(` detail: ${reBlob.trim().split(`
|
|
@@ -60860,11 +60816,16 @@ async function runPostTask(input, deps) {
|
|
|
60860
60816
|
emit,
|
|
60861
60817
|
respawnWorker
|
|
60862
60818
|
};
|
|
60863
|
-
|
|
60864
|
-
|
|
60865
|
-
|
|
60866
|
-
|
|
60867
|
-
|
|
60819
|
+
try {
|
|
60820
|
+
const status = await cmd.run(["git", "status", "--porcelain"], cwd2);
|
|
60821
|
+
if (status.stdout.trim()) {
|
|
60822
|
+
log2(`! ${changeName} has uncommitted changes after worker exit \u2014 the agent should commit everything before finishing. These changes will not be included in the PR.`, "yellow");
|
|
60823
|
+
}
|
|
60824
|
+
} catch (err) {
|
|
60825
|
+
log2(`! git status check failed for ${changeName}: ${err.message}`, "yellow");
|
|
60826
|
+
}
|
|
60827
|
+
{
|
|
60828
|
+
const { pr, gaveUp: prGaveUp } = await createPrWithRetry(ctx, issue);
|
|
60868
60829
|
if (prGaveUp) {
|
|
60869
60830
|
effectiveCode = PR_FAILED_EXIT;
|
|
60870
60831
|
} else if (!pr) {
|
|
@@ -60887,7 +60848,9 @@ async function runPostTask(input, deps) {
|
|
|
60887
60848
|
emit("teardown", cfg.teardownScript);
|
|
60888
60849
|
try {
|
|
60889
60850
|
await runScript("teardown", cfg.teardownScript, cwd2);
|
|
60890
|
-
} catch {
|
|
60851
|
+
} catch (err) {
|
|
60852
|
+
log2(`! teardown script threw: ${err.message}`, "yellow");
|
|
60853
|
+
}
|
|
60891
60854
|
}
|
|
60892
60855
|
if (useWorktree && cwd2 !== projectRoot) {
|
|
60893
60856
|
emit("cleanup", "checking worktree safety");
|
|
@@ -71886,6 +71849,8 @@ function buildTaskPrompt(state, taskDir) {
|
|
|
71886
71849
|
|
|
71887
71850
|
`;
|
|
71888
71851
|
prompt += `Run \`bunx openspec validate ${state.name}\` before committing.
|
|
71852
|
+
`;
|
|
71853
|
+
prompt += `Commit all changed files yourself before finishing \u2014 stage files individually (e.g. \`git add path/to/file\`), never \`git add -A\` or \`git commit -am\`. Nothing is committed automatically after you exit.
|
|
71889
71854
|
`;
|
|
71890
71855
|
return prompt;
|
|
71891
71856
|
}
|
|
@@ -72412,11 +72377,20 @@ var import_react57 = __toESM(require_react(), 1);
|
|
|
72412
72377
|
init_cli();
|
|
72413
72378
|
init_config();
|
|
72414
72379
|
init_wire();
|
|
72415
|
-
var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
|
|
72416
72380
|
import { join as join16, dirname as dirname4 } from "path";
|
|
72417
72381
|
import { pathToFileURL } from "url";
|
|
72418
72382
|
import { homedir as homedir3 } from "os";
|
|
72419
72383
|
import { appendFile, mkdir as mkdir4 } from "fs/promises";
|
|
72384
|
+
|
|
72385
|
+
// packages/core/src/progress.ts
|
|
72386
|
+
function countProgress(content) {
|
|
72387
|
+
const checked = (content.match(/^- \[x\]/gm) ?? []).length;
|
|
72388
|
+
const unchecked = (content.match(/^- \[ \]/gm) ?? []).length;
|
|
72389
|
+
return { checked, unchecked, total: checked + unchecked };
|
|
72390
|
+
}
|
|
72391
|
+
|
|
72392
|
+
// apps/cli/src/components/AgentMode.tsx
|
|
72393
|
+
var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
|
|
72420
72394
|
var lineCounter = 0;
|
|
72421
72395
|
function nextId() {
|
|
72422
72396
|
lineCounter += 1;
|
|
@@ -72443,6 +72417,18 @@ function fmtElapsed(ms) {
|
|
|
72443
72417
|
function trunc(s, max2) {
|
|
72444
72418
|
return s.length > max2 ? s.slice(0, max2 - 1) + "\u2026" : s;
|
|
72445
72419
|
}
|
|
72420
|
+
function calcProgressBar(checked, total, width) {
|
|
72421
|
+
const countStr = `${checked}/${total}`;
|
|
72422
|
+
const inner = width - 2;
|
|
72423
|
+
if (inner < countStr.length + 2)
|
|
72424
|
+
return null;
|
|
72425
|
+
const leftSlot = Math.floor((inner - countStr.length) / 2);
|
|
72426
|
+
const rightSlot = Math.max(0, inner - countStr.length - leftSlot);
|
|
72427
|
+
const filled = total > 0 ? Math.round(checked / total * inner) : 0;
|
|
72428
|
+
const filledLeft = Math.min(filled, leftSlot);
|
|
72429
|
+
const filledRight = Math.max(0, Math.min(filled - leftSlot - countStr.length, rightSlot));
|
|
72430
|
+
return { countStr, filledLeft, leftSlot, filledRight, rightSlot };
|
|
72431
|
+
}
|
|
72446
72432
|
function prLabel(prUrl) {
|
|
72447
72433
|
const m = prUrl.match(/\/pull\/(\d+)/);
|
|
72448
72434
|
return m ? `#${m[1]}` : "PR";
|
|
@@ -72557,8 +72543,6 @@ function phaseColor(phase) {
|
|
|
72557
72543
|
return "cyan";
|
|
72558
72544
|
case "scaffolding":
|
|
72559
72545
|
return "magenta";
|
|
72560
|
-
case "committing":
|
|
72561
|
-
case "commit-retry":
|
|
72562
72546
|
case "pushing":
|
|
72563
72547
|
case "push-retry":
|
|
72564
72548
|
case "rebasing":
|
|
@@ -72583,8 +72567,6 @@ function workerBorderColor(phase) {
|
|
|
72583
72567
|
case "working":
|
|
72584
72568
|
case "scaffolding":
|
|
72585
72569
|
return "cyan";
|
|
72586
|
-
case "committing":
|
|
72587
|
-
case "commit-retry":
|
|
72588
72570
|
case "pushing":
|
|
72589
72571
|
case "push-retry":
|
|
72590
72572
|
case "rebasing":
|
|
@@ -72691,6 +72673,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
72691
72673
|
phaseDetail: "",
|
|
72692
72674
|
phaseStartedAt: Date.now(),
|
|
72693
72675
|
currentTask: null,
|
|
72676
|
+
taskProgress: null,
|
|
72694
72677
|
prUrl: null,
|
|
72695
72678
|
currentCmd: null,
|
|
72696
72679
|
tail: []
|
|
@@ -72802,7 +72785,9 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
72802
72785
|
const json = await file.json();
|
|
72803
72786
|
meta.iter = json.iteration ?? meta.iter;
|
|
72804
72787
|
}
|
|
72805
|
-
} catch {
|
|
72788
|
+
} catch (err) {
|
|
72789
|
+
console.error(`Failed to read state file for worker '${changeName}' (may not exist yet):`, err);
|
|
72790
|
+
}
|
|
72806
72791
|
if (meta.changeDir) {
|
|
72807
72792
|
try {
|
|
72808
72793
|
const tasksFile = Bun.file(join16(meta.changeDir, "tasks.md"));
|
|
@@ -72810,8 +72795,12 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
72810
72795
|
const text = await tasksFile.text();
|
|
72811
72796
|
const match = text.match(/^- \[ \] (.+)$/m);
|
|
72812
72797
|
meta.currentTask = match?.[1]?.trim() ?? null;
|
|
72798
|
+
const { checked, total } = countProgress(text);
|
|
72799
|
+
meta.taskProgress = total > 0 ? { checked, total } : null;
|
|
72813
72800
|
}
|
|
72814
|
-
} catch {
|
|
72801
|
+
} catch (err) {
|
|
72802
|
+
console.error(`Failed to read tasks.md for worker '${changeName}' (may not exist yet):`, err);
|
|
72803
|
+
}
|
|
72815
72804
|
}
|
|
72816
72805
|
}
|
|
72817
72806
|
if (!cancelled)
|
|
@@ -73154,6 +73143,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
73154
73143
|
const tail2 = meta?.tail ?? [];
|
|
73155
73144
|
const prUrl = meta?.prUrl ?? null;
|
|
73156
73145
|
const currentTask = meta?.currentTask ?? null;
|
|
73146
|
+
const taskProgress = meta?.taskProgress ?? null;
|
|
73157
73147
|
const pBadge = priorityBadge(w.issue.priority);
|
|
73158
73148
|
const mBadge = modeBadge(w.mode);
|
|
73159
73149
|
const pColor = phaseColor(phase);
|
|
@@ -73357,6 +73347,46 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
73357
73347
|
}, undefined, false, undefined, this)
|
|
73358
73348
|
]
|
|
73359
73349
|
}, undefined, true, undefined, this),
|
|
73350
|
+
taskProgress && (() => {
|
|
73351
|
+
const bar = calcProgressBar(taskProgress.checked, taskProgress.total, termWidth - 4);
|
|
73352
|
+
if (!bar)
|
|
73353
|
+
return null;
|
|
73354
|
+
const { countStr, filledLeft, leftSlot, filledRight, rightSlot } = bar;
|
|
73355
|
+
return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
73356
|
+
marginTop: 0,
|
|
73357
|
+
children: [
|
|
73358
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73359
|
+
dimColor: true,
|
|
73360
|
+
children: "["
|
|
73361
|
+
}, undefined, false, undefined, this),
|
|
73362
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73363
|
+
color: "green",
|
|
73364
|
+
children: "\u2588".repeat(filledLeft)
|
|
73365
|
+
}, undefined, false, undefined, this),
|
|
73366
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73367
|
+
dimColor: true,
|
|
73368
|
+
children: "\u2591".repeat(leftSlot - filledLeft)
|
|
73369
|
+
}, undefined, false, undefined, this),
|
|
73370
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73371
|
+
color: "white",
|
|
73372
|
+
bold: true,
|
|
73373
|
+
children: countStr
|
|
73374
|
+
}, undefined, false, undefined, this),
|
|
73375
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73376
|
+
color: "green",
|
|
73377
|
+
children: "\u2588".repeat(filledRight)
|
|
73378
|
+
}, undefined, false, undefined, this),
|
|
73379
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73380
|
+
dimColor: true,
|
|
73381
|
+
children: "\u2591".repeat(rightSlot - filledRight)
|
|
73382
|
+
}, undefined, false, undefined, this),
|
|
73383
|
+
/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
|
|
73384
|
+
dimColor: true,
|
|
73385
|
+
children: "]"
|
|
73386
|
+
}, undefined, false, undefined, this)
|
|
73387
|
+
]
|
|
73388
|
+
}, undefined, true, undefined, this);
|
|
73389
|
+
})(),
|
|
73360
73390
|
currentTask && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
|
|
73361
73391
|
gap: 1,
|
|
73362
73392
|
marginTop: 0,
|