baro-ai 0.23.6 → 0.25.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.mjs CHANGED
@@ -8049,11 +8049,13 @@ function normalizePrd(input, source) {
8049
8049
  const branchName = typeof input.branchName === "string" ? input.branchName : "";
8050
8050
  const description = typeof input.description === "string" ? input.description : "";
8051
8051
  const stories = Array.isArray(input.userStories) ? input.userStories : [];
8052
+ const decisionDocument = typeof input.decisionDocument === "string" && input.decisionDocument.trim().length > 0 ? input.decisionDocument : void 0;
8052
8053
  return {
8053
8054
  project,
8054
8055
  branchName,
8055
8056
  description,
8056
- userStories: stories.map((s, i) => normalizeStory(s, i, source))
8057
+ userStories: stories.map((s, i) => normalizeStory(s, i, source)),
8058
+ decisionDocument
8057
8059
  };
8058
8060
  }
8059
8061
  function normalizeStory(input, index, source) {
@@ -8794,6 +8796,12 @@ var Conductor = class extends Participant {
8794
8796
  spawnQueue = [];
8795
8797
  /** Stories currently in flight in the active level. */
8796
8798
  inFlight = /* @__PURE__ */ new Set();
8799
+ /**
8800
+ * Timer handle when we're deliberately spacing out intra-level
8801
+ * spawns. Re-entering `fillSpawnSlots` while this is set is a
8802
+ * no-op; the timer callback resumes pumping.
8803
+ */
8804
+ pendingNextSpawn = null;
8797
8805
  /** Resolved when the run terminates, exposed for callers that need it. */
8798
8806
  done;
8799
8807
  resolveDone;
@@ -8803,8 +8811,12 @@ var Conductor = class extends Participant {
8803
8811
  parallel: 0,
8804
8812
  timeoutSecs: 600,
8805
8813
  defaultModel: "sonnet",
8814
+ intraLevelDelaySecs: 10,
8806
8815
  ...opts
8807
8816
  };
8817
+ if (this.opts.intraLevelDelaySecs == null) {
8818
+ this.opts.intraLevelDelaySecs = 10;
8819
+ }
8808
8820
  this.done = new Promise((resolve2) => {
8809
8821
  this.resolveDone = resolve2;
8810
8822
  });
@@ -8950,10 +8962,25 @@ var Conductor = class extends Participant {
8950
8962
  }
8951
8963
  async fillSpawnSlots() {
8952
8964
  if (!this.currentLevel) return;
8965
+ if (this.pendingNextSpawn) return;
8953
8966
  const cap = this.opts.parallel > 0 ? this.opts.parallel : Number.MAX_SAFE_INTEGER;
8967
+ const delaySecs = this.opts.intraLevelDelaySecs ?? 0;
8954
8968
  while (this.spawnQueue.length > 0 && this.inFlight.size < cap) {
8955
8969
  const story = this.spawnQueue.shift();
8956
8970
  await this.requestStorySpawn(story);
8971
+ if (this.spawnQueue.length > 0 && this.inFlight.size < cap && delaySecs > 0) {
8972
+ this.pendingNextSpawn = setTimeout(() => {
8973
+ this.pendingNextSpawn = null;
8974
+ if (this.phase === "done") return;
8975
+ this.fillSpawnSlots().catch((err) => {
8976
+ process.stderr.write(
8977
+ `[conductor] fillSpawnSlots resume failed: ${err?.stack ?? String(err)}
8978
+ `
8979
+ );
8980
+ });
8981
+ }, delaySecs * 1e3);
8982
+ return;
8983
+ }
8957
8984
  }
8958
8985
  }
8959
8986
  async requestStorySpawn(story) {
@@ -9085,13 +9112,32 @@ ${prompt}`;
9085
9112
  }
9086
9113
  resolvePrompt(story) {
9087
9114
  const candidatePath = this.opts.promptTemplatePath ?? join(this.opts.cwd, "prompt.md");
9115
+ let prompt;
9088
9116
  if (existsSync(candidatePath)) {
9089
9117
  const tpl = readFileSyncSafe(candidatePath);
9090
- if (tpl) {
9091
- return applyTemplate(tpl, story);
9092
- }
9093
- }
9094
- return buildDefaultStoryPrompt(story);
9118
+ prompt = tpl ? applyTemplate(tpl, story) : buildDefaultStoryPrompt(story);
9119
+ } else {
9120
+ prompt = buildDefaultStoryPrompt(story);
9121
+ }
9122
+ const doc = this.prd?.decisionDocument;
9123
+ if (doc && doc.trim().length > 0) {
9124
+ const header = [
9125
+ "## Design spec (authoritative \u2014 already decided)",
9126
+ "",
9127
+ "The Architect made these decisions before any story started.",
9128
+ "Treat them as fixed: use these exact file paths, names,",
9129
+ "schemas, API shapes, and dependency choices. Do NOT",
9130
+ "improvise alternatives \u2014 your siblings are working from",
9131
+ "the same spec and divergence breaks the build.",
9132
+ "",
9133
+ doc.trim(),
9134
+ "",
9135
+ "---",
9136
+ ""
9137
+ ].join("\n");
9138
+ prompt = header + prompt;
9139
+ }
9140
+ return prompt;
9095
9141
  }
9096
9142
  emit(item) {
9097
9143
  this.envRef?.deliverContextItem(this, item);
@@ -9785,15 +9831,21 @@ var EXPLORATION_TOOLS = /* @__PURE__ */ new Set([
9785
9831
  "WebFetch",
9786
9832
  "WebSearch"
9787
9833
  ]);
9834
+ var BROADCAST_TOOLS = /* @__PURE__ */ new Set(["Read", "Grep", "Glob", "LSP"]);
9788
9835
  var Librarian = class extends Participant {
9789
9836
  opts;
9790
9837
  pending = /* @__PURE__ */ new Map();
9791
9838
  knowledge = [];
9839
+ // Mid-flight bookkeeping
9840
+ inFlight = /* @__PURE__ */ new Set();
9841
+ storyHints = /* @__PURE__ */ new Map();
9842
+ broadcastBytes = /* @__PURE__ */ new Map();
9792
9843
  constructor(opts = {}) {
9793
9844
  super();
9794
9845
  this.opts = {
9795
9846
  maxContentChars: opts.maxContentChars ?? 4e3,
9796
- maxInjectedChars: opts.maxInjectedChars ?? 8e3
9847
+ maxInjectedChars: opts.maxInjectedChars ?? 2e4,
9848
+ maxBroadcastBytesPerStory: opts.maxBroadcastBytesPerStory ?? 5e4
9797
9849
  };
9798
9850
  }
9799
9851
  /** All indexed knowledge entries, in order discovered. */
@@ -9834,9 +9886,11 @@ var Librarian = class extends Participant {
9834
9886
  }
9835
9887
  if (lines.length === 0) return null;
9836
9888
  return [
9837
- "[librarian] Findings from prior agents in this run that may save",
9838
- "you time. Do not re-fetch what's already here unless you suspect",
9839
- "the file changed.",
9889
+ "## Codebase context (current as of this run)",
9890
+ "",
9891
+ "The following file contents and discovery results are authoritative",
9892
+ "and up-to-date. Do not re-read or re-search unless you have specific",
9893
+ "reason to suspect a file has changed since these were captured.",
9840
9894
  "",
9841
9895
  ...lines
9842
9896
  ].join("\n");
@@ -9850,6 +9904,18 @@ var Librarian = class extends Participant {
9850
9904
  this.completeWithOutput(source, item);
9851
9905
  return;
9852
9906
  }
9907
+ if (item instanceof StorySpawnRequestItem) {
9908
+ this.storyHints.set(item.storyId, tokenizeHints(item.prompt));
9909
+ return;
9910
+ }
9911
+ if (item instanceof StorySpawnedItem) {
9912
+ this.inFlight.add(item.storyId);
9913
+ return;
9914
+ }
9915
+ if (item instanceof StoryResultItem) {
9916
+ this.inFlight.delete(item.storyId);
9917
+ return;
9918
+ }
9853
9919
  }
9854
9920
  recordPending(source, item) {
9855
9921
  if (!EXPLORATION_TOOLS.has(item.name)) return;
@@ -9896,6 +9962,51 @@ var Librarian = class extends Participant {
9896
9962
  )
9897
9963
  );
9898
9964
  }
9965
+ if (BROADCAST_TOOLS.has(entry.tool)) {
9966
+ this.broadcastFinding(entry);
9967
+ }
9968
+ }
9969
+ broadcastFinding(finding) {
9970
+ if (this.inFlight.size === 0) return;
9971
+ const envs = this.getEnvironments();
9972
+ if (envs.length === 0) return;
9973
+ const findingTokens = new Set(
9974
+ [...finding.tags, finding.summary].join(" ").toLowerCase().split(/[^a-z0-9_/.\\-]+/).filter((t) => t.length >= 3)
9975
+ );
9976
+ const block = formatEntry(finding);
9977
+ const text = [
9978
+ "## Just-in-time codebase context",
9979
+ "",
9980
+ `Another agent in this run (${finding.sourceAgentId}) just`,
9981
+ "discovered the following. It is authoritative and current;",
9982
+ "use it directly without re-fetching.",
9983
+ "",
9984
+ block
9985
+ ].join("\n");
9986
+ const bytes = text.length;
9987
+ for (const recipientId of this.inFlight) {
9988
+ if (recipientId === finding.sourceAgentId) continue;
9989
+ const recipientHints = this.storyHints.get(recipientId) ?? [];
9990
+ if (recipientHints.length > 0) {
9991
+ const overlap = recipientHints.some(
9992
+ (h) => findingTokens.has(h.toLowerCase())
9993
+ );
9994
+ if (!overlap) continue;
9995
+ }
9996
+ const already = this.broadcastBytes.get(recipientId) ?? 0;
9997
+ if (already + bytes > this.opts.maxBroadcastBytesPerStory) continue;
9998
+ this.broadcastBytes.set(recipientId, already + bytes);
9999
+ for (const env of envs) {
10000
+ env.deliverContextItem(
10001
+ this,
10002
+ new AgentTargetedMessageItem(recipientId, text, {
10003
+ source: "librarian",
10004
+ finding: finding.summary,
10005
+ from_agent: finding.sourceAgentId
10006
+ })
10007
+ );
10008
+ }
10009
+ }
9899
10010
  }
9900
10011
  };
9901
10012
  function describeCall(tool, args) {
@@ -9948,6 +10059,9 @@ function formatEntry(k) {
9948
10059
  ""
9949
10060
  ].join("\n");
9950
10061
  }
10062
+ function tokenizeHints(prompt) {
10063
+ return prompt.toLowerCase().split(/[^a-z0-9_/.\-]+/).filter((t) => t.length >= 3);
10064
+ }
9951
10065
 
9952
10066
  // ../baro-orchestrator/src/participants/operator.ts
9953
10067
  var Operator = class extends Participant {
@@ -10412,6 +10526,7 @@ async function orchestrate(config) {
10412
10526
  timeoutSecs: config.timeoutSecs ?? 600,
10413
10527
  overrideModel: config.overrideModel ?? void 0,
10414
10528
  defaultModel: config.defaultModel ?? "opus",
10529
+ intraLevelDelaySecs: config.intraLevelDelaySecs,
10415
10530
  onRunStart: useGit ? async (prd) => {
10416
10531
  baseSha = await getHeadSha(config.cwd);
10417
10532
  if (prd.branchName) {
@@ -10750,6 +10865,12 @@ function parseArgs(argv) {
10750
10865
  case "--surgeon-model":
10751
10866
  args.surgeonModel = required(argv, ++i, "--surgeon-model");
10752
10867
  break;
10868
+ case "--intra-level-delay":
10869
+ args.intraLevelDelaySecs = parseInt(
10870
+ required(argv, ++i, "--intra-level-delay"),
10871
+ 10
10872
+ );
10873
+ break;
10753
10874
  default:
10754
10875
  process.stderr.write(`[cli] unknown flag: ${a}
10755
10876
  `);
@@ -10791,6 +10912,7 @@ function printHelp() {
10791
10912
  " --with-surgeon Enable Surgeon (adaptive DAG mutation)",
10792
10913
  " --surgeon-use-llm Use LLM evaluation in Surgeon (default: deterministic)",
10793
10914
  " --surgeon-model <name> Model for Surgeon LLM (default: opus)",
10915
+ " --intra-level-delay <secs> Stagger story spawns within a level (default: 10, 0 disables)",
10794
10916
  " -h, --help Show this message",
10795
10917
  ""
10796
10918
  ].join("\n")
@@ -10825,7 +10947,8 @@ async function main() {
10825
10947
  withSentry: args.noSentry ? false : void 0,
10826
10948
  withSurgeon: args.withSurgeon,
10827
10949
  surgeonUseLlm: args.surgeonUseLlm,
10828
- surgeonModel: args.surgeonModel
10950
+ surgeonModel: args.surgeonModel,
10951
+ intraLevelDelaySecs: args.intraLevelDelaySecs
10829
10952
  };
10830
10953
  process.stderr.write(
10831
10954
  `[cli] starting orchestrator: prd=${prdPath} cwd=${cwd} parallel=${args.parallel} timeout=${args.timeout}s