@neriros/ralphy 2.9.2 → 2.9.3
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 +156 -66
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -56407,7 +56407,7 @@ function log(msg) {
|
|
|
56407
56407
|
// package.json
|
|
56408
56408
|
var package_default = {
|
|
56409
56409
|
name: "@neriros/ralphy",
|
|
56410
|
-
version: "2.9.
|
|
56410
|
+
version: "2.9.3",
|
|
56411
56411
|
description: "An iterative AI task execution framework. Orchestrates multi-phase autonomous work using Claude or Codex engines.",
|
|
56412
56412
|
keywords: [
|
|
56413
56413
|
"agent",
|
|
@@ -70806,6 +70806,23 @@ function nextId() {
|
|
|
70806
70806
|
return `${Date.now()}-${lineCounter}`;
|
|
70807
70807
|
}
|
|
70808
70808
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
70809
|
+
async function appendSteering(proposalPath, steering) {
|
|
70810
|
+
const file = Bun.file(proposalPath);
|
|
70811
|
+
const prev = await file.exists() ? await file.text() : "";
|
|
70812
|
+
const stamped = `
|
|
70813
|
+
|
|
70814
|
+
### Steering feedback (${new Date().toISOString()})
|
|
70815
|
+
|
|
70816
|
+
${steering}
|
|
70817
|
+
`;
|
|
70818
|
+
const next = prev.includes("## Steering") ? prev.replace(/## Steering\n+([\s\S]*?)$/, (_m, rest2) => `## Steering
|
|
70819
|
+
${stamped}
|
|
70820
|
+
${rest2}`) : prev + `
|
|
70821
|
+
## Steering
|
|
70822
|
+
${stamped}
|
|
70823
|
+
`;
|
|
70824
|
+
await Bun.write(proposalPath, next);
|
|
70825
|
+
}
|
|
70809
70826
|
function fmtElapsed(ms) {
|
|
70810
70827
|
const s = Math.floor(ms / 1000);
|
|
70811
70828
|
if (s < 60)
|
|
@@ -70988,76 +71005,149 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70988
71005
|
appendLog(`! createPr requested but no worktree branch is tracked for ${changeName} (use --worktree)`, "yellow");
|
|
70989
71006
|
effectiveCode = PR_FAILED_EXIT;
|
|
70990
71007
|
} else {
|
|
70991
|
-
|
|
70992
|
-
|
|
70993
|
-
|
|
70994
|
-
|
|
70995
|
-
|
|
70996
|
-
|
|
70997
|
-
|
|
70998
|
-
|
|
70999
|
-
|
|
71000
|
-
|
|
71001
|
-
|
|
71002
|
-
|
|
71003
|
-
|
|
71004
|
-
|
|
71005
|
-
|
|
71006
|
-
|
|
71007
|
-
|
|
71008
|
-
|
|
71009
|
-
|
|
71010
|
-
|
|
71008
|
+
const proposalPath = join14(statesDirByChange.get(changeName) ?? statesDir, "..", "..", "openspec", "changes", changeName, "proposal.md");
|
|
71009
|
+
const maxHookFixAttempts = cfg.maxCiFixAttempts;
|
|
71010
|
+
const runWorkerWithSteering = async (steering) => {
|
|
71011
|
+
try {
|
|
71012
|
+
await appendSteering(proposalPath, steering);
|
|
71013
|
+
} catch (steerErr) {
|
|
71014
|
+
appendLog(`! could not append steering: ${steerErr.message}`, "red");
|
|
71015
|
+
return 1;
|
|
71016
|
+
}
|
|
71017
|
+
const rp = Bun.spawn({
|
|
71018
|
+
cmd: buildTaskCmd(),
|
|
71019
|
+
cwd: cwd2,
|
|
71020
|
+
stdout: "ignore",
|
|
71021
|
+
stderr: "ignore",
|
|
71022
|
+
stdin: "ignore"
|
|
71023
|
+
});
|
|
71024
|
+
return rp.exited;
|
|
71025
|
+
};
|
|
71026
|
+
let commitFixAttempt = 0;
|
|
71027
|
+
let commitGaveUp = false;
|
|
71028
|
+
while (true) {
|
|
71029
|
+
let dirty = "";
|
|
71030
|
+
try {
|
|
71031
|
+
const status = await bunCmdRunner.run(["git", "status", "--porcelain"], cwd2);
|
|
71032
|
+
dirty = status.stdout.trim();
|
|
71033
|
+
} catch (err) {
|
|
71034
|
+
appendLog(`! git status failed for ${changeName}: ${err.message}`, "yellow");
|
|
71035
|
+
break;
|
|
71036
|
+
}
|
|
71037
|
+
if (!dirty)
|
|
71038
|
+
break;
|
|
71039
|
+
try {
|
|
71040
|
+
await bunCmdRunner.run(["git", "add", "-A"], cwd2);
|
|
71041
|
+
await bunCmdRunner.run(["git", "commit", "-m", `ralph: residual changes for ${changeName}`], cwd2);
|
|
71042
|
+
appendLog(` committed residual changes for ${changeName}`, "gray");
|
|
71043
|
+
break;
|
|
71044
|
+
} catch (err) {
|
|
71045
|
+
const e = err;
|
|
71046
|
+
const detail = e.stderr?.trim() || e.message;
|
|
71047
|
+
const combined = `${e.stdout ?? ""}
|
|
71048
|
+
${e.stderr ?? ""}`;
|
|
71049
|
+
if (/nothing to commit/i.test(combined))
|
|
71050
|
+
break;
|
|
71051
|
+
if (commitFixAttempt >= maxHookFixAttempts) {
|
|
71052
|
+
appendLog(`! commit rejected for ${changeName} after ${commitFixAttempt} fix attempts (host pre-commit hook still failing) \u2014 worktree preserved at ${cwd2}`, "red");
|
|
71053
|
+
appendLog(` detail: ${detail}`, "red");
|
|
71054
|
+
effectiveCode = PR_FAILED_EXIT;
|
|
71055
|
+
commitGaveUp = true;
|
|
71056
|
+
break;
|
|
71057
|
+
}
|
|
71058
|
+
commitFixAttempt += 1;
|
|
71059
|
+
appendLog(`! commit rejected for ${changeName} \u2014 feeding error back to worker (attempt ${commitFixAttempt}/${maxHookFixAttempts})`, "yellow");
|
|
71060
|
+
appendLog(` detail: ${detail}`, "yellow");
|
|
71061
|
+
const retryCode = await runWorkerWithSteering(`Committing residual changes was rejected by the host repo's pre-commit hook. ` + `Fix the underlying problem reported below, then the commit will be retried.
|
|
71011
71062
|
|
|
71012
|
-
|
|
71013
|
-
|
|
71014
|
-
|
|
71015
|
-
|
|
71016
|
-
|
|
71017
|
-
|
|
71018
|
-
${stamped}
|
|
71019
|
-
`;
|
|
71020
|
-
await Bun.write(proposalPath, next);
|
|
71021
|
-
} catch (err) {
|
|
71022
|
-
appendLog(`! could not append steering: ${err.message}`, "red");
|
|
71023
|
-
}
|
|
71024
|
-
const p = Bun.spawn({
|
|
71025
|
-
cmd: buildTaskCmd(),
|
|
71026
|
-
cwd: cwd2,
|
|
71027
|
-
stdout: "ignore",
|
|
71028
|
-
stderr: "ignore",
|
|
71029
|
-
stdin: "ignore"
|
|
71030
|
-
});
|
|
71031
|
-
return p.exited;
|
|
71032
|
-
},
|
|
71033
|
-
pushBranch: async () => {
|
|
71034
|
-
await bunCmdRunner.run(["git", "push", "origin", branch], cwd2);
|
|
71035
|
-
},
|
|
71036
|
-
log: appendLog,
|
|
71037
|
-
sleep: (ms) => new Promise((r) => setTimeout(r, ms))
|
|
71038
|
-
}, {
|
|
71039
|
-
maxAttempts: cfg.maxCiFixAttempts,
|
|
71040
|
-
pollIntervalSeconds: cfg.ciPollIntervalSeconds
|
|
71041
|
-
});
|
|
71042
|
-
if (!result2.success) {
|
|
71043
|
-
appendLog(`! CI fix loop gave up after ${result2.attempts} attempts (${result2.reason ?? "unknown"}) \u2014 withholding done-status until CI passes`, "red");
|
|
71044
|
-
effectiveCode = CI_FAILED_EXIT;
|
|
71045
|
-
}
|
|
71063
|
+
` + "```\n" + combined.trim() + "\n```");
|
|
71064
|
+
if (retryCode !== 0) {
|
|
71065
|
+
appendLog(`! worker re-run after commit rejection exited code ${retryCode} \u2014 giving up`, "red");
|
|
71066
|
+
effectiveCode = PR_FAILED_EXIT;
|
|
71067
|
+
commitGaveUp = true;
|
|
71068
|
+
break;
|
|
71046
71069
|
}
|
|
71047
71070
|
}
|
|
71048
|
-
}
|
|
71049
|
-
|
|
71050
|
-
|
|
71051
|
-
|
|
71071
|
+
}
|
|
71072
|
+
let pushFixAttempt = 0;
|
|
71073
|
+
let pr = null;
|
|
71074
|
+
let prGaveUp = commitGaveUp;
|
|
71075
|
+
while (!prGaveUp) {
|
|
71076
|
+
try {
|
|
71077
|
+
pr = await createPullRequest({ cwd: cwd2, branch, issue: prIssue, base: cfg.prBaseBranch }, bunCmdRunner);
|
|
71078
|
+
break;
|
|
71079
|
+
} catch (err) {
|
|
71080
|
+
const e = err;
|
|
71081
|
+
const detail = e.stderr?.trim() || e.message;
|
|
71082
|
+
const combined = `${e.stdout ?? ""}
|
|
71052
71083
|
${e.stderr ?? ""}`;
|
|
71053
|
-
|
|
71054
|
-
|
|
71055
|
-
|
|
71056
|
-
|
|
71057
|
-
|
|
71058
|
-
|
|
71084
|
+
const pushRejected = /failed to push some refs|pre-push hook|hook declined/i.test(combined);
|
|
71085
|
+
if (!pushRejected || pushFixAttempt >= maxHookFixAttempts) {
|
|
71086
|
+
if (pushRejected) {
|
|
71087
|
+
appendLog(`! push rejected for ${changeName} after ${pushFixAttempt} fix attempts (host pre-push hook still failing) \u2014 worktree preserved at ${cwd2}`, "red");
|
|
71088
|
+
appendLog(` detail: ${detail}`, "red");
|
|
71089
|
+
} else {
|
|
71090
|
+
appendLog(`! PR create failed for ${changeName}: ${detail}`, "red");
|
|
71091
|
+
}
|
|
71092
|
+
effectiveCode = PR_FAILED_EXIT;
|
|
71093
|
+
prGaveUp = true;
|
|
71094
|
+
break;
|
|
71095
|
+
}
|
|
71096
|
+
pushFixAttempt += 1;
|
|
71097
|
+
appendLog(`! push rejected for ${changeName} \u2014 feeding error back to worker (attempt ${pushFixAttempt}/${maxHookFixAttempts})`, "yellow");
|
|
71098
|
+
appendLog(` detail: ${detail}`, "yellow");
|
|
71099
|
+
const retryCode = await runWorkerWithSteering(`Push to origin/${branch} was rejected by the host repo's pre-push hook. ` + `Fix the underlying problem reported below, then the push will be retried.
|
|
71100
|
+
|
|
71101
|
+
` + "```\n" + combined.trim() + "\n```");
|
|
71102
|
+
if (retryCode !== 0) {
|
|
71103
|
+
appendLog(`! worker re-run after push rejection exited code ${retryCode} \u2014 giving up`, "red");
|
|
71104
|
+
effectiveCode = PR_FAILED_EXIT;
|
|
71105
|
+
prGaveUp = true;
|
|
71106
|
+
break;
|
|
71107
|
+
}
|
|
71108
|
+
}
|
|
71109
|
+
}
|
|
71110
|
+
if (prGaveUp) {} else if (!pr) {
|
|
71111
|
+
appendLog(` no commits ahead of ${cfg.prBaseBranch} \u2014 skipping PR`, "gray");
|
|
71112
|
+
} else {
|
|
71113
|
+
appendLog(` ${pr.created ? "opened" : "found existing"} PR: ${pr.url}`, "green");
|
|
71114
|
+
const wantFixCi = args.fixCi || cfg.fixCiOnFailure;
|
|
71115
|
+
if (wantFixCi) {
|
|
71116
|
+
appendLog(` watching CI for ${pr.url} (max ${cfg.maxCiFixAttempts} fix attempts)`, "gray");
|
|
71117
|
+
const result2 = await fixCiUntilGreen({
|
|
71118
|
+
getStatus: () => getPrChecksStatus(pr.url, bunCmdRunner, cwd2),
|
|
71119
|
+
getFailedLogs: (ids) => fetchFailedRunLogs(ids, bunCmdRunner, cwd2),
|
|
71120
|
+
runTaskWithSteering: async (steering) => {
|
|
71121
|
+
try {
|
|
71122
|
+
await appendSteering(proposalPath, `CI feedback:
|
|
71123
|
+
|
|
71124
|
+
${steering}`);
|
|
71125
|
+
} catch (err) {
|
|
71126
|
+
appendLog(`! could not append steering: ${err.message}`, "red");
|
|
71127
|
+
}
|
|
71128
|
+
const p = Bun.spawn({
|
|
71129
|
+
cmd: buildTaskCmd(),
|
|
71130
|
+
cwd: cwd2,
|
|
71131
|
+
stdout: "ignore",
|
|
71132
|
+
stderr: "ignore",
|
|
71133
|
+
stdin: "ignore"
|
|
71134
|
+
});
|
|
71135
|
+
return p.exited;
|
|
71136
|
+
},
|
|
71137
|
+
pushBranch: async () => {
|
|
71138
|
+
await bunCmdRunner.run(["git", "push", "origin", branch], cwd2);
|
|
71139
|
+
},
|
|
71140
|
+
log: appendLog,
|
|
71141
|
+
sleep: (ms) => new Promise((r) => setTimeout(r, ms))
|
|
71142
|
+
}, {
|
|
71143
|
+
maxAttempts: cfg.maxCiFixAttempts,
|
|
71144
|
+
pollIntervalSeconds: cfg.ciPollIntervalSeconds
|
|
71145
|
+
});
|
|
71146
|
+
if (!result2.success) {
|
|
71147
|
+
appendLog(`! CI fix loop gave up after ${result2.attempts} attempts (${result2.reason ?? "unknown"}) \u2014 withholding done-status until CI passes`, "red");
|
|
71148
|
+
effectiveCode = CI_FAILED_EXIT;
|
|
71149
|
+
}
|
|
71059
71150
|
}
|
|
71060
|
-
effectiveCode = PR_FAILED_EXIT;
|
|
71061
71151
|
}
|
|
71062
71152
|
}
|
|
71063
71153
|
}
|