baro-ai 0.47.6 → 0.47.7

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.mjs CHANGED
@@ -39754,6 +39754,13 @@ var Conductor = class extends BaseObserver {
39754
39754
  * is true only when this list is empty.
39755
39755
  */
39756
39756
  globalDropped = [];
39757
+ /**
39758
+ * Extra end-of-run recovery attempts, separate from each StoryAgent's own
39759
+ * retry loop. A story may exhaust its normal attempts, block the DAG, and
39760
+ * still be recoverable after sibling stories have landed more context/code.
39761
+ */
39762
+ recoveryAttempts = /* @__PURE__ */ new Map();
39763
+ maxRecoveryAttemptsPerStory = 1;
39757
39764
  totalAttempts = 0;
39758
39765
  appliedReplans = 0;
39759
39766
  currentLevel = null;
@@ -39868,6 +39875,13 @@ var Conductor = class extends BaseObserver {
39868
39875
  const levels = buildDag(runnableStories);
39869
39876
  if (levels.length === 0) {
39870
39877
  const allPassed = this.prd.userStories.every((s2) => s2.passes) && this.globalDropped.length === 0;
39878
+ if (!allPassed && this.globalFailed.length > 0) {
39879
+ const recovered = await this.tryStartRecoveryLevel(
39880
+ this.globalFailed,
39881
+ blockedStoryIds.size > 0 ? `blocked dependencies: ${[...blockedStoryIds].join(", ")}` : "terminal failed stories"
39882
+ );
39883
+ if (recovered) return;
39884
+ }
39871
39885
  const abortReason = allPassed ? null : this.globalFailed.length > 0 ? blockedStoryIds.size > 0 ? `blocked by failed dependencies: failed ${this.globalFailed.join(", ")}; blocked ${[...blockedStoryIds].join(", ")}` : `stories failed: ${this.globalFailed.join(", ")}` : null;
39872
39886
  this.terminateRun(allPassed, abortReason);
39873
39887
  return;
@@ -39919,6 +39933,7 @@ var Conductor = class extends BaseObserver {
39919
39933
  if (item.success) {
39920
39934
  this.currentLevel.passed.push(item.storyId);
39921
39935
  this.globalCompleted.push(item.storyId);
39936
+ this.removeGlobalFailed(item.storyId);
39922
39937
  if (this.prd) {
39923
39938
  this.prd = markStoryPassed(this.prd, item.storyId, item.durationSecs);
39924
39939
  savePrd(this.opts.prdPath, this.prd);
@@ -39939,7 +39954,7 @@ var Conductor = class extends BaseObserver {
39939
39954
  }
39940
39955
  } else {
39941
39956
  this.currentLevel.failed.push(item.storyId);
39942
- this.globalFailed.push(item.storyId);
39957
+ this.addGlobalFailed(item.storyId);
39943
39958
  }
39944
39959
  await this.fillSpawnSlots();
39945
39960
  if (this.currentLevel.pending.size === 0) {
@@ -40023,6 +40038,16 @@ ${prompt}`;
40023
40038
  if (this.pendingReplans.length > 0 && this.prd) {
40024
40039
  const drained = this.pendingReplans.splice(0);
40025
40040
  for (const replan of drained) {
40041
+ if (replan.removedStoryIds.length > 0 && replan.addedStories.length === 0) {
40042
+ this.emit(
40043
+ ConductorState.create({
40044
+ phase: "running_level",
40045
+ detail: `skip proposal deferred (source=${replan.source}, -${replan.removedStoryIds.length}): ${replan.reason}`,
40046
+ currentLevel: lvl.ordinal
40047
+ })
40048
+ );
40049
+ continue;
40050
+ }
40026
40051
  this.prd = applyReplan(this.prd, replan);
40027
40052
  this.appliedReplans += 1;
40028
40053
  replannedThisLevel = true;
@@ -40055,6 +40080,11 @@ ${prompt}`;
40055
40080
  const anySuccess = lvl.passed.length > 0;
40056
40081
  const totalThisLevel = lvl.passed.length + lvl.failed.length;
40057
40082
  if (!anySuccess && totalThisLevel > 0 && !replannedThisLevel) {
40083
+ const recovered = await this.tryStartRecoveryLevel(
40084
+ lvl.failed,
40085
+ "all stories in level failed"
40086
+ );
40087
+ if (recovered) return;
40058
40088
  this.terminateRun(
40059
40089
  false,
40060
40090
  "all stories in level failed; aborting remaining levels"
@@ -40128,6 +40158,71 @@ ${prompt}`;
40128
40158
  }
40129
40159
  return blocked;
40130
40160
  }
40161
+ addGlobalFailed(storyId) {
40162
+ if (!this.globalFailed.includes(storyId)) {
40163
+ this.globalFailed.push(storyId);
40164
+ }
40165
+ }
40166
+ removeGlobalFailed(storyId) {
40167
+ for (let i2 = this.globalFailed.length - 1; i2 >= 0; i2--) {
40168
+ if (this.globalFailed[i2] === storyId) {
40169
+ this.globalFailed.splice(i2, 1);
40170
+ }
40171
+ }
40172
+ }
40173
+ async tryStartRecoveryLevel(candidateIds, reason) {
40174
+ if (!this.prd) return false;
40175
+ const seen = /* @__PURE__ */ new Set();
40176
+ const stories = [];
40177
+ for (const id of candidateIds) {
40178
+ if (seen.has(id)) continue;
40179
+ seen.add(id);
40180
+ const attempts = this.recoveryAttempts.get(id) ?? 0;
40181
+ if (attempts >= this.maxRecoveryAttemptsPerStory) continue;
40182
+ const story = this.prd.userStories.find((s2) => s2.id === id);
40183
+ if (!story || story.passes) continue;
40184
+ stories.push(story);
40185
+ }
40186
+ if (stories.length === 0) return false;
40187
+ for (const story of stories) {
40188
+ this.recoveryAttempts.set(
40189
+ story.id,
40190
+ (this.recoveryAttempts.get(story.id) ?? 0) + 1
40191
+ );
40192
+ this.removeGlobalFailed(story.id);
40193
+ }
40194
+ const ordinal = (this.currentLevel?.ordinal ?? 0) + 1;
40195
+ const totalLevelsHint = ordinal;
40196
+ this.currentLevel = {
40197
+ ordinal,
40198
+ totalLevelsHint,
40199
+ storyIds: stories.map((s2) => s2.id),
40200
+ pending: new Set(stories.map((s2) => s2.id)),
40201
+ passed: [],
40202
+ failed: [],
40203
+ perStoryAttempts: /* @__PURE__ */ new Map()
40204
+ };
40205
+ this.emit(
40206
+ LevelStarted.create({
40207
+ ordinal,
40208
+ totalLevelsHint,
40209
+ storyIds: this.currentLevel.storyIds
40210
+ })
40211
+ );
40212
+ this.emit(
40213
+ ConductorState.create({
40214
+ phase: "running_level",
40215
+ detail: `auto-recovery retry for ${this.currentLevel.storyIds.join(", ")} (${reason})`,
40216
+ currentLevel: ordinal,
40217
+ totalLevels: totalLevelsHint,
40218
+ storyIds: this.currentLevel.storyIds
40219
+ })
40220
+ );
40221
+ this.phase = "running";
40222
+ this.spawnQueue.push(...stories);
40223
+ await this.fillSpawnSlots();
40224
+ return true;
40225
+ }
40131
40226
  resolvePrompt(story) {
40132
40227
  const candidatePath = this.opts.promptTemplatePath ?? join(this.opts.cwd, "prompt.md");
40133
40228
  let prompt;
@@ -40954,8 +41049,10 @@ var Finalizer = class extends BaseObserver {
40954
41049
  }
40955
41050
  async finalize(run) {
40956
41051
  if (!this.opts.createPr) return;
40957
- if (!run.success && run.completedStories.length === 0) {
40958
- this.log("[finalizer] run failed before producing any commits; skipping PR");
41052
+ if (!run.success) {
41053
+ this.log(
41054
+ `[finalizer] run did not complete successfully (${run.abortReason ?? "no reason"}); skipping PR`
41055
+ );
40959
41056
  this.emit(
40960
41057
  PrCreated.create({
40961
41058
  url: null,