baro-ai 0.42.2 → 0.43.1

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
@@ -10752,6 +10752,226 @@ function extractVerdictJson(text) {
10752
10752
  throw new Error(`unbalanced JSON object in critic response: ${trimmed.slice(0, 200)}`);
10753
10753
  }
10754
10754
 
10755
+ // ../baro-orchestrator/src/codex-one-shot.ts
10756
+ import { spawn } from "child_process";
10757
+ async function runCodexOneShot(opts) {
10758
+ const label = opts.label ?? "codex";
10759
+ const args = ["exec", "--json"];
10760
+ if (opts.skipGitRepoCheck) args.push("--skip-git-repo-check");
10761
+ if (opts.bypassSandbox !== false) {
10762
+ args.push("--dangerously-bypass-approvals-and-sandbox");
10763
+ }
10764
+ if (opts.model) args.push("--model", opts.model);
10765
+ args.push(opts.prompt);
10766
+ const timeoutMs = opts.timeoutMs ?? 6e5;
10767
+ return await new Promise((resolve4, reject) => {
10768
+ let proc;
10769
+ try {
10770
+ proc = spawn(opts.codexBin ?? "codex", args, {
10771
+ cwd: opts.cwd,
10772
+ stdio: ["ignore", "pipe", "pipe"]
10773
+ });
10774
+ } catch (e) {
10775
+ reject(e instanceof Error ? e : new Error(String(e)));
10776
+ return;
10777
+ }
10778
+ let agentMessage = "";
10779
+ let stdoutBuffer = "";
10780
+ const eventTypesSeen = [];
10781
+ const itemTypesSeen = [];
10782
+ let timedOut = false;
10783
+ const startedAt = Date.now();
10784
+ const timer = setTimeout(() => {
10785
+ timedOut = true;
10786
+ try {
10787
+ proc.kill("SIGTERM");
10788
+ } catch {
10789
+ }
10790
+ }, timeoutMs);
10791
+ proc.stdout.setEncoding("utf8");
10792
+ proc.stdout.on("data", (chunk) => {
10793
+ stdoutBuffer += chunk;
10794
+ let nl;
10795
+ while ((nl = stdoutBuffer.indexOf("\n")) >= 0) {
10796
+ const line = stdoutBuffer.slice(0, nl).trim();
10797
+ stdoutBuffer = stdoutBuffer.slice(nl + 1);
10798
+ if (!line) continue;
10799
+ let event;
10800
+ try {
10801
+ event = JSON.parse(line);
10802
+ } catch {
10803
+ continue;
10804
+ }
10805
+ const type = typeof event.type === "string" ? event.type : "";
10806
+ if (type) eventTypesSeen.push(type);
10807
+ if (type === "turn.completed") {
10808
+ const usage = event.usage;
10809
+ if (usage) {
10810
+ process.stderr.write(
10811
+ `[${label}] usage: in=${usage.input_tokens ?? 0} out=${usage.output_tokens ?? 0}
10812
+ `
10813
+ );
10814
+ }
10815
+ continue;
10816
+ }
10817
+ if (type === "item.completed") {
10818
+ const item = event.item;
10819
+ if (item) {
10820
+ const innerType = typeof item.type === "string" ? item.type : "?";
10821
+ itemTypesSeen.push(innerType);
10822
+ if (item.type === "agent_message" && typeof item.text === "string") {
10823
+ agentMessage = agentMessage ? `${agentMessage}
10824
+ ${item.text}` : item.text;
10825
+ } else if (innerType === "command_execution") {
10826
+ const cmd = typeof item.command === "string" ? item.command.slice(0, 120) : "?";
10827
+ process.stderr.write(`[${label}] $ ${cmd}
10828
+ `);
10829
+ }
10830
+ }
10831
+ continue;
10832
+ }
10833
+ }
10834
+ });
10835
+ proc.stderr.setEncoding("utf8");
10836
+ proc.stderr.on("data", (chunk) => {
10837
+ const trimmed = chunk.trimEnd();
10838
+ if (trimmed) {
10839
+ process.stderr.write(`[${label}/stderr] ${trimmed}
10840
+ `);
10841
+ }
10842
+ });
10843
+ proc.on("error", (err) => {
10844
+ clearTimeout(timer);
10845
+ reject(err);
10846
+ });
10847
+ proc.on("exit", (code, signal) => {
10848
+ clearTimeout(timer);
10849
+ const elapsedMs = Date.now() - startedAt;
10850
+ if (agentMessage.trim()) {
10851
+ resolve4(agentMessage);
10852
+ return;
10853
+ }
10854
+ const ctx = [
10855
+ `elapsed=${elapsedMs}ms`,
10856
+ `exit=${code}`,
10857
+ signal ? `signal=${signal}` : null,
10858
+ timedOut ? `timedOut=true (cap=${timeoutMs}ms)` : null,
10859
+ `events=${eventTypesSeen.length}`,
10860
+ `items=${itemTypesSeen.length}`,
10861
+ eventTypesSeen.length > 0 ? `event_types=[${[...new Set(eventTypesSeen)].join(",")}]` : null,
10862
+ itemTypesSeen.length > 0 ? `item_types=[${[...new Set(itemTypesSeen)].join(",")}]` : null
10863
+ ].filter((x) => x !== null).join(" ");
10864
+ reject(
10865
+ new Error(
10866
+ `runCodexOneShot: codex produced no agent_message (${ctx})`
10867
+ )
10868
+ );
10869
+ });
10870
+ });
10871
+ }
10872
+
10873
+ // ../baro-orchestrator/src/participants/critic-codex.ts
10874
+ var CriticCodex = class extends BaseObserver {
10875
+ opts;
10876
+ emissions = /* @__PURE__ */ new Map();
10877
+ turnCount = /* @__PURE__ */ new Map();
10878
+ pending = /* @__PURE__ */ new Set();
10879
+ constructor(opts) {
10880
+ super();
10881
+ this.opts = {
10882
+ maxEmissionsPerAgent: opts.maxEmissionsPerAgent ?? 2,
10883
+ model: opts.model,
10884
+ codexBin: opts.codexBin ?? "codex",
10885
+ timeoutMs: opts.timeoutMs ?? 18e4,
10886
+ targets: opts.targets
10887
+ };
10888
+ }
10889
+ /** Resolves once every in-flight evaluation has emitted its CritiqueItem. */
10890
+ async idle() {
10891
+ await Promise.allSettled([...this.pending]);
10892
+ }
10893
+ async onExternalEvent(_source, event) {
10894
+ if (!AgentResult.is(event)) return;
10895
+ const { agentId, isError, resultText } = event.data;
10896
+ if (isError || !resultText) return;
10897
+ const criteria = this.opts.targets.get(agentId);
10898
+ if (!criteria || criteria.length === 0) return;
10899
+ const turn = (this.turnCount.get(agentId) ?? 0) + 1;
10900
+ this.turnCount.set(agentId, turn);
10901
+ const work = (async () => {
10902
+ const { verdict, reasoning, violatedCriteria } = await this.evaluate(
10903
+ resultText,
10904
+ criteria
10905
+ );
10906
+ const critiqueEvent = Critique.create({
10907
+ agentId,
10908
+ verdict,
10909
+ reasoning,
10910
+ violatedCriteria,
10911
+ turn,
10912
+ modelUsed: this.opts.model ?? "codex-default"
10913
+ });
10914
+ for (const env of this.getEnvironments()) {
10915
+ env.deliverSemanticEvent(this, critiqueEvent);
10916
+ }
10917
+ if (verdict === "fail") {
10918
+ const emitted = this.emissions.get(agentId) ?? 0;
10919
+ if (emitted < this.opts.maxEmissionsPerAgent) {
10920
+ this.emissions.set(agentId, emitted + 1);
10921
+ const text = buildCorrectiveMessage(reasoning, violatedCriteria);
10922
+ const msg = AgentTargetedMessage.create({
10923
+ recipientId: agentId,
10924
+ text,
10925
+ metadata: {
10926
+ criticTurn: turn,
10927
+ emissionIndex: emitted + 1
10928
+ }
10929
+ });
10930
+ for (const env of this.getEnvironments()) {
10931
+ env.deliverSemanticEvent(this, msg);
10932
+ }
10933
+ }
10934
+ }
10935
+ })();
10936
+ this.pending.add(work);
10937
+ work.finally(() => {
10938
+ this.pending.delete(work);
10939
+ });
10940
+ await work;
10941
+ }
10942
+ async evaluate(resultText, criteria) {
10943
+ const userPrompt = buildEvalPrompt(criteria, resultText);
10944
+ const prompt = `${VERDICT_SYSTEM_PROMPT}
10945
+
10946
+ ${userPrompt}`;
10947
+ try {
10948
+ const text = await runCodexOneShot({
10949
+ prompt,
10950
+ cwd: process.cwd(),
10951
+ skipGitRepoCheck: true,
10952
+ bypassSandbox: true,
10953
+ model: this.opts.model,
10954
+ codexBin: this.opts.codexBin,
10955
+ timeoutMs: this.opts.timeoutMs,
10956
+ label: "codex-critic"
10957
+ });
10958
+ const verdictJson = extractVerdictJson(text.trim());
10959
+ const parsed = JSON.parse(verdictJson);
10960
+ return {
10961
+ verdict: parsed.verdict === "pass" ? "pass" : "fail",
10962
+ reasoning: parsed.reasoning ?? "",
10963
+ violatedCriteria: Array.isArray(parsed.violated_criteria) ? parsed.violated_criteria : []
10964
+ };
10965
+ } catch (err) {
10966
+ return {
10967
+ verdict: "fail",
10968
+ reasoning: `CriticCodex LLM call failed: ${String(err?.message ?? err)}`,
10969
+ violatedCriteria: ["[critic error \u2014 could not evaluate]"]
10970
+ };
10971
+ }
10972
+ }
10973
+ };
10974
+
10755
10975
  // ../baro-orchestrator/src/planning/openai-runtime.ts
10756
10976
  async function runInferenceRound(_context, _model) {
10757
10977
  throw new Error(
@@ -11769,7 +11989,7 @@ function extractPath(item) {
11769
11989
  import { setTimeout as setTimeoutPromise } from "timers/promises";
11770
11990
 
11771
11991
  // ../baro-orchestrator/src/participants/codex-cli-participant.ts
11772
- import { spawn } from "child_process";
11992
+ import { spawn as spawn2 } from "child_process";
11773
11993
 
11774
11994
  // ../baro-orchestrator/src/codex-stream-mapper.ts
11775
11995
  function mapCodexEvent(agentId, event) {
@@ -11991,7 +12211,7 @@ var CodexCliParticipant = class _CodexCliParticipant extends BaseObserver {
11991
12211
  const args = this.buildArgs();
11992
12212
  let proc;
11993
12213
  try {
11994
- proc = spawn(this.options.codexBin, args, {
12214
+ proc = spawn2(this.options.codexBin, args, {
11995
12215
  cwd: this.options.cwd,
11996
12216
  stdio: ["ignore", "pipe", "pipe"]
11997
12217
  });
@@ -13136,7 +13356,7 @@ function sleep2(ms) {
13136
13356
  import { setTimeout as setTimeoutPromise2 } from "timers/promises";
13137
13357
 
13138
13358
  // ../baro-orchestrator/src/participants/claude-cli-participant.ts
13139
- import { spawn as spawn2 } from "child_process";
13359
+ import { spawn as spawn3 } from "child_process";
13140
13360
 
13141
13361
  // ../baro-orchestrator/src/stream-json-mapper.ts
13142
13362
  function mapClaudeEvent(agentId, event) {
@@ -13309,7 +13529,7 @@ var ClaudeCliParticipant = class _ClaudeCliParticipant extends BaseObserver {
13309
13529
  const args = this.buildArgs();
13310
13530
  let proc;
13311
13531
  try {
13312
- proc = spawn2(this.options.claudeBin, args, {
13532
+ proc = spawn3(this.options.claudeBin, args, {
13313
13533
  cwd: this.options.cwd,
13314
13534
  stdio: ["pipe", "pipe", "pipe"]
13315
13535
  });
@@ -14053,6 +14273,86 @@ function surgeonDeterministicReplan(failure) {
14053
14273
  };
14054
14274
  }
14055
14275
 
14276
+ // ../baro-orchestrator/src/participants/surgeon-codex.ts
14277
+ var SurgeonCodex = class extends BaseObserver {
14278
+ opts;
14279
+ replansEmitted = 0;
14280
+ pending = /* @__PURE__ */ new Set();
14281
+ constructor(opts) {
14282
+ super();
14283
+ this.opts = {
14284
+ useLlm: opts.useLlm ?? true,
14285
+ model: opts.model,
14286
+ maxReplans: opts.maxReplans ?? 10,
14287
+ codexBin: opts.codexBin ?? "codex",
14288
+ timeoutMs: opts.timeoutMs ?? 3e5,
14289
+ snapshot: opts.snapshot
14290
+ };
14291
+ }
14292
+ async idle() {
14293
+ await Promise.allSettled([...this.pending]);
14294
+ }
14295
+ async onExternalEvent(_source, event) {
14296
+ if (!StoryResult.is(event)) return;
14297
+ if (event.data.success) return;
14298
+ if (this.replansEmitted >= this.opts.maxReplans) return;
14299
+ const work = (async () => {
14300
+ const replan = this.opts.useLlm ? await this.evaluateWithLlm(event.data) : surgeonDeterministicReplan(event.data);
14301
+ if (!replan) return;
14302
+ this.replansEmitted += 1;
14303
+ for (const env of this.getEnvironments()) {
14304
+ env.deliverSemanticEvent(this, Replan.create(replan));
14305
+ }
14306
+ })();
14307
+ this.pending.add(work);
14308
+ work.finally(() => this.pending.delete(work));
14309
+ await work;
14310
+ }
14311
+ async evaluateWithLlm(failure) {
14312
+ const snap = this.opts.snapshot();
14313
+ const userPrompt = buildSurgeonPrompt(snap, failure);
14314
+ const prompt = `${SURGEON_SYSTEM_PROMPT}
14315
+
14316
+ ${userPrompt}`;
14317
+ try {
14318
+ const text = await runCodexOneShot({
14319
+ prompt,
14320
+ cwd: process.cwd(),
14321
+ skipGitRepoCheck: true,
14322
+ bypassSandbox: true,
14323
+ model: this.opts.model,
14324
+ codexBin: this.opts.codexBin,
14325
+ timeoutMs: this.opts.timeoutMs,
14326
+ label: "codex-surgeon"
14327
+ });
14328
+ const verdictText = text.trim();
14329
+ if (!verdictText) throw new Error("empty result");
14330
+ const verdictJson = extractJsonObject(verdictText);
14331
+ const parsed = JSON.parse(verdictJson);
14332
+ if (parsed.action === "abort") return null;
14333
+ const modifiedDeps = {};
14334
+ for (const m of parsed.modifiedDeps ?? []) {
14335
+ if (typeof m.id === "string" && Array.isArray(m.newDependsOn)) {
14336
+ modifiedDeps[m.id] = [...m.newDependsOn];
14337
+ }
14338
+ }
14339
+ return {
14340
+ source: "surgeon",
14341
+ reason: `${parsed.action}: ${parsed.reason ?? ""}`,
14342
+ addedStories: parsed.added ?? [],
14343
+ removedStoryIds: parsed.removed ?? [],
14344
+ modifiedDeps
14345
+ };
14346
+ } catch (err) {
14347
+ const fallback = surgeonDeterministicReplan(failure);
14348
+ return {
14349
+ ...fallback,
14350
+ reason: `${fallback.reason} (codex fallback after error: ${err?.message ?? String(err)})`
14351
+ };
14352
+ }
14353
+ }
14354
+ };
14355
+
14056
14356
  // ../baro-orchestrator/src/participants/surgeon-openai.ts
14057
14357
  function pickModel3(name) {
14058
14358
  switch (name) {
@@ -14173,7 +14473,7 @@ async function orchestrate(config) {
14173
14473
  );
14174
14474
  } else if (llm === "codex") {
14175
14475
  process.stderr.write(
14176
- "[orchestrate] llm=codex: Story phase shells out to `codex exec --json` (ChatGPT subscription path). Architect / Planner / Critic / Surgeon fall back to Claude in v1 \u2014 codex-* siblings for those phases are a v2 follow-up.\n"
14476
+ "[orchestrate] llm=codex: every LLM phase shells out to `codex exec --json` (ChatGPT subscription path). Architect / Planner / Critic / Surgeon / StoryAgent all running through Codex.\n"
14177
14477
  );
14178
14478
  } else {
14179
14479
  process.stderr.write(
@@ -14218,14 +14518,24 @@ async function orchestrate(config) {
14218
14518
  }))
14219
14519
  };
14220
14520
  };
14221
- surgeon = llm === "openai" ? new SurgeonOpenAI({
14222
- snapshot,
14223
- model: config.surgeonModel ?? "gpt-5.5"
14224
- }) : new Surgeon({
14225
- snapshot,
14226
- useLlm: config.surgeonUseLlm ?? false,
14227
- model: config.surgeonModel ?? "opus"
14228
- });
14521
+ if (llm === "openai") {
14522
+ surgeon = new SurgeonOpenAI({
14523
+ snapshot,
14524
+ model: config.surgeonModel ?? "gpt-5.5"
14525
+ });
14526
+ } else if (llm === "codex") {
14527
+ surgeon = new SurgeonCodex({
14528
+ snapshot,
14529
+ useLlm: config.surgeonUseLlm ?? true,
14530
+ model: config.surgeonModel
14531
+ });
14532
+ } else {
14533
+ surgeon = new Surgeon({
14534
+ snapshot,
14535
+ useLlm: config.surgeonUseLlm ?? false,
14536
+ model: config.surgeonModel ?? "opus"
14537
+ });
14538
+ }
14229
14539
  surgeon.join(env);
14230
14540
  }
14231
14541
  let critic = null;
@@ -14234,13 +14544,22 @@ async function orchestrate(config) {
14234
14544
  const targets = new Map(
14235
14545
  prd.userStories.filter((s) => s.acceptance && s.acceptance.length > 0).map((s) => [s.id, s.acceptance])
14236
14546
  );
14237
- critic = llm === "openai" ? new CriticOpenAI({
14238
- targets,
14239
- model: config.criticModel ?? "gpt-5.4-mini"
14240
- }) : new Critic({
14241
- targets,
14242
- model: config.criticModel ?? "haiku"
14243
- });
14547
+ if (llm === "openai") {
14548
+ critic = new CriticOpenAI({
14549
+ targets,
14550
+ model: config.criticModel ?? "gpt-5.4-mini"
14551
+ });
14552
+ } else if (llm === "codex") {
14553
+ critic = new CriticCodex({
14554
+ targets,
14555
+ model: config.criticModel
14556
+ });
14557
+ } else {
14558
+ critic = new Critic({
14559
+ targets,
14560
+ model: config.criticModel ?? "haiku"
14561
+ });
14562
+ }
14244
14563
  critic.join(env);
14245
14564
  }
14246
14565
  const finalizer = useGit ? new Finalizer({