@neriros/ralphy 2.7.5 → 2.7.6
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/README.md +6 -0
- package/dist/cli/index.js +53 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,11 +104,13 @@ Defaults are written to `ralphy.config.json` on first run; CLI flags override co
|
|
|
104
104
|
"doneStatus": "In Review",
|
|
105
105
|
"doneLabel": "ralphy-done",
|
|
106
106
|
"postComments": true,
|
|
107
|
+
"updateEveryIterations": 10,
|
|
107
108
|
},
|
|
108
109
|
"useWorktree": true,
|
|
109
110
|
"cleanupWorktreeOnSuccess": false,
|
|
110
111
|
"setupScript": "bun install",
|
|
111
112
|
"teardownScript": "git status",
|
|
113
|
+
"appendPrompt": "Always run lint before committing.",
|
|
112
114
|
}
|
|
113
115
|
```
|
|
114
116
|
|
|
@@ -120,6 +122,10 @@ With `--worktree` (or `useWorktree: true` in config) each task runs in an isolat
|
|
|
120
122
|
|
|
121
123
|
Use `setupScript` (run inside the worktree right after scaffolding) to install dependencies, copy `.env`, etc. Use `teardownScript` (run after the loop exits, before any worktree cleanup) to gather artifacts or roll back local mutations. Both run via `sh -c`; failures are logged but never block the loop. With `cleanupWorktreeOnSuccess: true` the worktree is removed when the worker exits 0 — failed workers always keep their worktree (and branch) for human inspection.
|
|
122
124
|
|
|
125
|
+
**`appendPrompt`** (or `--prompt` in agent mode) is appended to every scaffolded `proposal.md` under an `## Additional instructions` section — use it for cross-cutting guidance every task should see.
|
|
126
|
+
|
|
127
|
+
**`updateEveryIterations`** (default `10`, `0` disables) posts a "🔄 Ralph progress update: iteration N" comment on the Linear issue every N task iterations. Requires `postComments: true`.
|
|
128
|
+
|
|
123
129
|
Failed workers (non-zero exit) are not marked processed, so they'll be retried on the next poll. SIGINT/SIGTERM cleanly stops polling and kills active workers. All Linear side effects are best-effort — failures log a warning but never block the task loop.
|
|
124
130
|
|
|
125
131
|
## CLI Options
|
package/dist/cli/index.js
CHANGED
|
@@ -56131,7 +56131,7 @@ var HELP_TEXT = [
|
|
|
56131
56131
|
"",
|
|
56132
56132
|
"Options:",
|
|
56133
56133
|
" --name <name> Change name (required for most commands)",
|
|
56134
|
-
" --prompt <text> Task description",
|
|
56134
|
+
" --prompt <text> Task description (in agent mode: appended to every scaffolded proposal)",
|
|
56135
56135
|
" --prompt-file <path> Read prompt from file",
|
|
56136
56136
|
" --model <model> Set model (haiku|sonnet|opus)",
|
|
56137
56137
|
" --claude [model] Use Claude engine (haiku|sonnet|opus, default: opus)",
|
|
@@ -69772,7 +69772,7 @@ function changeNameForIssue(issue) {
|
|
|
69772
69772
|
const slug = issue.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
69773
69773
|
return slug ? `${issue.identifier.toLowerCase()}-${slug}` : issue.identifier.toLowerCase();
|
|
69774
69774
|
}
|
|
69775
|
-
async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = []) {
|
|
69775
|
+
async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = [], appendPrompt = "") {
|
|
69776
69776
|
const name = changeNameForIssue(issue);
|
|
69777
69777
|
const changeDir = join11(tasksDir, name);
|
|
69778
69778
|
const stateDir = join11(statesDir, name);
|
|
@@ -69802,6 +69802,7 @@ async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = [])
|
|
|
69802
69802
|
"",
|
|
69803
69803
|
issue.description?.trim() || "_No description provided in Linear._",
|
|
69804
69804
|
...commentsBlock,
|
|
69805
|
+
...appendPrompt.trim() ? ["", "## Additional instructions", "", appendPrompt.trim()] : [],
|
|
69805
69806
|
"",
|
|
69806
69807
|
"## Steering",
|
|
69807
69808
|
"",
|
|
@@ -69843,6 +69844,7 @@ var RalphyConfigSchema = exports_external.object({
|
|
|
69843
69844
|
cleanupWorktreeOnSuccess: exports_external.boolean().default(false),
|
|
69844
69845
|
setupScript: exports_external.string().optional(),
|
|
69845
69846
|
teardownScript: exports_external.string().optional(),
|
|
69847
|
+
appendPrompt: exports_external.string().optional(),
|
|
69846
69848
|
engine: exports_external.enum(["claude", "codex"]).default("claude"),
|
|
69847
69849
|
model: exports_external.enum(["haiku", "sonnet", "opus"]).default("opus"),
|
|
69848
69850
|
linear: exports_external.object({
|
|
@@ -69853,7 +69855,8 @@ var RalphyConfigSchema = exports_external.object({
|
|
|
69853
69855
|
inProgressStatus: exports_external.string().optional(),
|
|
69854
69856
|
doneStatus: exports_external.string().optional(),
|
|
69855
69857
|
doneLabel: exports_external.string().optional(),
|
|
69856
|
-
postComments: exports_external.boolean().default(true)
|
|
69858
|
+
postComments: exports_external.boolean().default(true),
|
|
69859
|
+
updateEveryIterations: exports_external.number().int().nonnegative().default(10)
|
|
69857
69860
|
}).default({ statuses: [], labels: [], postComments: true })
|
|
69858
69861
|
}).default({
|
|
69859
69862
|
concurrency: 1,
|
|
@@ -69939,8 +69942,37 @@ class AgentCoordinator {
|
|
|
69939
69942
|
state.lastPollAt = new Date().toISOString();
|
|
69940
69943
|
await this.deps.saveState(state);
|
|
69941
69944
|
this.spawnNext();
|
|
69945
|
+
await this.reportProgress();
|
|
69942
69946
|
return { found: issues.length, added };
|
|
69943
69947
|
}
|
|
69948
|
+
async reportProgress() {
|
|
69949
|
+
const updater = this.deps.updater;
|
|
69950
|
+
const everyN = this.opts.commentEveryIterations ?? 0;
|
|
69951
|
+
if (everyN <= 0 || !updater || this.opts.postComments === false || !this.deps.getIterationCount) {
|
|
69952
|
+
return;
|
|
69953
|
+
}
|
|
69954
|
+
for (const w of this.workers) {
|
|
69955
|
+
let count;
|
|
69956
|
+
try {
|
|
69957
|
+
count = await this.deps.getIterationCount(w.changeName);
|
|
69958
|
+
} catch (err) {
|
|
69959
|
+
this.deps.onLog(`! iteration count read failed for ${w.issueIdentifier}: ${err.message}`, "yellow");
|
|
69960
|
+
continue;
|
|
69961
|
+
}
|
|
69962
|
+
if (count < everyN)
|
|
69963
|
+
continue;
|
|
69964
|
+
const currMilestone = Math.floor(count / everyN);
|
|
69965
|
+
const lastMilestone = Math.floor(w.lastReportedIteration / everyN);
|
|
69966
|
+
if (currMilestone <= lastMilestone)
|
|
69967
|
+
continue;
|
|
69968
|
+
try {
|
|
69969
|
+
await updater.postComment(w.issue, `\uD83D\uDD04 Ralph progress update: iteration ${count} on \`${w.changeName}\``);
|
|
69970
|
+
w.lastReportedIteration = count;
|
|
69971
|
+
} catch (err) {
|
|
69972
|
+
this.deps.onLog(`! Linear progress comment failed for ${w.issueIdentifier}: ${err.message}`, "red");
|
|
69973
|
+
}
|
|
69974
|
+
}
|
|
69975
|
+
}
|
|
69944
69976
|
spawnNext() {
|
|
69945
69977
|
if (this.stopped || !this.state)
|
|
69946
69978
|
return;
|
|
@@ -69970,7 +70002,9 @@ class AgentCoordinator {
|
|
|
69970
70002
|
changeName,
|
|
69971
70003
|
issueId: issue.id,
|
|
69972
70004
|
issueIdentifier: issue.identifier,
|
|
69973
|
-
|
|
70005
|
+
issue,
|
|
70006
|
+
kill: handle.kill,
|
|
70007
|
+
lastReportedIteration: 0
|
|
69974
70008
|
};
|
|
69975
70009
|
this.workers.push(worker);
|
|
69976
70010
|
this.pendingIds.delete(issue.id);
|
|
@@ -70157,6 +70191,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70157
70191
|
const teamKeyOf = (issue) => issue.identifier.split("-")[0];
|
|
70158
70192
|
const useWorktree = args.worktree || cfg.useWorktree;
|
|
70159
70193
|
const cwdByChange = new Map;
|
|
70194
|
+
const statesDirByChange = new Map;
|
|
70160
70195
|
async function runScript(label, cmd, cwd2) {
|
|
70161
70196
|
appendLog(` ${label}: ${cmd}`, "gray");
|
|
70162
70197
|
const proc = Bun.spawn({
|
|
@@ -70197,8 +70232,10 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70197
70232
|
appendLog(`! worktree create failed for ${issue.identifier}: ${err.message} \u2014 falling back to project root`, "yellow");
|
|
70198
70233
|
}
|
|
70199
70234
|
}
|
|
70200
|
-
const
|
|
70235
|
+
const appendPrompt = args.prompt || cfg.appendPrompt || "";
|
|
70236
|
+
const changeName = await scaffoldChangeForIssue(scaffoldTasksDir, scaffoldStatesDir, issue, comments, appendPrompt);
|
|
70201
70237
|
cwdByChange.set(changeName, workerCwd);
|
|
70238
|
+
statesDirByChange.set(changeName, scaffoldStatesDir);
|
|
70202
70239
|
if (cfg.setupScript) {
|
|
70203
70240
|
await runScript("setup", cfg.setupScript, workerCwd);
|
|
70204
70241
|
}
|
|
@@ -70246,6 +70283,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70246
70283
|
}
|
|
70247
70284
|
}
|
|
70248
70285
|
cwdByChange.delete(changeName);
|
|
70286
|
+
statesDirByChange.delete(changeName);
|
|
70249
70287
|
return code;
|
|
70250
70288
|
});
|
|
70251
70289
|
return { exited: wrapped, kill: () => proc.kill() };
|
|
@@ -70254,6 +70292,14 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70254
70292
|
saveState: (s) => writeAgentState(projectRoot, s),
|
|
70255
70293
|
onLog: appendLog,
|
|
70256
70294
|
onWorkersChanged: () => setTick((t) => t + 1),
|
|
70295
|
+
getIterationCount: async (changeName) => {
|
|
70296
|
+
const dir = statesDirByChange.get(changeName) ?? statesDir;
|
|
70297
|
+
const file = Bun.file(join14(dir, changeName, ".ralph-state.json"));
|
|
70298
|
+
if (!await file.exists())
|
|
70299
|
+
return 0;
|
|
70300
|
+
const json = await file.json();
|
|
70301
|
+
return json.iteration ?? 0;
|
|
70302
|
+
},
|
|
70257
70303
|
updater: {
|
|
70258
70304
|
postComment: (issue, body) => addIssueComment(apiKey, issue.id, body),
|
|
70259
70305
|
setState: (issue, stateId) => updateIssueState(apiKey, issue.id, stateId),
|
|
@@ -70285,7 +70331,8 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
70285
70331
|
inProgressStatus: args.inProgressStatus || cfg.linear.inProgressStatus,
|
|
70286
70332
|
doneStatus: args.doneStatus || cfg.linear.doneStatus,
|
|
70287
70333
|
doneLabel: args.doneLabel || cfg.linear.doneLabel,
|
|
70288
|
-
postComments: cfg.linear.postComments
|
|
70334
|
+
postComments: cfg.linear.postComments,
|
|
70335
|
+
commentEveryIterations: cfg.linear.updateEveryIterations
|
|
70289
70336
|
});
|
|
70290
70337
|
coordRef.current = coord2;
|
|
70291
70338
|
await coord2.init();
|