@neriros/ralphy 2.10.1 → 2.11.0
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 +93 -27
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -50837,8 +50837,8 @@ var require_axios = __commonJS((exports, module) => {
|
|
|
50837
50837
|
});
|
|
50838
50838
|
|
|
50839
50839
|
// apps/cli/src/index.ts
|
|
50840
|
-
import { resolve, join as join17, dirname as
|
|
50841
|
-
import { exists, mkdir as
|
|
50840
|
+
import { resolve, join as join17, dirname as dirname5 } from "path";
|
|
50841
|
+
import { exists as exists2, mkdir as mkdir4, rm } from "fs/promises";
|
|
50842
50842
|
|
|
50843
50843
|
// node_modules/.bun/ink@5.2.1+1f88f629f0141b18/node_modules/ink/build/render.js
|
|
50844
50844
|
import { Stream } from "stream";
|
|
@@ -56407,7 +56407,7 @@ function log(msg) {
|
|
|
56407
56407
|
// package.json
|
|
56408
56408
|
var package_default = {
|
|
56409
56409
|
name: "@neriros/ralphy",
|
|
56410
|
-
version: "2.
|
|
56410
|
+
version: "2.11.0",
|
|
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",
|
|
@@ -64894,7 +64894,9 @@ var {spawn: bunSpawn } = globalThis.Bun;
|
|
|
64894
64894
|
var spawn = bunSpawn;
|
|
64895
64895
|
|
|
64896
64896
|
// packages/engine/src/engine.ts
|
|
64897
|
-
import {
|
|
64897
|
+
import { createWriteStream } from "fs";
|
|
64898
|
+
import { mkdtemp, unlink, mkdir } from "fs/promises";
|
|
64899
|
+
import { dirname as dirname2 } from "path";
|
|
64898
64900
|
import { join as join5 } from "path";
|
|
64899
64901
|
import { tmpdir } from "os";
|
|
64900
64902
|
|
|
@@ -65711,6 +65713,21 @@ async function runEngine(opts) {
|
|
|
65711
65713
|
stdin.write(new TextEncoder().encode(prompt));
|
|
65712
65714
|
await stdin.flush();
|
|
65713
65715
|
stdin.end();
|
|
65716
|
+
let rawWriter = null;
|
|
65717
|
+
if (opts.logFlag && opts.logFile) {
|
|
65718
|
+
await mkdir(dirname2(opts.logFile), { recursive: true });
|
|
65719
|
+
rawWriter = createWriteStream(opts.logFile, { flags: "a" });
|
|
65720
|
+
}
|
|
65721
|
+
const writeRaw = (line) => {
|
|
65722
|
+
if (rawWriter)
|
|
65723
|
+
rawWriter.write(line + `
|
|
65724
|
+
`);
|
|
65725
|
+
};
|
|
65726
|
+
const closeRaw = () => new Promise((resolve) => {
|
|
65727
|
+
if (!rawWriter)
|
|
65728
|
+
return resolve();
|
|
65729
|
+
rawWriter.end(resolve);
|
|
65730
|
+
});
|
|
65714
65731
|
const emit = opts.onFeedEvent;
|
|
65715
65732
|
function emitEvent(event) {
|
|
65716
65733
|
if (emit) {
|
|
@@ -65745,6 +65762,7 @@ async function runEngine(opts) {
|
|
|
65745
65762
|
usage: null
|
|
65746
65763
|
};
|
|
65747
65764
|
for await (const line of streamLines(stdout)) {
|
|
65765
|
+
writeRaw(line);
|
|
65748
65766
|
if (sessionId === null) {
|
|
65749
65767
|
try {
|
|
65750
65768
|
const parsed = JSON.parse(line);
|
|
@@ -65772,6 +65790,7 @@ async function runEngine(opts) {
|
|
|
65772
65790
|
pendingTools: 0
|
|
65773
65791
|
};
|
|
65774
65792
|
for await (const line of streamLines(stdout)) {
|
|
65793
|
+
writeRaw(line);
|
|
65775
65794
|
for (const event of parseCodexLine(line, codexState)) {
|
|
65776
65795
|
emitEvent(event);
|
|
65777
65796
|
}
|
|
@@ -65779,12 +65798,14 @@ async function runEngine(opts) {
|
|
|
65779
65798
|
if (proc.stderr) {
|
|
65780
65799
|
const stderr = proc.stderr;
|
|
65781
65800
|
for await (const line of streamLines(stderr)) {
|
|
65801
|
+
writeRaw(line);
|
|
65782
65802
|
for (const event of parseCodexLine(line, codexState)) {
|
|
65783
65803
|
emitEvent(event);
|
|
65784
65804
|
}
|
|
65785
65805
|
}
|
|
65786
65806
|
}
|
|
65787
65807
|
}
|
|
65808
|
+
await closeRaw();
|
|
65788
65809
|
const exitCode = await proc.exited;
|
|
65789
65810
|
const wasIntentionalKill = (exitCode === 143 || exitCode === 137) && (usage !== null || aborted);
|
|
65790
65811
|
const normalizedExitCode = wasIntentionalKill ? 0 : exitCode;
|
|
@@ -65843,7 +65864,7 @@ function commitTaskDir(taskDir, message) {
|
|
|
65843
65864
|
}
|
|
65844
65865
|
|
|
65845
65866
|
// node_modules/.bun/posthog-node@4.18.0/node_modules/posthog-node/lib/node/index.mjs
|
|
65846
|
-
import { posix, dirname as
|
|
65867
|
+
import { posix, dirname as dirname3, sep } from "path";
|
|
65847
65868
|
import { createReadStream } from "fs";
|
|
65848
65869
|
import { createInterface } from "readline";
|
|
65849
65870
|
var NAME = "posthog-node";
|
|
@@ -66423,7 +66444,7 @@ class ErrorTracking {
|
|
|
66423
66444
|
return !this.client.isDisabled && this._exceptionAutocaptureEnabled;
|
|
66424
66445
|
}
|
|
66425
66446
|
}
|
|
66426
|
-
function createGetModuleFromFilename(basePath = process.argv[1] ?
|
|
66447
|
+
function createGetModuleFromFilename(basePath = process.argv[1] ? dirname3(process.argv[1]) : process.cwd(), isWindows3 = sep === "\\") {
|
|
66427
66448
|
const normalizedBase = isWindows3 ? normalizeWindowsPath(basePath) : basePath;
|
|
66428
66449
|
return (filename) => {
|
|
66429
66450
|
if (!filename) {
|
|
@@ -69460,11 +69481,16 @@ var STEERING_MAX_LINES = 20;
|
|
|
69460
69481
|
function extractFirstUncheckedSection(tasksContent) {
|
|
69461
69482
|
const sections = tasksContent.split(/(?=^## )/m);
|
|
69462
69483
|
for (const section of sections) {
|
|
69463
|
-
if (/^- \[ \]/m.test(section))
|
|
69484
|
+
if (/^## /m.test(section) && /^- \[ \]/m.test(section))
|
|
69464
69485
|
return section.trim();
|
|
69465
69486
|
}
|
|
69487
|
+
if (/^- \[ \]/m.test(tasksContent))
|
|
69488
|
+
return tasksContent.trim();
|
|
69466
69489
|
return null;
|
|
69467
69490
|
}
|
|
69491
|
+
function countUncheckedTasks(tasksContent) {
|
|
69492
|
+
return (tasksContent.match(/^- \[ \]/gm) ?? []).length;
|
|
69493
|
+
}
|
|
69468
69494
|
function allTasksCompleted(tasksContent) {
|
|
69469
69495
|
return !/^- \[ \]/m.test(tasksContent);
|
|
69470
69496
|
}
|
|
@@ -69504,6 +69530,9 @@ function buildTaskPrompt(state, taskDir) {
|
|
|
69504
69530
|
`;
|
|
69505
69531
|
prompt += `---
|
|
69506
69532
|
|
|
69533
|
+
`;
|
|
69534
|
+
prompt += `**Tracking progress**: as you finish each item above, edit ` + `\`${join7(taskDir, "tasks.md")}\` and change its \`- [ ]\` to ` + `\`- [x]\` in the same commit. The loop reads this file between ` + `iterations and stops when no \`- [ ]\` items remain \u2014 if you do ` + `not tick the box, the next iteration will repeat this task.
|
|
69535
|
+
|
|
69507
69536
|
`;
|
|
69508
69537
|
}
|
|
69509
69538
|
} else if (state.prompt) {
|
|
@@ -69723,6 +69752,10 @@ function useLoop(opts) {
|
|
|
69723
69752
|
break;
|
|
69724
69753
|
}
|
|
69725
69754
|
const tasksContent = storage.read(join8(tasksDir, "tasks.md"));
|
|
69755
|
+
if (tasksContent !== null) {
|
|
69756
|
+
const remaining = countUncheckedTasks(tasksContent);
|
|
69757
|
+
addInfo(`tasks.md: ${remaining} unchecked item${remaining === 1 ? "" : "s"} remaining`);
|
|
69758
|
+
}
|
|
69726
69759
|
if (tasksContent !== null && allTasksCompleted(tasksContent)) {
|
|
69727
69760
|
addInfo("All tasks completed \u2014 archiving change.");
|
|
69728
69761
|
currentState = {
|
|
@@ -69758,6 +69791,7 @@ function useLoop(opts) {
|
|
|
69758
69791
|
model: opts.model,
|
|
69759
69792
|
prompt,
|
|
69760
69793
|
logFlag: opts.log,
|
|
69794
|
+
logFile: join8(stateDir, "log.json"),
|
|
69761
69795
|
taskDir: tasksDir,
|
|
69762
69796
|
interactive: false,
|
|
69763
69797
|
onFeedEvent: addFeedEvent,
|
|
@@ -69780,6 +69814,7 @@ function useLoop(opts) {
|
|
|
69780
69814
|
model: opts.model,
|
|
69781
69815
|
prompt: buildSteeringPrompt(steerMessage),
|
|
69782
69816
|
logFlag: opts.log,
|
|
69817
|
+
logFile: join8(stateDir, "log.json"),
|
|
69783
69818
|
taskDir: tasksDir,
|
|
69784
69819
|
onFeedEvent: addResumeFeedEvent,
|
|
69785
69820
|
signal: resumeController.signal,
|
|
@@ -70262,7 +70297,7 @@ async function writeAgentState(projectRoot, state) {
|
|
|
70262
70297
|
|
|
70263
70298
|
// apps/cli/src/agent/scaffold.ts
|
|
70264
70299
|
import { join as join11 } from "path";
|
|
70265
|
-
import { mkdir } from "fs/promises";
|
|
70300
|
+
import { mkdir as mkdir2 } from "fs/promises";
|
|
70266
70301
|
function changeNameForIssue(issue) {
|
|
70267
70302
|
const slug = issue.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
70268
70303
|
return slug ? `${issue.identifier.toLowerCase()}-${slug}` : issue.identifier.toLowerCase();
|
|
@@ -70271,9 +70306,9 @@ async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = [],
|
|
|
70271
70306
|
const name = changeNameForIssue(issue);
|
|
70272
70307
|
const changeDir = join11(tasksDir, name);
|
|
70273
70308
|
const stateDir = join11(statesDir, name);
|
|
70274
|
-
await
|
|
70275
|
-
await
|
|
70276
|
-
await
|
|
70309
|
+
await mkdir2(changeDir, { recursive: true });
|
|
70310
|
+
await mkdir2(join11(changeDir, "specs"), { recursive: true });
|
|
70311
|
+
await mkdir2(stateDir, { recursive: true });
|
|
70277
70312
|
const commentsBlock = comments.length > 0 ? [
|
|
70278
70313
|
"",
|
|
70279
70314
|
"## Linear comments",
|
|
@@ -70308,6 +70343,8 @@ async function scaffoldChangeForIssue(tasksDir, statesDir, issue, comments = [],
|
|
|
70308
70343
|
const tasks = [
|
|
70309
70344
|
`# Tasks for ${issue.identifier}`,
|
|
70310
70345
|
"",
|
|
70346
|
+
"## Subtasks",
|
|
70347
|
+
"",
|
|
70311
70348
|
`- [ ] Read the Linear issue at ${issue.url} and break it into concrete subtasks`,
|
|
70312
70349
|
`- [ ] Implement the changes described in proposal.md`,
|
|
70313
70350
|
`- [ ] Add or update tests covering the new behavior`,
|
|
@@ -70849,6 +70886,30 @@ ${logs}
|
|
|
70849
70886
|
// apps/cli/src/components/AgentMode.tsx
|
|
70850
70887
|
var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
|
|
70851
70888
|
import { join as join14 } from "path";
|
|
70889
|
+
import { exists } from "fs/promises";
|
|
70890
|
+
async function seedWorktreeMcpConfig(projectRoot, worktreeCwd) {
|
|
70891
|
+
const dst = join14(worktreeCwd, ".mcp.json");
|
|
70892
|
+
const src = join14(projectRoot, ".mcp.json");
|
|
70893
|
+
const source = await exists(dst) ? dst : await exists(src) ? src : null;
|
|
70894
|
+
if (!source)
|
|
70895
|
+
return;
|
|
70896
|
+
let parsed;
|
|
70897
|
+
try {
|
|
70898
|
+
parsed = await Bun.file(source).json();
|
|
70899
|
+
} catch {
|
|
70900
|
+
return;
|
|
70901
|
+
}
|
|
70902
|
+
const servers = parsed.mcpServers;
|
|
70903
|
+
if (servers && typeof servers === "object") {
|
|
70904
|
+
for (const cfg of Object.values(servers)) {
|
|
70905
|
+
if (Array.isArray(cfg.args)) {
|
|
70906
|
+
cfg.args = cfg.args.map((a) => typeof a === "string" && a.startsWith(".ralph/") ? join14(projectRoot, a) : a);
|
|
70907
|
+
}
|
|
70908
|
+
}
|
|
70909
|
+
}
|
|
70910
|
+
await Bun.write(dst, JSON.stringify(parsed, null, 2) + `
|
|
70911
|
+
`);
|
|
70912
|
+
}
|
|
70852
70913
|
var bunGitRunner = {
|
|
70853
70914
|
run: async (args, cwd2) => {
|
|
70854
70915
|
const proc = Bun.spawn({ cmd: ["git", ...args], cwd: cwd2, stdout: "pipe", stderr: "pipe" });
|
|
@@ -71007,6 +71068,11 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
|
|
|
71007
71068
|
scaffoldTasksDir = join14(wt.cwd, "openspec", "changes");
|
|
71008
71069
|
scaffoldStatesDir = join14(wt.cwd, ".ralph", "tasks");
|
|
71009
71070
|
appendLog(` ${issue.identifier} worktree: ${wt.cwd} (${wt.branch})`, "gray");
|
|
71071
|
+
try {
|
|
71072
|
+
await seedWorktreeMcpConfig(projectRoot, wt.cwd);
|
|
71073
|
+
} catch (err) {
|
|
71074
|
+
appendLog(`! seeding .mcp.json failed for ${issue.identifier}: ${err.message}`, "yellow");
|
|
71075
|
+
}
|
|
71010
71076
|
} catch (err) {
|
|
71011
71077
|
appendLog(`! worktree create failed for ${issue.identifier}: ${err.message} \u2014 falling back to project root`, "yellow");
|
|
71012
71078
|
}
|
|
@@ -71450,11 +71516,11 @@ ${check.unpushedCommits}`, "yellow");
|
|
|
71450
71516
|
}
|
|
71451
71517
|
|
|
71452
71518
|
// packages/openspec/src/openspec-change-store.ts
|
|
71453
|
-
import { join as join15, dirname as
|
|
71454
|
-
import { readdir, mkdir as
|
|
71519
|
+
import { join as join15, dirname as dirname4 } from "path";
|
|
71520
|
+
import { readdir, mkdir as mkdir3 } from "fs/promises";
|
|
71455
71521
|
function resolveOpenspecBin() {
|
|
71456
71522
|
const pkgJsonPath = Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir);
|
|
71457
|
-
return join15(
|
|
71523
|
+
return join15(dirname4(pkgJsonPath), "bin", "openspec.js");
|
|
71458
71524
|
}
|
|
71459
71525
|
function runOpenspec(args, options = {}) {
|
|
71460
71526
|
const stdio = options.inherit ? ["inherit", "inherit", "inherit"] : ["ignore", "pipe", "pipe"];
|
|
@@ -71512,7 +71578,7 @@ class OpenSpecChangeStore {
|
|
|
71512
71578
|
}
|
|
71513
71579
|
async writeTaskList(name, content) {
|
|
71514
71580
|
const path = join15("openspec", "changes", name, "tasks.md");
|
|
71515
|
-
await
|
|
71581
|
+
await mkdir3(dirname4(path), { recursive: true });
|
|
71516
71582
|
await Bun.write(path, content);
|
|
71517
71583
|
}
|
|
71518
71584
|
async appendSteering(name, message) {
|
|
@@ -71523,7 +71589,7 @@ class OpenSpecChangeStore {
|
|
|
71523
71589
|
|
|
71524
71590
|
${existing.trimStart()}` : `${message}
|
|
71525
71591
|
`;
|
|
71526
|
-
await
|
|
71592
|
+
await mkdir3(dirname4(path), { recursive: true });
|
|
71527
71593
|
await Bun.write(path, updated);
|
|
71528
71594
|
}
|
|
71529
71595
|
async readSection(name, artifact, heading) {
|
|
@@ -71671,7 +71737,7 @@ if (typeof globalThis.Bun === "undefined") {
|
|
|
71671
71737
|
async function findProjectRoot() {
|
|
71672
71738
|
let dir = process.cwd();
|
|
71673
71739
|
while (dir !== "/") {
|
|
71674
|
-
if (await
|
|
71740
|
+
if (await exists2(join17(dir, "openspec")))
|
|
71675
71741
|
return dir;
|
|
71676
71742
|
dir = resolve(dir, "..");
|
|
71677
71743
|
}
|
|
@@ -71709,8 +71775,8 @@ try {
|
|
|
71709
71775
|
const statesDir = join17(projectRoot, ".ralph", "tasks");
|
|
71710
71776
|
const tasksDir = join17(projectRoot, "openspec", "changes");
|
|
71711
71777
|
if (args.mode === "init") {
|
|
71712
|
-
await
|
|
71713
|
-
const openspecBin = join17(
|
|
71778
|
+
await mkdir4(statesDir, { recursive: true });
|
|
71779
|
+
const openspecBin = join17(dirname5(Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir)), "bin", "openspec.js");
|
|
71714
71780
|
Bun.spawnSync({
|
|
71715
71781
|
cmd: [process.execPath, openspecBin, "init", "--tools", "none", "--force"],
|
|
71716
71782
|
stdio: ["inherit", "inherit", "inherit"],
|
|
@@ -71728,7 +71794,7 @@ try {
|
|
|
71728
71794
|
const stateDir = join17(statesDir, args.name);
|
|
71729
71795
|
const branch = `ralph/${args.name}`;
|
|
71730
71796
|
const removed = [];
|
|
71731
|
-
if (await
|
|
71797
|
+
if (await exists2(worktreeDir)) {
|
|
71732
71798
|
const proc = Bun.spawn({
|
|
71733
71799
|
cmd: ["git", "worktree", "remove", "--force", worktreeDir],
|
|
71734
71800
|
cwd: projectRoot,
|
|
@@ -71755,11 +71821,11 @@ try {
|
|
|
71755
71821
|
});
|
|
71756
71822
|
if (await branchProc.exited === 0)
|
|
71757
71823
|
removed.push(`branch ${branch}`);
|
|
71758
|
-
if (await
|
|
71824
|
+
if (await exists2(changeDir)) {
|
|
71759
71825
|
await rm(changeDir, { recursive: true, force: true });
|
|
71760
71826
|
removed.push(`openspec change ${changeDir}`);
|
|
71761
71827
|
}
|
|
71762
|
-
if (await
|
|
71828
|
+
if (await exists2(stateDir)) {
|
|
71763
71829
|
await rm(stateDir, { recursive: true, force: true });
|
|
71764
71830
|
removed.push(`task state ${stateDir}`);
|
|
71765
71831
|
}
|
|
@@ -71786,13 +71852,13 @@ try {
|
|
|
71786
71852
|
process.exit(0);
|
|
71787
71853
|
}
|
|
71788
71854
|
if (args.mode === "task" && args.name) {
|
|
71789
|
-
await
|
|
71790
|
-
await
|
|
71855
|
+
await mkdir4(join17(statesDir, args.name), { recursive: true });
|
|
71856
|
+
await mkdir4(join17(tasksDir, args.name), { recursive: true });
|
|
71791
71857
|
}
|
|
71792
71858
|
if (args.mode === "agent") {
|
|
71793
|
-
await
|
|
71794
|
-
await
|
|
71795
|
-
await
|
|
71859
|
+
await mkdir4(statesDir, { recursive: true });
|
|
71860
|
+
await mkdir4(tasksDir, { recursive: true });
|
|
71861
|
+
await mkdir4(join17(projectRoot, ".ralph"), { recursive: true });
|
|
71796
71862
|
}
|
|
71797
71863
|
await runWithContext(createDefaultContext(), async () => {
|
|
71798
71864
|
const { waitUntilExit } = render_default(import_react59.createElement(App2, { args, statesDir, tasksDir, projectRoot }));
|