@neriros/ralphy 3.3.1 → 3.4.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/mcp/index.js CHANGED
@@ -25106,22 +25106,6 @@ ${existing.trimStart()}` : `${message}
25106
25106
  await mkdir(dirname3(tasksPath), { recursive: true });
25107
25107
  await Bun.write(tasksPath, next);
25108
25108
  }
25109
- async readSection(name, artifact, heading) {
25110
- const file = Bun.file(join4("openspec", "changes", name, artifact));
25111
- if (!await file.exists())
25112
- return "";
25113
- const content = await file.text();
25114
- const headingIndex = content.indexOf(heading);
25115
- if (headingIndex === -1)
25116
- return "";
25117
- const afterHeading = content.slice(headingIndex + heading.length);
25118
- const levelMatch = heading.match(/^(#+)/);
25119
- const level = levelMatch ? levelMatch[1].length : 2;
25120
- const nextHeadingPattern = new RegExp(`\\n#{1,${level}} `);
25121
- const nextMatch = afterHeading.match(nextHeadingPattern);
25122
- const sectionContent = nextMatch ? afterHeading.slice(0, nextMatch.index) : afterHeading;
25123
- return sectionContent.trim();
25124
- }
25125
25109
  async validateChange(name) {
25126
25110
  const result = runOpenspec(["validate", name, "--json", "--no-interactive"]);
25127
25111
  if (result.stdout) {
@@ -25140,8 +25124,71 @@ ${existing.trimStart()}` : `${message}
25140
25124
  errors: result.stderr ? [result.stderr] : []
25141
25125
  };
25142
25126
  }
25127
+ async getStatus(name) {
25128
+ const result = runOpenspec(["status", "--change", name, "--json"]);
25129
+ if (result.stdout) {
25130
+ try {
25131
+ const parsed = JSON.parse(result.stdout);
25132
+ const status = {
25133
+ changeName: parsed.changeName ?? name,
25134
+ isComplete: parsed.isComplete ?? false,
25135
+ applyRequires: parsed.applyRequires ?? [],
25136
+ artifacts: parsed.artifacts ?? []
25137
+ };
25138
+ if (parsed.schemaName !== undefined)
25139
+ status.schemaName = parsed.schemaName;
25140
+ return status;
25141
+ } catch {}
25142
+ }
25143
+ return {
25144
+ changeName: name,
25145
+ isComplete: false,
25146
+ applyRequires: [],
25147
+ artifacts: []
25148
+ };
25149
+ }
25150
+ async getInstructions(name, artifact) {
25151
+ const result = runOpenspec(["instructions", artifact, "--change", name, "--json"]);
25152
+ if (result.stdout) {
25153
+ try {
25154
+ const parsed = JSON.parse(result.stdout);
25155
+ const out = {
25156
+ changeName: parsed.changeName ?? name,
25157
+ artifactId: parsed.artifactId ?? artifact,
25158
+ instruction: parsed.instruction ?? ""
25159
+ };
25160
+ if (parsed.outputPath !== undefined)
25161
+ out.outputPath = parsed.outputPath;
25162
+ if (parsed.description !== undefined)
25163
+ out.description = parsed.description;
25164
+ if (parsed.template !== undefined)
25165
+ out.template = parsed.template;
25166
+ if (parsed.dependencies !== undefined)
25167
+ out.dependencies = parsed.dependencies;
25168
+ return out;
25169
+ } catch {}
25170
+ }
25171
+ return { changeName: name, artifactId: artifact, instruction: "" };
25172
+ }
25173
+ async showChange(name) {
25174
+ const result = runOpenspec(["show", name, "--json", "--type", "change"]);
25175
+ if (result.stdout) {
25176
+ try {
25177
+ const parsed = JSON.parse(result.stdout);
25178
+ const out = {
25179
+ id: parsed.id ?? name,
25180
+ deltaCount: parsed.deltaCount ?? 0,
25181
+ deltas: parsed.deltas ?? []
25182
+ };
25183
+ if (parsed.title !== undefined)
25184
+ out.title = parsed.title;
25185
+ return out;
25186
+ } catch {}
25187
+ }
25188
+ return { id: name, deltaCount: 0, deltas: [] };
25189
+ }
25143
25190
  async archiveChange(name) {
25144
- const result = runOpenspec(["archive", name, "-y", "--skip-specs"], { inherit: true });
25191
+ const result = runOpenspec(["archive", name, "-y"], { inherit: true });
25145
25192
  if (result.status !== 0) {
25146
25193
  throw new Error("openspec archive failed");
25147
25194
  }
@@ -18928,8 +18928,8 @@ import { readFileSync } from "fs";
18928
18928
  import { resolve } from "path";
18929
18929
  function getVersion() {
18930
18930
  try {
18931
- if ("3.3.1")
18932
- return "3.3.1";
18931
+ if ("3.4.0")
18932
+ return "3.4.0";
18933
18933
  } catch {}
18934
18934
  const dirsToTry = [];
18935
18935
  try {
@@ -59558,22 +59558,6 @@ ${existing.trimStart()}` : `${message}
59558
59558
  await mkdir(dirname4(tasksPath), { recursive: true });
59559
59559
  await Bun.write(tasksPath, next);
59560
59560
  }
59561
- async readSection(name, artifact, heading) {
59562
- const file = Bun.file(join6("openspec", "changes", name, artifact));
59563
- if (!await file.exists())
59564
- return "";
59565
- const content = await file.text();
59566
- const headingIndex = content.indexOf(heading);
59567
- if (headingIndex === -1)
59568
- return "";
59569
- const afterHeading = content.slice(headingIndex + heading.length);
59570
- const levelMatch = heading.match(/^(#+)/);
59571
- const level = levelMatch ? levelMatch[1].length : 2;
59572
- const nextHeadingPattern = new RegExp(`\\n#{1,${level}} `);
59573
- const nextMatch = afterHeading.match(nextHeadingPattern);
59574
- const sectionContent = nextMatch ? afterHeading.slice(0, nextMatch.index) : afterHeading;
59575
- return sectionContent.trim();
59576
- }
59577
59561
  async validateChange(name) {
59578
59562
  const result2 = runOpenspec(["validate", name, "--json", "--no-interactive"]);
59579
59563
  if (result2.stdout) {
@@ -59592,8 +59576,71 @@ ${existing.trimStart()}` : `${message}
59592
59576
  errors: result2.stderr ? [result2.stderr] : []
59593
59577
  };
59594
59578
  }
59579
+ async getStatus(name) {
59580
+ const result2 = runOpenspec(["status", "--change", name, "--json"]);
59581
+ if (result2.stdout) {
59582
+ try {
59583
+ const parsed = JSON.parse(result2.stdout);
59584
+ const status = {
59585
+ changeName: parsed.changeName ?? name,
59586
+ isComplete: parsed.isComplete ?? false,
59587
+ applyRequires: parsed.applyRequires ?? [],
59588
+ artifacts: parsed.artifacts ?? []
59589
+ };
59590
+ if (parsed.schemaName !== undefined)
59591
+ status.schemaName = parsed.schemaName;
59592
+ return status;
59593
+ } catch {}
59594
+ }
59595
+ return {
59596
+ changeName: name,
59597
+ isComplete: false,
59598
+ applyRequires: [],
59599
+ artifacts: []
59600
+ };
59601
+ }
59602
+ async getInstructions(name, artifact) {
59603
+ const result2 = runOpenspec(["instructions", artifact, "--change", name, "--json"]);
59604
+ if (result2.stdout) {
59605
+ try {
59606
+ const parsed = JSON.parse(result2.stdout);
59607
+ const out = {
59608
+ changeName: parsed.changeName ?? name,
59609
+ artifactId: parsed.artifactId ?? artifact,
59610
+ instruction: parsed.instruction ?? ""
59611
+ };
59612
+ if (parsed.outputPath !== undefined)
59613
+ out.outputPath = parsed.outputPath;
59614
+ if (parsed.description !== undefined)
59615
+ out.description = parsed.description;
59616
+ if (parsed.template !== undefined)
59617
+ out.template = parsed.template;
59618
+ if (parsed.dependencies !== undefined)
59619
+ out.dependencies = parsed.dependencies;
59620
+ return out;
59621
+ } catch {}
59622
+ }
59623
+ return { changeName: name, artifactId: artifact, instruction: "" };
59624
+ }
59625
+ async showChange(name) {
59626
+ const result2 = runOpenspec(["show", name, "--json", "--type", "change"]);
59627
+ if (result2.stdout) {
59628
+ try {
59629
+ const parsed = JSON.parse(result2.stdout);
59630
+ const out = {
59631
+ id: parsed.id ?? name,
59632
+ deltaCount: parsed.deltaCount ?? 0,
59633
+ deltas: parsed.deltas ?? []
59634
+ };
59635
+ if (parsed.title !== undefined)
59636
+ out.title = parsed.title;
59637
+ return out;
59638
+ } catch {}
59639
+ }
59640
+ return { id: name, deltaCount: 0, deltas: [] };
59641
+ }
59595
59642
  async archiveChange(name) {
59596
- const result2 = runOpenspec(["archive", name, "-y", "--skip-specs"], { inherit: true });
59643
+ const result2 = runOpenspec(["archive", name, "-y"], { inherit: true });
59597
59644
  if (result2.status !== 0) {
59598
59645
  throw new Error("openspec archive failed");
59599
59646
  }
@@ -70726,6 +70773,14 @@ function useLoop(opts) {
70726
70773
  writeState(stateDir, currentState);
70727
70774
  setState(currentState);
70728
70775
  try {
70776
+ if (typeof opts.changeStore.getStatus === "function") {
70777
+ const status = await opts.changeStore.getStatus(opts.name);
70778
+ if (!status.isComplete) {
70779
+ const blocked = status.artifacts.filter((a) => a.status !== "done").map((a) => `${a.id}=${a.status}`).join(", ");
70780
+ addInfo(`Archive skipped: openspec status reports change incomplete (${blocked || "no artifacts"}).`);
70781
+ throw new Error("openspec status: change not complete");
70782
+ }
70783
+ }
70729
70784
  await opts.changeStore.archiveChange(opts.name);
70730
70785
  addInfo("Change archived.");
70731
70786
  } catch (err) {
@@ -95184,6 +95239,14 @@ ${truncated}`);
95184
95239
 
95185
95240
  `);
95186
95241
  }
95242
+ async function safeSha(getHeadSha) {
95243
+ try {
95244
+ const sha = (await getHeadSha()).trim();
95245
+ return sha || null;
95246
+ } catch {
95247
+ return null;
95248
+ }
95249
+ }
95187
95250
  async function fixCiUntilGreen(deps, opts) {
95188
95251
  for (let attempt2 = 1;attempt2 <= opts.maxAttempts; attempt2++) {
95189
95252
  let pollN = 0;
@@ -95213,10 +95276,18 @@ async function fixCiUntilGreen(deps, opts) {
95213
95276
  \`\`\`
95214
95277
  ${logs}
95215
95278
  \`\`\``;
95279
+ const shaBefore = deps.getHeadSha ? await safeSha(deps.getHeadSha) : null;
95216
95280
  const code = await deps.runTaskWithSteering(steering);
95217
95281
  if (code !== 0) {
95218
95282
  deps.log(`! task loop exited code ${code} during CI fix attempt ${attempt2}`, "red");
95219
95283
  }
95284
+ if (shaBefore !== null) {
95285
+ const shaAfter = await safeSha(deps.getHeadSha);
95286
+ if (shaAfter !== null && shaAfter === shaBefore) {
95287
+ deps.log(`! worker produced no new commits on CI fix attempt ${attempt2} \u2014 failure looks external (e.g. rate-limited deploy). Giving up CI watch.`, "yellow");
95288
+ return { success: false, attempts: attempt2, reason: "no-progress" };
95289
+ }
95290
+ }
95220
95291
  try {
95221
95292
  deps.onPhase?.("ci-fix", `attempt ${attempt2}/${opts.maxAttempts} \xB7 pushing fix`);
95222
95293
  await deps.pushBranch();
@@ -95657,6 +95728,10 @@ async function fixConflictsAndCiLoop(ctx, prUrl, wantFixCi, checkPrConflict) {
95657
95728
  pushBranch: async () => {
95658
95729
  await ctx.cmd.run(["git", "push", "origin", ctx.branch], ctx.cwd);
95659
95730
  },
95731
+ getHeadSha: async () => {
95732
+ const r = await ctx.cmd.run(["git", "rev-parse", "HEAD"], ctx.cwd);
95733
+ return r.stdout.trim();
95734
+ },
95660
95735
  log: ctx.log,
95661
95736
  sleep: (ms) => new Promise((r) => setTimeout(r, ms))
95662
95737
  }, {
@@ -96215,24 +96290,28 @@ function truncate4(s, max2) {
96215
96290
  \u2026(truncated)`;
96216
96291
  }
96217
96292
  function renderTasksBlock(tasksMd, meta3) {
96218
- const sections = parseTasksMd(tasksMd);
96293
+ const sections = parseTasksMd(tasksMd).filter((s) => s.heading.trim().toLowerCase() !== "planning");
96219
96294
  const out = [];
96220
96295
  out.push(RALPHY_TASKS_START);
96221
96296
  out.push("### Ralph progress");
96222
96297
  out.push("");
96223
- for (const section of sections) {
96224
- if (section.items.length === 0)
96225
- continue;
96226
- out.push(`**${section.heading}**`);
96298
+ const renderable = sections.filter((s) => s.items.length > 0);
96299
+ if (renderable.length === 0) {
96300
+ out.push("_No mission tasks yet \u2014 planning in progress._");
96227
96301
  out.push("");
96228
- for (const item of section.items) {
96229
- out.push(item.bullet);
96230
- if (item.code !== undefined) {
96231
- const inner = truncate4(item.code, MAX_CODE_BLOCK_BYTES);
96232
- out.push(` <details><summary>output</summary><pre>${inner}</pre></details>`);
96302
+ } else {
96303
+ for (const section of renderable) {
96304
+ out.push(`**${section.heading}**`);
96305
+ out.push("");
96306
+ for (const item of section.items) {
96307
+ out.push(item.bullet);
96308
+ if (item.code !== undefined) {
96309
+ const inner = truncate4(item.code, MAX_CODE_BLOCK_BYTES);
96310
+ out.push(` <details><summary>output</summary><pre>${inner}</pre></details>`);
96311
+ }
96233
96312
  }
96313
+ out.push("");
96234
96314
  }
96235
- out.push("");
96236
96315
  }
96237
96316
  out.push(`<sub>\`${meta3.changeName}\` \xB7 iteration ${meta3.iteration}</sub>`);
96238
96317
  out.push(RALPHY_TASKS_END);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neriros/ralphy",
3
- "version": "3.3.1",
3
+ "version": "3.4.0",
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",