@neriros/ralphy 2.13.4 → 2.13.5

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.
Files changed (2) hide show
  1. package/dist/cli/index.js +257 -35
  2. 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.13.4",
56410
+ version: "2.13.5",
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",
@@ -71919,7 +71919,7 @@ PR: ${prUrl}` : ""
71919
71919
  return injected(buildTaskCmdFor(changeName), cwd2).exited;
71920
71920
  return defaultSpawn(changeName, buildTaskCmdFor(changeName), cwd2, `respawn at ${new Date().toISOString()}`).exited;
71921
71921
  };
71922
- onWorkerStarted(changeName, statesDirByChange.get(changeName) ?? statesDir, logFilePath);
71922
+ onWorkerStarted(changeName, statesDirByChange.get(changeName) ?? statesDir, logFilePath, projectLayout(cwd2).changeDir(changeName));
71923
71923
  onWorkerPhase?.(changeName, "working");
71924
71924
  const tracedCmd = onWorkerCmd ? traceCmdRunner(cmdRunner, (cmd) => onWorkerCmd(changeName, cmd, "start"), (cmd, ms, ok) => onWorkerCmd(changeName, cmd, "end", ms, ok)) : cmdRunner;
71925
71925
  const wantPr = args.createPr || cfg.createPrOnSuccess;
@@ -71954,6 +71954,7 @@ PR: ${prUrl}` : ""
71954
71954
  registerPr: (cn, url) => {
71955
71955
  prByChange.set(cn, url);
71956
71956
  prUnavailable.delete(cn);
71957
+ input.onWorkerPr?.(cn, url);
71957
71958
  },
71958
71959
  ...onWorkerPhase && {
71959
71960
  onPhase: (phase, detail) => onWorkerPhase(changeName, phase, detail)
@@ -72085,7 +72086,7 @@ function nextId() {
72085
72086
  lineCounter += 1;
72086
72087
  return `${Date.now()}-${lineCounter}`;
72087
72088
  }
72088
- var TAIL_MAX_LINES = 5;
72089
+ var TAIL_BUFFER_SIZE = 30;
72089
72090
  var CMD_DISPLAY_MAX = 80;
72090
72091
  function fmtCmd(argv) {
72091
72092
  const joined = argv.join(" ");
@@ -72103,6 +72104,92 @@ function fmtElapsed(ms) {
72103
72104
  const h = Math.floor(m / 60);
72104
72105
  return `${h}h${(m % 60).toString().padStart(2, "0")}m`;
72105
72106
  }
72107
+ function trunc(s, max2) {
72108
+ return s.length > max2 ? s.slice(0, max2 - 1) + "\u2026" : s;
72109
+ }
72110
+ function priorityBadge(p) {
72111
+ switch (p) {
72112
+ case 1:
72113
+ return { text: "!", color: "red" };
72114
+ case 2:
72115
+ return { text: "\u2191", color: "yellow" };
72116
+ case 3:
72117
+ return { text: "\xB7", color: "blue" };
72118
+ case 4:
72119
+ return { text: "\u2193", color: "gray" };
72120
+ default:
72121
+ return { text: " ", color: "gray" };
72122
+ }
72123
+ }
72124
+ function modeBadge(mode) {
72125
+ switch (mode) {
72126
+ case "fresh":
72127
+ return { text: "new", color: "cyan" };
72128
+ case "resume":
72129
+ return { text: "resume", color: "yellow" };
72130
+ case "conflict-fix":
72131
+ return { text: "fix", color: "magenta" };
72132
+ default:
72133
+ return { text: mode, color: "white" };
72134
+ }
72135
+ }
72136
+ function phaseColor(phase) {
72137
+ switch (phase) {
72138
+ case "working":
72139
+ return "cyan";
72140
+ case "scaffolding":
72141
+ return "magenta";
72142
+ case "committing":
72143
+ case "commit-retry":
72144
+ case "pushing":
72145
+ case "push-retry":
72146
+ case "rebasing":
72147
+ case "pr-create":
72148
+ return "yellow";
72149
+ case "ci-poll":
72150
+ case "ci-fix":
72151
+ return "blue";
72152
+ case "teardown":
72153
+ case "cleanup":
72154
+ return "gray";
72155
+ case "done":
72156
+ return "green";
72157
+ case "gave-up":
72158
+ return "red";
72159
+ default:
72160
+ return "white";
72161
+ }
72162
+ }
72163
+ function displayTailLines(activeCount) {
72164
+ if (activeCount <= 1)
72165
+ return 20;
72166
+ if (activeCount <= 2)
72167
+ return 12;
72168
+ if (activeCount <= 3)
72169
+ return 8;
72170
+ return 6;
72171
+ }
72172
+ function settingsSummary(cfg, filterDesc) {
72173
+ const parts = [
72174
+ `${cfg.engine}/${cfg.model}`,
72175
+ `concurrency: ${cfg.concurrency}`,
72176
+ `poll: ${cfg.pollIntervalSeconds}s`
72177
+ ];
72178
+ if (cfg.maxIterationsPerTask > 0)
72179
+ parts.push(`maxIter: ${cfg.maxIterationsPerTask}`);
72180
+ if (cfg.maxCostUsdPerTask > 0)
72181
+ parts.push(`maxCost: $${cfg.maxCostUsdPerTask}`);
72182
+ if (cfg.maxRuntimeMinutesPerTask > 0)
72183
+ parts.push(`maxRuntime: ${cfg.maxRuntimeMinutesPerTask}m`);
72184
+ if (cfg.createPrOnSuccess)
72185
+ parts.push("PR: on");
72186
+ if (cfg.fixCiOnFailure)
72187
+ parts.push("fixCI: on");
72188
+ if (cfg.useWorktree)
72189
+ parts.push("worktree: on");
72190
+ const settingsStr = parts.join(" \xB7 ");
72191
+ return filterDesc ? `${settingsStr} [${filterDesc}]` : settingsStr;
72192
+ }
72106
72193
  function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72107
72194
  const { exit } = use_app_default();
72108
72195
  const [logs, setLogs] = import_react57.useState([]);
@@ -72111,6 +72198,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72111
72198
  const coordRef = import_react57.useRef(null);
72112
72199
  const workerMetaRef = import_react57.useRef(new Map);
72113
72200
  const nextPollAtRef = import_react57.useRef(0);
72201
+ const cfgRef = import_react57.useRef(null);
72114
72202
  const [pollStatus, setPollStatus] = import_react57.useState({ state: "idle", lastFound: null, lastAdded: null, lastAt: null, filterDesc: "" });
72115
72203
  function appendLog(text, color) {
72116
72204
  setLogs((prev) => [...prev, { id: nextId(), text, color }]);
@@ -72120,7 +72208,8 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72120
72208
  let cancelled = false;
72121
72209
  async function init2() {
72122
72210
  const cfgPath = await ensureRalphyConfig(projectRoot);
72123
- const cfg = await loadRalphyConfig(projectRoot);
72211
+ const cfg2 = await loadRalphyConfig(projectRoot);
72212
+ cfgRef.current = cfg2;
72124
72213
  appendLog(`agent mode v${VERSION} \u2014 config: ${cfgPath}`, "gray");
72125
72214
  const apiKey = process.env["LINEAR_API_KEY"];
72126
72215
  if (!apiKey) {
@@ -72130,24 +72219,26 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72130
72219
  }
72131
72220
  const { coord: coord2, filterDesc, concurrency, pollInterval } = buildAgentCoordinator({
72132
72221
  args,
72133
- cfg,
72222
+ cfg: cfg2,
72134
72223
  projectRoot,
72135
72224
  statesDir,
72136
72225
  tasksDir,
72137
72226
  apiKey,
72138
72227
  onLog: appendLog,
72139
72228
  onWorkersChanged: () => setTick((t) => t + 1),
72140
- onWorkerStarted: (changeName, dir, logFile) => {
72229
+ onWorkerStarted: (changeName, dir, logFile, changeDir) => {
72141
72230
  workerMetaRef.current.set(changeName, {
72142
72231
  startedAt: Date.now(),
72143
72232
  statesDir: dir,
72144
72233
  logFile,
72234
+ changeDir,
72145
72235
  iter: 0,
72146
72236
  phase: "working",
72147
72237
  phaseDetail: "",
72148
72238
  phaseStartedAt: Date.now(),
72239
+ currentTask: null,
72240
+ prUrl: null,
72149
72241
  currentCmd: null,
72150
- lastCmd: null,
72151
72242
  tail: []
72152
72243
  });
72153
72244
  },
@@ -72168,8 +72259,8 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72168
72259
  if (!m)
72169
72260
  return;
72170
72261
  m.tail.push(line);
72171
- if (m.tail.length > TAIL_MAX_LINES)
72172
- m.tail.splice(0, m.tail.length - TAIL_MAX_LINES);
72262
+ if (m.tail.length > TAIL_BUFFER_SIZE)
72263
+ m.tail.splice(0, m.tail.length - TAIL_BUFFER_SIZE);
72173
72264
  },
72174
72265
  onWorkerCmd: (changeName, cmd, state, durationMs, ok) => {
72175
72266
  const m = workerMetaRef.current.get(changeName);
@@ -72179,11 +72270,28 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72179
72270
  m.currentCmd = { argv: cmd, startedAt: Date.now() };
72180
72271
  } else {
72181
72272
  m.currentCmd = null;
72182
- m.lastCmd = { argv: cmd, durationMs: durationMs ?? 0, ok: ok ?? true };
72183
72273
  }
72274
+ },
72275
+ onWorkerPr: (changeName, prUrl) => {
72276
+ const m = workerMetaRef.current.get(changeName);
72277
+ if (m)
72278
+ m.prUrl = prUrl;
72184
72279
  }
72185
72280
  });
72186
- appendLog(`concurrency=${concurrency} pollInterval=${pollInterval}s`, "gray");
72281
+ appendLog(` concurrency: ${concurrency} \xB7 poll: ${pollInterval}s \xB7 ${cfg2.engine}/${cfg2.model}`, "gray");
72282
+ const feats = [];
72283
+ if (cfg2.createPrOnSuccess)
72284
+ feats.push("createPR");
72285
+ if (cfg2.fixCiOnFailure)
72286
+ feats.push("fixCI");
72287
+ if (cfg2.useWorktree)
72288
+ feats.push("worktree");
72289
+ if (cfg2.maxIterationsPerTask > 0)
72290
+ feats.push(`maxIter=${cfg2.maxIterationsPerTask}`);
72291
+ if (cfg2.maxCostUsdPerTask > 0)
72292
+ feats.push(`maxCost=$${cfg2.maxCostUsdPerTask}`);
72293
+ if (feats.length)
72294
+ appendLog(` features: ${feats.join(", ")}`, "gray");
72187
72295
  coordRef.current = coord2;
72188
72296
  await coord2.init();
72189
72297
  const tick = async () => {
@@ -72242,6 +72350,16 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72242
72350
  meta.iter = json.iteration ?? meta.iter;
72243
72351
  }
72244
72352
  } catch {}
72353
+ if (meta.changeDir) {
72354
+ try {
72355
+ const tasksFile = Bun.file(join16(meta.changeDir, "tasks.md"));
72356
+ if (await tasksFile.exists()) {
72357
+ const text = await tasksFile.text();
72358
+ const match = text.match(/^- \[ \] (.+)$/m);
72359
+ meta.currentTask = match?.[1]?.trim() ?? null;
72360
+ }
72361
+ } catch {}
72362
+ }
72245
72363
  }
72246
72364
  if (!cancelled)
72247
72365
  setClock((c) => c + 1);
@@ -72253,9 +72371,12 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72253
72371
  };
72254
72372
  }, []);
72255
72373
  const coord = coordRef.current;
72374
+ const cfg = cfgRef.current;
72256
72375
  const spinnerFrame = SPINNER_FRAMES[clock % SPINNER_FRAMES.length];
72257
72376
  const now2 = Date.now();
72258
72377
  const secsToNextPoll = nextPollAtRef.current ? Math.max(0, Math.ceil((nextPollAtRef.current - now2) / 1000)) : null;
72378
+ const activeCount = coord?.activeCount ?? 0;
72379
+ const tailLines = displayTailLines(activeCount);
72259
72380
  return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
72260
72381
  flexDirection: "column",
72261
72382
  children: [
@@ -72280,14 +72401,25 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72280
72401
  pollStatus.state === "polling" ? `polling Linear (${pollStatus.filterDesc})` : pollStatus.lastAt !== null ? `last poll: ${pollStatus.lastFound} open, ${pollStatus.lastAdded} new${secsToNextPoll !== null ? ` \xB7 next in ${secsToNextPoll}s` : ""}` : "starting\u2026"
72281
72402
  ]
72282
72403
  }, undefined, true, undefined, this),
72283
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72284
- dimColor: true,
72404
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
72285
72405
  children: [
72286
- " ",
72287
- "workers active: ",
72288
- coord?.activeCount ?? 0,
72289
- " \xB7 queued: ",
72290
- coord?.queuedCount ?? 0
72406
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72407
+ dimColor: true,
72408
+ children: [
72409
+ " ",
72410
+ "workers active: ",
72411
+ activeCount,
72412
+ " \xB7 queued: ",
72413
+ coord?.queuedCount ?? 0
72414
+ ]
72415
+ }, undefined, true, undefined, this),
72416
+ cfg && pollStatus.filterDesc && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72417
+ dimColor: true,
72418
+ children: [
72419
+ " ",
72420
+ settingsSummary(cfg, pollStatus.filterDesc)
72421
+ ]
72422
+ }, undefined, true, undefined, this)
72291
72423
  ]
72292
72424
  }, undefined, true, undefined, this),
72293
72425
  coord?.activeWorkers.map((w) => {
@@ -72300,32 +72432,122 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72300
72432
  const cmd = meta?.currentCmd;
72301
72433
  const cmdElapsed = cmd ? fmtElapsed(now2 - cmd.startedAt) : null;
72302
72434
  const tail2 = meta?.tail ?? [];
72435
+ const prUrl = meta?.prUrl ?? null;
72436
+ const currentTask = meta?.currentTask ?? null;
72437
+ const pBadge = priorityBadge(w.issue.priority);
72438
+ const mBadge = modeBadge(w.mode);
72439
+ const issueTitle = trunc(w.issue.title, 52);
72440
+ const pColor = phaseColor(phase);
72303
72441
  return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
72304
72442
  flexDirection: "column",
72443
+ marginTop: 1,
72305
72444
  children: [
72445
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
72446
+ children: [
72447
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72448
+ children: " "
72449
+ }, undefined, false, undefined, this),
72450
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72451
+ children: [
72452
+ spinnerFrame,
72453
+ " "
72454
+ ]
72455
+ }, undefined, true, undefined, this),
72456
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72457
+ color: pBadge.color,
72458
+ children: pBadge.text
72459
+ }, undefined, false, undefined, this),
72460
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72461
+ children: " "
72462
+ }, undefined, false, undefined, this),
72463
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72464
+ color: "cyan",
72465
+ bold: true,
72466
+ children: w.issueIdentifier
72467
+ }, undefined, false, undefined, this),
72468
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72469
+ dimColor: true,
72470
+ children: " \xB7 "
72471
+ }, undefined, false, undefined, this),
72472
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72473
+ children: issueTitle
72474
+ }, undefined, false, undefined, this),
72475
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72476
+ dimColor: true,
72477
+ children: " "
72478
+ }, undefined, false, undefined, this),
72479
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72480
+ color: mBadge.color,
72481
+ children: [
72482
+ "[",
72483
+ mBadge.text,
72484
+ "]"
72485
+ ]
72486
+ }, undefined, true, undefined, this),
72487
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72488
+ dimColor: true,
72489
+ children: [
72490
+ " ",
72491
+ elapsed,
72492
+ " \xB7 iter ",
72493
+ iter
72494
+ ]
72495
+ }, undefined, true, undefined, this)
72496
+ ]
72497
+ }, undefined, true, undefined, this),
72306
72498
  /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72307
- color: "cyan",
72499
+ dimColor: true,
72308
72500
  children: [
72309
- " ",
72310
- spinnerFrame,
72311
- " ",
72312
- w.issueIdentifier,
72313
- " (",
72314
- w.changeName,
72315
- ") \xB7 iter ",
72316
- iter,
72317
- " \xB7 ",
72318
- elapsed
72501
+ " \u2197 ",
72502
+ w.issue.url
72503
+ ]
72504
+ }, undefined, true, undefined, this),
72505
+ currentTask && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
72506
+ children: [
72507
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72508
+ dimColor: true,
72509
+ children: " \u25B6 "
72510
+ }, undefined, false, undefined, this),
72511
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72512
+ color: "white",
72513
+ children: trunc(currentTask, 90)
72514
+ }, undefined, false, undefined, this)
72515
+ ]
72516
+ }, undefined, true, undefined, this),
72517
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
72518
+ children: [
72519
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72520
+ dimColor: true,
72521
+ children: " phase: "
72522
+ }, undefined, false, undefined, this),
72523
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72524
+ color: pColor,
72525
+ children: [
72526
+ phase,
72527
+ phaseDetail
72528
+ ]
72529
+ }, undefined, true, undefined, this),
72530
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72531
+ dimColor: true,
72532
+ children: [
72533
+ " \xB7 ",
72534
+ phaseElapsed
72535
+ ]
72536
+ }, undefined, true, undefined, this)
72537
+ ]
72538
+ }, undefined, true, undefined, this),
72539
+ prUrl && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72540
+ dimColor: true,
72541
+ children: [
72542
+ " \u2197 pr: ",
72543
+ prUrl
72319
72544
  ]
72320
72545
  }, undefined, true, undefined, this),
72321
72546
  /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72322
72547
  dimColor: true,
72323
72548
  children: [
72324
- " phase: ",
72325
- phase,
72326
- phaseDetail,
72327
- " \xB7 ",
72328
- phaseElapsed
72549
+ " log: ",
72550
+ meta?.logFile ?? "\u2013"
72329
72551
  ]
72330
72552
  }, undefined, true, undefined, this),
72331
72553
  cmd && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
@@ -72337,7 +72559,7 @@ function AgentMode({ args, projectRoot, statesDir, tasksDir }) {
72337
72559
  cmdElapsed
72338
72560
  ]
72339
72561
  }, undefined, true, undefined, this),
72340
- tail2.map((line, i) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72562
+ tail2.slice(-tailLines).map((line, i) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
72341
72563
  dimColor: true,
72342
72564
  children: [
72343
72565
  " \u2502 ",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neriros/ralphy",
3
- "version": "2.13.4",
3
+ "version": "2.13.5",
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",