@neriros/ralphy 2.21.1 → 2.21.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/README.md CHANGED
@@ -181,10 +181,16 @@ Example `ralphy.config.json`:
181
181
  "codeReviewStaleHours": 24,
182
182
  "indicators": {
183
183
  "getTodo": { "filter": [{ "type": "status", "value": "Todo" }] },
184
- "getInProgress": { "filter": [{ "type": "status", "value": "In Progress" }] },
185
- "getConflicted": { "filter": [{ "type": "label", "value": "ralph:conflicted" }] },
184
+ "getInProgress": {
185
+ "filter": [{ "type": "status", "value": "In Progress" }],
186
+ },
187
+ "getConflicted": {
188
+ "filter": [{ "type": "label", "value": "ralph:conflicted" }],
189
+ },
186
190
  "getReview": { "filter": [{ "type": "label", "value": "ralph:review" }] },
187
- "getAutoMerge": { "filter": [{ "type": "label", "value": "ralph:auto-merge" }] },
191
+ "getAutoMerge": {
192
+ "filter": [{ "type": "label", "value": "ralph:auto-merge" }],
193
+ },
188
194
  "setInProgress": { "type": "status", "value": "In Progress" },
189
195
  "setDone": {
190
196
  "apply": [
@@ -243,6 +249,9 @@ With `useWorktree: true` (or `--worktree`) each task runs in an isolated worktre
243
249
 
244
250
  - **`setupScript`** — `sh -c`-run inside the worktree right after scaffolding (e.g. `bun install`, `cp .env.example .env`).
245
251
  - **`teardownScript`** — `sh -c`-run after the loop exits and (optional) worktree cleanup.
252
+
253
+ Both scripts receive `WORKSPACE_ROOT` in their environment — the absolute path to the origin repository (the parent of the worktree). Use it to reference project-root files from inside a worktree, e.g. `cp "$WORKSPACE_ROOT/.env.example" .env`.
254
+
246
255
  - **`cleanupWorktreeOnSuccess`** — remove the worktree on clean exit. Failed workers always keep their worktree + branch for human inspection.
247
256
 
248
257
  Both scripts log failures but never block the loop. **`appendPrompt`** (or `--prompt` in agent mode) is appended to every scaffolded `proposal.md` under `## Additional instructions` — use it for cross-cutting guidance every task should see.
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.21.1")
35033
- return "2.21.1";
35032
+ if ("2.21.3")
35033
+ return "2.21.3";
35034
35034
  } catch {}
35035
35035
  const dirsToTry = [];
35036
35036
  try {
@@ -61460,6 +61460,7 @@ function buildAgentCoordinator(input) {
61460
61460
  const proc = Bun.spawn({
61461
61461
  cmd: ["sh", "-c", cmd],
61462
61462
  cwd: cwd2,
61463
+ env: { ...process.env, WORKSPACE_ROOT: projectRoot },
61463
61464
  stdout: "ignore",
61464
61465
  stderr: "pipe",
61465
61466
  stdin: "ignore"
@@ -62245,7 +62246,7 @@ var exports_json_runner = {};
62245
62246
  __export(exports_json_runner, {
62246
62247
  runAgentJson: () => runAgentJson
62247
62248
  });
62248
- import { join as join21 } from "path";
62249
+ import { join as join22 } from "path";
62249
62250
  import { mkdir as mkdir6 } from "fs/promises";
62250
62251
  import { homedir as homedir4 } from "os";
62251
62252
  function cleanOutputLine2(raw) {
@@ -62270,7 +62271,7 @@ async function runAgentJson({
62270
62271
  statesDir,
62271
62272
  tasksDir
62272
62273
  }) {
62273
- await mkdir6(join21(homedir4(), ".ralph"), { recursive: true }).catch(() => {
62274
+ await mkdir6(join22(homedir4(), ".ralph"), { recursive: true }).catch(() => {
62274
62275
  return;
62275
62276
  });
62276
62277
  const cfgPath = await ensureRalphyConfig(projectRoot);
@@ -62409,7 +62410,7 @@ var init_json_runner = __esm(() => {
62409
62410
  });
62410
62411
 
62411
62412
  // apps/cli/src/index.ts
62412
- import { resolve as resolve2, join as join22, dirname as dirname6 } from "path";
62413
+ import { resolve as resolve2, join as join23 } from "path";
62413
62414
  import { exists as exists2, mkdir as mkdir7, rm } from "fs/promises";
62414
62415
 
62415
62416
  // node_modules/.bun/ink@5.2.1+1f88f629f0141b18/node_modules/ink/build/render.js
@@ -67532,7 +67533,7 @@ function createDefaultContext() {
67532
67533
 
67533
67534
  // apps/cli/src/components/App.tsx
67534
67535
  var import_react58 = __toESM(require_react(), 1);
67535
- import { join as join19 } from "path";
67536
+ import { join as join20 } from "path";
67536
67537
 
67537
67538
  // packages/core/src/state.ts
67538
67539
  init_types2();
@@ -74236,16 +74237,79 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
74236
74237
  }
74237
74238
 
74238
74239
  // packages/openspec/src/openspec-change-store.ts
74239
- import { join as join18, dirname as dirname5 } from "path";
74240
+ import { dirname as dirname6, join as join19 } from "path";
74240
74241
  import { readdir, mkdir as mkdir5 } from "fs/promises";
74241
- function resolveOpenspecBin() {
74242
- const pkgJsonPath = Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir);
74243
- return join18(dirname5(pkgJsonPath), "bin", "openspec.js");
74242
+
74243
+ // packages/openspec/src/openspec-bin.ts
74244
+ import { dirname as dirname5, join as join18 } from "path";
74245
+ var bunInstallRunner = {
74246
+ spawnSync: (cmd, cwd2) => {
74247
+ const proc = Bun.spawnSync({
74248
+ cmd,
74249
+ cwd: cwd2,
74250
+ stdio: ["ignore", "inherit", "inherit"]
74251
+ });
74252
+ return { exitCode: proc.exitCode };
74253
+ },
74254
+ resolveSync: (specifier, fromDir) => Bun.resolveSync(specifier, fromDir),
74255
+ log: (text) => {
74256
+ process.stderr.write(text);
74257
+ }
74258
+ };
74259
+ function findPackageRoot(startDir) {
74260
+ let dir = startDir;
74261
+ for (let i = 0;i < 8; i++) {
74262
+ if (Bun.file(join18(dir, "package.json")).size >= 0) {
74263
+ try {
74264
+ if (Bun.file(join18(dir, "package.json")).size > 0)
74265
+ return dir;
74266
+ } catch {}
74267
+ }
74268
+ const parent = dirname5(dir);
74269
+ if (parent === dir)
74270
+ break;
74271
+ dir = parent;
74272
+ }
74273
+ return startDir;
74244
74274
  }
74275
+ function ensureOpenspecInstalled(fromDir, runner) {
74276
+ const installDir = findPackageRoot(fromDir);
74277
+ runner.log(`[ralphy] @fission-ai/openspec not found in ${installDir} \u2014 installing automatically...
74278
+ `);
74279
+ const candidates = [
74280
+ ["npm", "install", "--no-save", "--no-audit", "--no-fund", "@fission-ai/openspec@latest"],
74281
+ ["bun", "add", "@fission-ai/openspec@latest"]
74282
+ ];
74283
+ for (const cmd of candidates) {
74284
+ try {
74285
+ const result2 = runner.spawnSync(cmd, installDir);
74286
+ if (result2.exitCode === 0) {
74287
+ runner.log(`[ralphy] installed @fission-ai/openspec via ${cmd[0]}.
74288
+ `);
74289
+ return;
74290
+ }
74291
+ } catch {}
74292
+ }
74293
+ const err = new Error("openspec auto-install failed");
74294
+ err.installDir = installDir;
74295
+ throw err;
74296
+ }
74297
+ function resolveOpenspecBin(fromDir, runner = bunInstallRunner) {
74298
+ try {
74299
+ const pkgJsonPath = runner.resolveSync("@fission-ai/openspec/package.json", fromDir);
74300
+ return join18(dirname5(pkgJsonPath), "bin", "openspec.js");
74301
+ } catch {
74302
+ ensureOpenspecInstalled(fromDir, runner);
74303
+ const pkgJsonPath = runner.resolveSync("@fission-ai/openspec/package.json", fromDir);
74304
+ return join18(dirname5(pkgJsonPath), "bin", "openspec.js");
74305
+ }
74306
+ }
74307
+
74308
+ // packages/openspec/src/openspec-change-store.ts
74245
74309
  function runOpenspec(args, options = {}) {
74246
74310
  const stdio = options.inherit ? ["inherit", "inherit", "inherit"] : ["ignore", "pipe", "pipe"];
74247
74311
  const proc = Bun.spawnSync({
74248
- cmd: [process.execPath, resolveOpenspecBin(), ...args],
74312
+ cmd: [process.execPath, resolveOpenspecBin(import.meta.dir), ...args],
74249
74313
  stdio
74250
74314
  });
74251
74315
  const decoder = new TextDecoder;
@@ -74266,7 +74330,7 @@ class OpenSpecChangeStore {
74266
74330
  }
74267
74331
  }
74268
74332
  getChangeDirectory(name) {
74269
- return join18("openspec", "changes", name);
74333
+ return join19("openspec", "changes", name);
74270
74334
  }
74271
74335
  async listChanges() {
74272
74336
  const result2 = runOpenspec(["list", "--json"]);
@@ -74280,7 +74344,7 @@ class OpenSpecChangeStore {
74280
74344
  }
74281
74345
  } catch {}
74282
74346
  }
74283
- const changesDir = join18("openspec", "changes");
74347
+ const changesDir = join19("openspec", "changes");
74284
74348
  if (!await Bun.file(changesDir).exists())
74285
74349
  return [];
74286
74350
  try {
@@ -74291,29 +74355,29 @@ class OpenSpecChangeStore {
74291
74355
  }
74292
74356
  }
74293
74357
  async readTaskList(name) {
74294
- const file = Bun.file(join18("openspec", "changes", name, "tasks.md"));
74358
+ const file = Bun.file(join19("openspec", "changes", name, "tasks.md"));
74295
74359
  if (!await file.exists())
74296
74360
  return "";
74297
74361
  return await file.text();
74298
74362
  }
74299
74363
  async writeTaskList(name, content) {
74300
- const path = join18("openspec", "changes", name, "tasks.md");
74301
- await mkdir5(dirname5(path), { recursive: true });
74364
+ const path = join19("openspec", "changes", name, "tasks.md");
74365
+ await mkdir5(dirname6(path), { recursive: true });
74302
74366
  await Bun.write(path, content);
74303
74367
  }
74304
74368
  async appendSteering(name, message) {
74305
- const path = join18("openspec", "changes", name, "steering.md");
74369
+ const path = join19("openspec", "changes", name, "steering.md");
74306
74370
  const file = Bun.file(path);
74307
74371
  const existing = await file.exists() ? await file.text() : null;
74308
74372
  const updated = existing ? `${message}
74309
74373
 
74310
74374
  ${existing.trimStart()}` : `${message}
74311
74375
  `;
74312
- await mkdir5(dirname5(path), { recursive: true });
74376
+ await mkdir5(dirname6(path), { recursive: true });
74313
74377
  await Bun.write(path, updated);
74314
74378
  }
74315
74379
  async readSection(name, artifact, heading) {
74316
- const file = Bun.file(join18("openspec", "changes", name, artifact));
74380
+ const file = Bun.file(join19("openspec", "changes", name, artifact));
74317
74381
  if (!await file.exists())
74318
74382
  return "";
74319
74383
  const content = await file.text();
@@ -74432,8 +74496,8 @@ function App2({ args, statesDir, tasksDir, projectRoot }) {
74432
74496
  message: "Error: --name is required for status mode"
74433
74497
  }, undefined, false, undefined, this);
74434
74498
  }
74435
- const stateDir = join19(statesDir, args.name);
74436
- if (getStorage().read(join19(stateDir, ".ralph-state.json")) === null) {
74499
+ const stateDir = join20(statesDir, args.name);
74500
+ if (getStorage().read(join20(stateDir, ".ralph-state.json")) === null) {
74437
74501
  return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(ErrorMessage, {
74438
74502
  message: `Error: change '${args.name}' not found`
74439
74503
  }, undefined, false, undefined, this);
@@ -74480,7 +74544,7 @@ init_worktree();
74480
74544
 
74481
74545
  // apps/cli/src/debug.ts
74482
74546
  init_log();
74483
- import { join as join20 } from "path";
74547
+ import { join as join21 } from "path";
74484
74548
  function fmtTs(d) {
74485
74549
  return d.toISOString().replace("T", " ").slice(0, 23);
74486
74550
  }
@@ -74593,7 +74657,7 @@ function detectStuck(lines) {
74593
74657
  };
74594
74658
  }
74595
74659
  async function inspectBinary(projectRoot) {
74596
- const binPath = join20(projectRoot, ".ralph", "bin", "cli.js");
74660
+ const binPath = join21(projectRoot, ".ralph", "bin", "cli.js");
74597
74661
  const file = Bun.file(binPath);
74598
74662
  if (!await file.exists())
74599
74663
  return null;
@@ -74619,7 +74683,7 @@ var SPAWN_RE = /\u25B6 (\S+) \u2192 (\S+)/;
74619
74683
  async function resolveDebugTarget(projectRoot, opts) {
74620
74684
  const agentLogFile = Bun.file(AGENT_LOG_PATH);
74621
74685
  const textLines = await agentLogFile.exists() ? parseTextLog(await agentLogFile.text()) : [];
74622
- const jsonlLogFile = Bun.file(join20(projectRoot, ".ralph", "agent.log"));
74686
+ const jsonlLogFile = Bun.file(join21(projectRoot, ".ralph", "agent.log"));
74623
74687
  const jsonlLines = await jsonlLogFile.exists() ? parseJsonlLog(await jsonlLogFile.text()) : [];
74624
74688
  const allLines = [...textLines, ...jsonlLines];
74625
74689
  if (opts.name && !opts.issue) {
@@ -74724,7 +74788,7 @@ async function runDebug(opts) {
74724
74788
  `);
74725
74789
  const agentLogFile = Bun.file(AGENT_LOG_PATH);
74726
74790
  const textLines = await agentLogFile.exists() ? parseTextLog(await agentLogFile.text()) : [];
74727
- const jsonlLogPath = join20(projectRoot, ".ralph", "agent.log");
74791
+ const jsonlLogPath = join21(projectRoot, ".ralph", "agent.log");
74728
74792
  const jsonlLogFile = Bun.file(jsonlLogPath);
74729
74793
  const hasJsonlLog = await jsonlLogFile.exists();
74730
74794
  let { changeName, identifier: issueIdentifier } = await resolveDebugTarget(projectRoot, {
@@ -74738,7 +74802,7 @@ async function runDebug(opts) {
74738
74802
  }
74739
74803
  const jsonlLines = hasJsonlLog ? parseJsonlLog(await jsonlLogFile.text(), changeName) : [];
74740
74804
  const relevantText = textLines.filter((l) => l.text.includes(changeName) || issueIdentifier !== undefined && l.text.includes(issueIdentifier));
74741
- const workerLogFile = Bun.file(join20(projectRoot, ".ralph", "logs", `${changeName}.log`));
74805
+ const workerLogFile = Bun.file(join21(projectRoot, ".ralph", "logs", `${changeName}.log`));
74742
74806
  const workerLines = await workerLogFile.exists() ? parseTextLog(await workerLogFile.text()) : [];
74743
74807
  const merged = [...relevantText, ...jsonlLines, ...workerLines].sort((a, b) => +a.ts - +b.ts);
74744
74808
  const seen = new Set;
@@ -74895,8 +74959,8 @@ async function runDebug(opts) {
74895
74959
  out(" \u26A0 PR currently has merge conflicts");
74896
74960
  if (pr?.checks.some((c) => c.conclusion === "FAILURE"))
74897
74961
  out(" \u26A0 PR has failing CI checks");
74898
- const worktreePath = join20(projectRoot, ".ralph", "worktrees", changeName);
74899
- if (await Bun.file(join20(worktreePath, ".git")).exists()) {
74962
+ const worktreePath = join21(projectRoot, ".ralph", "worktrees", changeName);
74963
+ if (await Bun.file(join21(worktreePath, ".git")).exists()) {
74900
74964
  out(` Worktree : ${worktreePath}`);
74901
74965
  }
74902
74966
  if (!timeline.length)
@@ -74914,7 +74978,7 @@ if (typeof globalThis.Bun === "undefined") {
74914
74978
  async function findProjectRoot() {
74915
74979
  let dir = process.cwd();
74916
74980
  while (dir !== "/") {
74917
- if (await exists2(join22(dir, "openspec")))
74981
+ if (await exists2(join23(dir, "openspec")))
74918
74982
  return dir;
74919
74983
  dir = resolve2(dir, "..");
74920
74984
  }
@@ -74955,7 +75019,7 @@ try {
74955
75019
  const tasksDir = layout.tasksDir;
74956
75020
  if (args.mode === "init") {
74957
75021
  await mkdir7(statesDir, { recursive: true });
74958
- const openspecBin = join22(dirname6(Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir)), "bin", "openspec.js");
75022
+ const openspecBin = resolveOpenspecBin(import.meta.dir);
74959
75023
  Bun.spawnSync({
74960
75024
  cmd: [process.execPath, openspecBin, "init", "--tools", "none", "--force"],
74961
75025
  stdio: ["inherit", "inherit", "inherit"],
@@ -74978,9 +75042,9 @@ try {
74978
75042
  `);
74979
75043
  process.exit(1);
74980
75044
  }
74981
- const worktreeDir = join22(worktreesDir(projectRoot), args.name);
74982
- const changeDir = join22(tasksDir, args.name);
74983
- const stateDir = join22(statesDir, args.name);
75045
+ const worktreeDir = join23(worktreesDir(projectRoot), args.name);
75046
+ const changeDir = join23(tasksDir, args.name);
75047
+ const stateDir = join23(statesDir, args.name);
74984
75048
  const branch = `ralph/${args.name}`;
74985
75049
  const removed = [];
74986
75050
  if (await exists2(worktreeDir)) {
@@ -75032,13 +75096,13 @@ try {
75032
75096
  process.exit(0);
75033
75097
  }
75034
75098
  if (args.mode === "task" && args.name) {
75035
- await mkdir7(join22(statesDir, args.name), { recursive: true });
75036
- await mkdir7(join22(tasksDir, args.name), { recursive: true });
75099
+ await mkdir7(join23(statesDir, args.name), { recursive: true });
75100
+ await mkdir7(join23(tasksDir, args.name), { recursive: true });
75037
75101
  }
75038
75102
  if (args.mode === "agent") {
75039
75103
  await mkdir7(statesDir, { recursive: true });
75040
75104
  await mkdir7(tasksDir, { recursive: true });
75041
- await mkdir7(join22(projectRoot, ".ralph"), { recursive: true });
75105
+ await mkdir7(join23(projectRoot, ".ralph"), { recursive: true });
75042
75106
  }
75043
75107
  if (args.mode === "agent" && args.jsonOutput) {
75044
75108
  const { runAgentJson: runAgentJson2 } = await Promise.resolve().then(() => (init_json_runner(), exports_json_runner));
package/dist/mcp/index.js CHANGED
@@ -6605,7 +6605,7 @@ var require_dist = __commonJS((exports, module) => {
6605
6605
  });
6606
6606
 
6607
6607
  // apps/mcp/src/index.ts
6608
- import { resolve, join as join4 } from "path";
6608
+ import { resolve, join as join5 } from "path";
6609
6609
  import { exists } from "fs/promises";
6610
6610
 
6611
6611
  // packages/context/src/context.ts
@@ -24900,16 +24900,79 @@ function error2(msg) {
24900
24900
  }
24901
24901
 
24902
24902
  // packages/openspec/src/openspec-change-store.ts
24903
- import { join as join3, dirname as dirname2 } from "path";
24903
+ import { dirname as dirname3, join as join4 } from "path";
24904
24904
  import { readdir, mkdir } from "fs/promises";
24905
- function resolveOpenspecBin() {
24906
- const pkgJsonPath = Bun.resolveSync("@fission-ai/openspec/package.json", import.meta.dir);
24907
- return join3(dirname2(pkgJsonPath), "bin", "openspec.js");
24905
+
24906
+ // packages/openspec/src/openspec-bin.ts
24907
+ import { dirname as dirname2, join as join3 } from "path";
24908
+ var bunInstallRunner = {
24909
+ spawnSync: (cmd, cwd) => {
24910
+ const proc = Bun.spawnSync({
24911
+ cmd,
24912
+ cwd,
24913
+ stdio: ["ignore", "inherit", "inherit"]
24914
+ });
24915
+ return { exitCode: proc.exitCode };
24916
+ },
24917
+ resolveSync: (specifier, fromDir) => Bun.resolveSync(specifier, fromDir),
24918
+ log: (text) => {
24919
+ process.stderr.write(text);
24920
+ }
24921
+ };
24922
+ function findPackageRoot(startDir) {
24923
+ let dir = startDir;
24924
+ for (let i = 0;i < 8; i++) {
24925
+ if (Bun.file(join3(dir, "package.json")).size >= 0) {
24926
+ try {
24927
+ if (Bun.file(join3(dir, "package.json")).size > 0)
24928
+ return dir;
24929
+ } catch {}
24930
+ }
24931
+ const parent = dirname2(dir);
24932
+ if (parent === dir)
24933
+ break;
24934
+ dir = parent;
24935
+ }
24936
+ return startDir;
24937
+ }
24938
+ function ensureOpenspecInstalled(fromDir, runner) {
24939
+ const installDir = findPackageRoot(fromDir);
24940
+ runner.log(`[ralphy] @fission-ai/openspec not found in ${installDir} \u2014 installing automatically...
24941
+ `);
24942
+ const candidates = [
24943
+ ["npm", "install", "--no-save", "--no-audit", "--no-fund", "@fission-ai/openspec@latest"],
24944
+ ["bun", "add", "@fission-ai/openspec@latest"]
24945
+ ];
24946
+ for (const cmd of candidates) {
24947
+ try {
24948
+ const result = runner.spawnSync(cmd, installDir);
24949
+ if (result.exitCode === 0) {
24950
+ runner.log(`[ralphy] installed @fission-ai/openspec via ${cmd[0]}.
24951
+ `);
24952
+ return;
24953
+ }
24954
+ } catch {}
24955
+ }
24956
+ const err = new Error("openspec auto-install failed");
24957
+ err.installDir = installDir;
24958
+ throw err;
24908
24959
  }
24960
+ function resolveOpenspecBin(fromDir, runner = bunInstallRunner) {
24961
+ try {
24962
+ const pkgJsonPath = runner.resolveSync("@fission-ai/openspec/package.json", fromDir);
24963
+ return join3(dirname2(pkgJsonPath), "bin", "openspec.js");
24964
+ } catch {
24965
+ ensureOpenspecInstalled(fromDir, runner);
24966
+ const pkgJsonPath = runner.resolveSync("@fission-ai/openspec/package.json", fromDir);
24967
+ return join3(dirname2(pkgJsonPath), "bin", "openspec.js");
24968
+ }
24969
+ }
24970
+
24971
+ // packages/openspec/src/openspec-change-store.ts
24909
24972
  function runOpenspec(args, options = {}) {
24910
24973
  const stdio = options.inherit ? ["inherit", "inherit", "inherit"] : ["ignore", "pipe", "pipe"];
24911
24974
  const proc = Bun.spawnSync({
24912
- cmd: [process.execPath, resolveOpenspecBin(), ...args],
24975
+ cmd: [process.execPath, resolveOpenspecBin(import.meta.dir), ...args],
24913
24976
  stdio
24914
24977
  });
24915
24978
  const decoder = new TextDecoder;
@@ -24930,7 +24993,7 @@ class OpenSpecChangeStore {
24930
24993
  }
24931
24994
  }
24932
24995
  getChangeDirectory(name) {
24933
- return join3("openspec", "changes", name);
24996
+ return join4("openspec", "changes", name);
24934
24997
  }
24935
24998
  async listChanges() {
24936
24999
  const result = runOpenspec(["list", "--json"]);
@@ -24944,7 +25007,7 @@ class OpenSpecChangeStore {
24944
25007
  }
24945
25008
  } catch {}
24946
25009
  }
24947
- const changesDir = join3("openspec", "changes");
25010
+ const changesDir = join4("openspec", "changes");
24948
25011
  if (!await Bun.file(changesDir).exists())
24949
25012
  return [];
24950
25013
  try {
@@ -24955,29 +25018,29 @@ class OpenSpecChangeStore {
24955
25018
  }
24956
25019
  }
24957
25020
  async readTaskList(name) {
24958
- const file = Bun.file(join3("openspec", "changes", name, "tasks.md"));
25021
+ const file = Bun.file(join4("openspec", "changes", name, "tasks.md"));
24959
25022
  if (!await file.exists())
24960
25023
  return "";
24961
25024
  return await file.text();
24962
25025
  }
24963
25026
  async writeTaskList(name, content) {
24964
- const path = join3("openspec", "changes", name, "tasks.md");
24965
- await mkdir(dirname2(path), { recursive: true });
25027
+ const path = join4("openspec", "changes", name, "tasks.md");
25028
+ await mkdir(dirname3(path), { recursive: true });
24966
25029
  await Bun.write(path, content);
24967
25030
  }
24968
25031
  async appendSteering(name, message) {
24969
- const path = join3("openspec", "changes", name, "steering.md");
25032
+ const path = join4("openspec", "changes", name, "steering.md");
24970
25033
  const file = Bun.file(path);
24971
25034
  const existing = await file.exists() ? await file.text() : null;
24972
25035
  const updated = existing ? `${message}
24973
25036
 
24974
25037
  ${existing.trimStart()}` : `${message}
24975
25038
  `;
24976
- await mkdir(dirname2(path), { recursive: true });
25039
+ await mkdir(dirname3(path), { recursive: true });
24977
25040
  await Bun.write(path, updated);
24978
25041
  }
24979
25042
  async readSection(name, artifact, heading) {
24980
- const file = Bun.file(join3("openspec", "changes", name, artifact));
25043
+ const file = Bun.file(join4("openspec", "changes", name, artifact));
24981
25044
  if (!await file.exists())
24982
25045
  return "";
24983
25046
  const content = await file.text();
@@ -25021,7 +25084,7 @@ ${existing.trimStart()}` : `${message}
25021
25084
  async function findProjectRoot(startDir) {
25022
25085
  let dir = startDir;
25023
25086
  while (dir !== "/") {
25024
- if (await exists(join4(dir, "openspec")))
25087
+ if (await exists(join5(dir, "openspec")))
25025
25088
  return dir;
25026
25089
  dir = resolve(dir, "..");
25027
25090
  }
@@ -25035,8 +25098,8 @@ async function main() {
25035
25098
  startDir = resolve(args[dirIdx + 1]);
25036
25099
  }
25037
25100
  const projectRoot = await findProjectRoot(startDir);
25038
- const changesDir = join4(projectRoot, ".ralph", "tasks");
25039
- const taskFilesDir = join4(projectRoot, "openspec", "changes");
25101
+ const changesDir = join5(projectRoot, ".ralph", "tasks");
25102
+ const taskFilesDir = join5(projectRoot, "openspec", "changes");
25040
25103
  const changeStore = new OpenSpecChangeStore;
25041
25104
  const server = new McpServer({
25042
25105
  name: "ralph",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neriros/ralphy",
3
- "version": "2.21.1",
3
+ "version": "2.21.3",
4
4
  "description": "An iterative AI task execution framework. Orchestrates multi-phase autonomous work using Claude or Codex engines.",
5
5
  "keywords": [
6
6
  "agent",
@@ -56,10 +56,12 @@
56
56
  "copy-assets": "bun scripts/copy-assets.ts",
57
57
  "prepublishOnly": "bun run build:publish"
58
58
  },
59
+ "dependencies": {
60
+ "@fission-ai/openspec": "latest"
61
+ },
59
62
  "devDependencies": {
60
63
  "@commitlint/cli": "^20.5.3",
61
64
  "@commitlint/config-conventional": "^20.5.3",
62
- "@fission-ai/openspec": "latest",
63
65
  "@modelcontextprotocol/sdk": "^1.29.0",
64
66
  "@nx/devkit": "^22.7.1",
65
67
  "@nx/js": "^22.7.1",