baro-ai 0.42.2 → 0.43.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 +285 -30
- package/dist/cli.mjs.map +1 -1
- package/dist/run-architect.mjs +80 -3
- package/dist/run-architect.mjs.map +1 -1
- package/dist/run-planner.mjs +113 -5
- package/dist/run-planner.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -10752,6 +10752,163 @@ 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 { execFile as execFile3 } from "child_process";
|
|
10757
|
+
import { promisify as promisify3 } from "util";
|
|
10758
|
+
var execFileAsync2 = promisify3(execFile3);
|
|
10759
|
+
async function runCodexOneShot(opts) {
|
|
10760
|
+
const args = ["exec", "--json"];
|
|
10761
|
+
if (opts.skipGitRepoCheck) args.push("--skip-git-repo-check");
|
|
10762
|
+
if (opts.bypassSandbox !== false) {
|
|
10763
|
+
args.push("--dangerously-bypass-approvals-and-sandbox");
|
|
10764
|
+
}
|
|
10765
|
+
if (opts.model) args.push("--model", opts.model);
|
|
10766
|
+
args.push(opts.prompt);
|
|
10767
|
+
const { stdout } = await execFileAsync2(opts.codexBin ?? "codex", args, {
|
|
10768
|
+
cwd: opts.cwd,
|
|
10769
|
+
timeout: opts.timeoutMs ?? 18e4,
|
|
10770
|
+
maxBuffer: opts.maxBuffer ?? 16 * 1024 * 1024
|
|
10771
|
+
});
|
|
10772
|
+
let result = "";
|
|
10773
|
+
for (const rawLine of stdout.split("\n")) {
|
|
10774
|
+
const line = rawLine.trim();
|
|
10775
|
+
if (!line) continue;
|
|
10776
|
+
let event;
|
|
10777
|
+
try {
|
|
10778
|
+
event = JSON.parse(line);
|
|
10779
|
+
} catch {
|
|
10780
|
+
continue;
|
|
10781
|
+
}
|
|
10782
|
+
if (event.type === "turn.completed") {
|
|
10783
|
+
const usage = event.usage;
|
|
10784
|
+
if (usage) {
|
|
10785
|
+
process.stderr.write(
|
|
10786
|
+
`[codex] usage: in=${usage.input_tokens ?? 0} out=${usage.output_tokens ?? 0}
|
|
10787
|
+
`
|
|
10788
|
+
);
|
|
10789
|
+
}
|
|
10790
|
+
continue;
|
|
10791
|
+
}
|
|
10792
|
+
if (event.type !== "item.completed") continue;
|
|
10793
|
+
const item = event.item;
|
|
10794
|
+
if (!item) continue;
|
|
10795
|
+
if (item.type === "agent_message" && typeof item.text === "string") {
|
|
10796
|
+
result = result ? `${result}
|
|
10797
|
+
${item.text}` : item.text;
|
|
10798
|
+
}
|
|
10799
|
+
}
|
|
10800
|
+
if (!result.trim()) {
|
|
10801
|
+
throw new Error("runCodexOneShot: codex produced no agent_message");
|
|
10802
|
+
}
|
|
10803
|
+
return result;
|
|
10804
|
+
}
|
|
10805
|
+
|
|
10806
|
+
// ../baro-orchestrator/src/participants/critic-codex.ts
|
|
10807
|
+
var CriticCodex = class extends BaseObserver {
|
|
10808
|
+
opts;
|
|
10809
|
+
emissions = /* @__PURE__ */ new Map();
|
|
10810
|
+
turnCount = /* @__PURE__ */ new Map();
|
|
10811
|
+
pending = /* @__PURE__ */ new Set();
|
|
10812
|
+
constructor(opts) {
|
|
10813
|
+
super();
|
|
10814
|
+
this.opts = {
|
|
10815
|
+
maxEmissionsPerAgent: opts.maxEmissionsPerAgent ?? 2,
|
|
10816
|
+
model: opts.model,
|
|
10817
|
+
codexBin: opts.codexBin ?? "codex",
|
|
10818
|
+
timeoutMs: opts.timeoutMs ?? 6e4,
|
|
10819
|
+
targets: opts.targets
|
|
10820
|
+
};
|
|
10821
|
+
}
|
|
10822
|
+
/** Resolves once every in-flight evaluation has emitted its CritiqueItem. */
|
|
10823
|
+
async idle() {
|
|
10824
|
+
await Promise.allSettled([...this.pending]);
|
|
10825
|
+
}
|
|
10826
|
+
async onExternalEvent(_source, event) {
|
|
10827
|
+
if (!AgentResult.is(event)) return;
|
|
10828
|
+
const { agentId, isError, resultText } = event.data;
|
|
10829
|
+
if (isError || !resultText) return;
|
|
10830
|
+
const criteria = this.opts.targets.get(agentId);
|
|
10831
|
+
if (!criteria || criteria.length === 0) return;
|
|
10832
|
+
const turn = (this.turnCount.get(agentId) ?? 0) + 1;
|
|
10833
|
+
this.turnCount.set(agentId, turn);
|
|
10834
|
+
const work = (async () => {
|
|
10835
|
+
const { verdict, reasoning, violatedCriteria } = await this.evaluate(
|
|
10836
|
+
resultText,
|
|
10837
|
+
criteria
|
|
10838
|
+
);
|
|
10839
|
+
const critiqueEvent = Critique.create({
|
|
10840
|
+
agentId,
|
|
10841
|
+
verdict,
|
|
10842
|
+
reasoning,
|
|
10843
|
+
violatedCriteria,
|
|
10844
|
+
turn,
|
|
10845
|
+
modelUsed: this.opts.model ?? "codex-default"
|
|
10846
|
+
});
|
|
10847
|
+
for (const env of this.getEnvironments()) {
|
|
10848
|
+
env.deliverSemanticEvent(this, critiqueEvent);
|
|
10849
|
+
}
|
|
10850
|
+
if (verdict === "fail") {
|
|
10851
|
+
const emitted = this.emissions.get(agentId) ?? 0;
|
|
10852
|
+
if (emitted < this.opts.maxEmissionsPerAgent) {
|
|
10853
|
+
this.emissions.set(agentId, emitted + 1);
|
|
10854
|
+
const text = buildCorrectiveMessage(reasoning, violatedCriteria);
|
|
10855
|
+
const msg = AgentTargetedMessage.create({
|
|
10856
|
+
recipientId: agentId,
|
|
10857
|
+
text,
|
|
10858
|
+
metadata: {
|
|
10859
|
+
criticTurn: turn,
|
|
10860
|
+
emissionIndex: emitted + 1
|
|
10861
|
+
}
|
|
10862
|
+
});
|
|
10863
|
+
for (const env of this.getEnvironments()) {
|
|
10864
|
+
env.deliverSemanticEvent(this, msg);
|
|
10865
|
+
}
|
|
10866
|
+
}
|
|
10867
|
+
}
|
|
10868
|
+
})();
|
|
10869
|
+
this.pending.add(work);
|
|
10870
|
+
work.finally(() => {
|
|
10871
|
+
this.pending.delete(work);
|
|
10872
|
+
});
|
|
10873
|
+
await work;
|
|
10874
|
+
}
|
|
10875
|
+
async evaluate(resultText, criteria) {
|
|
10876
|
+
const userPrompt = buildEvalPrompt(criteria, resultText);
|
|
10877
|
+
const prompt = `${VERDICT_SYSTEM_PROMPT}
|
|
10878
|
+
|
|
10879
|
+
${userPrompt}`;
|
|
10880
|
+
try {
|
|
10881
|
+
const text = await runCodexOneShot({
|
|
10882
|
+
prompt,
|
|
10883
|
+
// Critic doesn't operate on the worktree — but Codex
|
|
10884
|
+
// still insists on running inside a git repo unless we
|
|
10885
|
+
// skip the check. Pass through skipGitRepoCheck so the
|
|
10886
|
+
// critic can be invoked from anywhere (including baro's
|
|
10887
|
+
// own cwd that may not be the story worktree).
|
|
10888
|
+
cwd: process.cwd(),
|
|
10889
|
+
skipGitRepoCheck: true,
|
|
10890
|
+
bypassSandbox: true,
|
|
10891
|
+
model: this.opts.model,
|
|
10892
|
+
codexBin: this.opts.codexBin,
|
|
10893
|
+
timeoutMs: this.opts.timeoutMs
|
|
10894
|
+
});
|
|
10895
|
+
const verdictJson = extractVerdictJson(text.trim());
|
|
10896
|
+
const parsed = JSON.parse(verdictJson);
|
|
10897
|
+
return {
|
|
10898
|
+
verdict: parsed.verdict === "pass" ? "pass" : "fail",
|
|
10899
|
+
reasoning: parsed.reasoning ?? "",
|
|
10900
|
+
violatedCriteria: Array.isArray(parsed.violated_criteria) ? parsed.violated_criteria : []
|
|
10901
|
+
};
|
|
10902
|
+
} catch (err) {
|
|
10903
|
+
return {
|
|
10904
|
+
verdict: "fail",
|
|
10905
|
+
reasoning: `CriticCodex LLM call failed: ${String(err?.message ?? err)}`,
|
|
10906
|
+
violatedCriteria: ["[critic error \u2014 could not evaluate]"]
|
|
10907
|
+
};
|
|
10908
|
+
}
|
|
10909
|
+
}
|
|
10910
|
+
};
|
|
10911
|
+
|
|
10755
10912
|
// ../baro-orchestrator/src/planning/openai-runtime.ts
|
|
10756
10913
|
async function runInferenceRound(_context, _model) {
|
|
10757
10914
|
throw new Error(
|
|
@@ -10927,9 +11084,9 @@ var CriticOpenAI = class extends BaseObserver {
|
|
|
10927
11084
|
};
|
|
10928
11085
|
|
|
10929
11086
|
// ../baro-orchestrator/src/participants/finalizer.ts
|
|
10930
|
-
import { execFile as
|
|
10931
|
-
import { promisify as
|
|
10932
|
-
var
|
|
11087
|
+
import { execFile as execFile4 } from "child_process";
|
|
11088
|
+
import { promisify as promisify4 } from "util";
|
|
11089
|
+
var execFileAsync3 = promisify4(execFile4);
|
|
10933
11090
|
var Finalizer = class extends BaseObserver {
|
|
10934
11091
|
opts;
|
|
10935
11092
|
envRef = null;
|
|
@@ -11178,7 +11335,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11178
11335
|
async collectCommitsSinceBase() {
|
|
11179
11336
|
if (!this.baseSha) return [];
|
|
11180
11337
|
try {
|
|
11181
|
-
const { stdout } = await
|
|
11338
|
+
const { stdout } = await execFileAsync3(
|
|
11182
11339
|
"git",
|
|
11183
11340
|
["log", `${this.baseSha}..HEAD`, "--pretty=format:%H%x09%s"],
|
|
11184
11341
|
{ cwd: this.opts.cwd }
|
|
@@ -11194,7 +11351,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11194
11351
|
async collectFileStats() {
|
|
11195
11352
|
if (!this.baseSha) return { created: 0, modified: 0 };
|
|
11196
11353
|
try {
|
|
11197
|
-
const { stdout } = await
|
|
11354
|
+
const { stdout } = await execFileAsync3(
|
|
11198
11355
|
"git",
|
|
11199
11356
|
["diff", "--name-status", this.baseSha, "HEAD"],
|
|
11200
11357
|
{ cwd: this.opts.cwd }
|
|
@@ -11213,7 +11370,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11213
11370
|
}
|
|
11214
11371
|
async detectBranch() {
|
|
11215
11372
|
try {
|
|
11216
|
-
const { stdout } = await
|
|
11373
|
+
const { stdout } = await execFileAsync3(
|
|
11217
11374
|
"git",
|
|
11218
11375
|
["branch", "--show-current"],
|
|
11219
11376
|
{ cwd: this.opts.cwd }
|
|
@@ -11225,7 +11382,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11225
11382
|
}
|
|
11226
11383
|
async detectDefaultBaseBranch() {
|
|
11227
11384
|
try {
|
|
11228
|
-
const { stdout } = await
|
|
11385
|
+
const { stdout } = await execFileAsync3(
|
|
11229
11386
|
"gh",
|
|
11230
11387
|
["repo", "view", "--json", "defaultBranchRef", "--jq", ".defaultBranchRef.name"],
|
|
11231
11388
|
{ cwd: this.opts.cwd }
|
|
@@ -11235,7 +11392,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11235
11392
|
} catch {
|
|
11236
11393
|
}
|
|
11237
11394
|
try {
|
|
11238
|
-
const { stdout } = await
|
|
11395
|
+
const { stdout } = await execFileAsync3(
|
|
11239
11396
|
"git",
|
|
11240
11397
|
["symbolic-ref", "--short", "refs/remotes/origin/HEAD"],
|
|
11241
11398
|
{ cwd: this.opts.cwd }
|
|
@@ -11323,7 +11480,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11323
11480
|
}
|
|
11324
11481
|
async hasGhBinary() {
|
|
11325
11482
|
try {
|
|
11326
|
-
await
|
|
11483
|
+
await execFileAsync3("gh", ["--version"], { cwd: this.opts.cwd });
|
|
11327
11484
|
return true;
|
|
11328
11485
|
} catch {
|
|
11329
11486
|
return false;
|
|
@@ -11331,7 +11488,7 @@ var Finalizer = class extends BaseObserver {
|
|
|
11331
11488
|
}
|
|
11332
11489
|
async openPr(args) {
|
|
11333
11490
|
try {
|
|
11334
|
-
const { stdout } = await
|
|
11491
|
+
const { stdout } = await execFileAsync3(
|
|
11335
11492
|
"gh",
|
|
11336
11493
|
[
|
|
11337
11494
|
"pr",
|
|
@@ -13844,9 +14001,9 @@ var StoryFactory = class extends BaseObserver {
|
|
|
13844
14001
|
};
|
|
13845
14002
|
|
|
13846
14003
|
// ../baro-orchestrator/src/participants/surgeon.ts
|
|
13847
|
-
import { execFile as
|
|
13848
|
-
import { promisify as
|
|
13849
|
-
var
|
|
14004
|
+
import { execFile as execFile5 } from "child_process";
|
|
14005
|
+
import { promisify as promisify5 } from "util";
|
|
14006
|
+
var execFileAsync4 = promisify5(execFile5);
|
|
13850
14007
|
var SURGEON_SYSTEM_PROMPT = `You are the Surgeon \u2014 an autonomous planner that adapts a software-project
|
|
13851
14008
|
DAG when stories fail. Given:
|
|
13852
14009
|
1. A snapshot of the current PRD (project, story list with dependencies +
|
|
@@ -13952,7 +14109,7 @@ var Surgeon = class extends BaseObserver {
|
|
|
13952
14109
|
const snap = this.opts.snapshot();
|
|
13953
14110
|
const prompt = buildSurgeonPrompt(snap, failure);
|
|
13954
14111
|
try {
|
|
13955
|
-
const { stdout } = await
|
|
14112
|
+
const { stdout } = await execFileAsync4(
|
|
13956
14113
|
this.opts.claudeBin,
|
|
13957
14114
|
[
|
|
13958
14115
|
"--print",
|
|
@@ -14053,6 +14210,85 @@ function surgeonDeterministicReplan(failure) {
|
|
|
14053
14210
|
};
|
|
14054
14211
|
}
|
|
14055
14212
|
|
|
14213
|
+
// ../baro-orchestrator/src/participants/surgeon-codex.ts
|
|
14214
|
+
var SurgeonCodex = class extends BaseObserver {
|
|
14215
|
+
opts;
|
|
14216
|
+
replansEmitted = 0;
|
|
14217
|
+
pending = /* @__PURE__ */ new Set();
|
|
14218
|
+
constructor(opts) {
|
|
14219
|
+
super();
|
|
14220
|
+
this.opts = {
|
|
14221
|
+
useLlm: opts.useLlm ?? true,
|
|
14222
|
+
model: opts.model,
|
|
14223
|
+
maxReplans: opts.maxReplans ?? 10,
|
|
14224
|
+
codexBin: opts.codexBin ?? "codex",
|
|
14225
|
+
timeoutMs: opts.timeoutMs ?? 12e4,
|
|
14226
|
+
snapshot: opts.snapshot
|
|
14227
|
+
};
|
|
14228
|
+
}
|
|
14229
|
+
async idle() {
|
|
14230
|
+
await Promise.allSettled([...this.pending]);
|
|
14231
|
+
}
|
|
14232
|
+
async onExternalEvent(_source, event) {
|
|
14233
|
+
if (!StoryResult.is(event)) return;
|
|
14234
|
+
if (event.data.success) return;
|
|
14235
|
+
if (this.replansEmitted >= this.opts.maxReplans) return;
|
|
14236
|
+
const work = (async () => {
|
|
14237
|
+
const replan = this.opts.useLlm ? await this.evaluateWithLlm(event.data) : surgeonDeterministicReplan(event.data);
|
|
14238
|
+
if (!replan) return;
|
|
14239
|
+
this.replansEmitted += 1;
|
|
14240
|
+
for (const env of this.getEnvironments()) {
|
|
14241
|
+
env.deliverSemanticEvent(this, Replan.create(replan));
|
|
14242
|
+
}
|
|
14243
|
+
})();
|
|
14244
|
+
this.pending.add(work);
|
|
14245
|
+
work.finally(() => this.pending.delete(work));
|
|
14246
|
+
await work;
|
|
14247
|
+
}
|
|
14248
|
+
async evaluateWithLlm(failure) {
|
|
14249
|
+
const snap = this.opts.snapshot();
|
|
14250
|
+
const userPrompt = buildSurgeonPrompt(snap, failure);
|
|
14251
|
+
const prompt = `${SURGEON_SYSTEM_PROMPT}
|
|
14252
|
+
|
|
14253
|
+
${userPrompt}`;
|
|
14254
|
+
try {
|
|
14255
|
+
const text = await runCodexOneShot({
|
|
14256
|
+
prompt,
|
|
14257
|
+
cwd: process.cwd(),
|
|
14258
|
+
skipGitRepoCheck: true,
|
|
14259
|
+
bypassSandbox: true,
|
|
14260
|
+
model: this.opts.model,
|
|
14261
|
+
codexBin: this.opts.codexBin,
|
|
14262
|
+
timeoutMs: this.opts.timeoutMs
|
|
14263
|
+
});
|
|
14264
|
+
const verdictText = text.trim();
|
|
14265
|
+
if (!verdictText) throw new Error("empty result");
|
|
14266
|
+
const verdictJson = extractJsonObject(verdictText);
|
|
14267
|
+
const parsed = JSON.parse(verdictJson);
|
|
14268
|
+
if (parsed.action === "abort") return null;
|
|
14269
|
+
const modifiedDeps = {};
|
|
14270
|
+
for (const m of parsed.modifiedDeps ?? []) {
|
|
14271
|
+
if (typeof m.id === "string" && Array.isArray(m.newDependsOn)) {
|
|
14272
|
+
modifiedDeps[m.id] = [...m.newDependsOn];
|
|
14273
|
+
}
|
|
14274
|
+
}
|
|
14275
|
+
return {
|
|
14276
|
+
source: "surgeon",
|
|
14277
|
+
reason: `${parsed.action}: ${parsed.reason ?? ""}`,
|
|
14278
|
+
addedStories: parsed.added ?? [],
|
|
14279
|
+
removedStoryIds: parsed.removed ?? [],
|
|
14280
|
+
modifiedDeps
|
|
14281
|
+
};
|
|
14282
|
+
} catch (err) {
|
|
14283
|
+
const fallback = surgeonDeterministicReplan(failure);
|
|
14284
|
+
return {
|
|
14285
|
+
...fallback,
|
|
14286
|
+
reason: `${fallback.reason} (codex fallback after error: ${err?.message ?? String(err)})`
|
|
14287
|
+
};
|
|
14288
|
+
}
|
|
14289
|
+
}
|
|
14290
|
+
};
|
|
14291
|
+
|
|
14056
14292
|
// ../baro-orchestrator/src/participants/surgeon-openai.ts
|
|
14057
14293
|
function pickModel3(name) {
|
|
14058
14294
|
switch (name) {
|
|
@@ -14173,7 +14409,7 @@ async function orchestrate(config) {
|
|
|
14173
14409
|
);
|
|
14174
14410
|
} else if (llm === "codex") {
|
|
14175
14411
|
process.stderr.write(
|
|
14176
|
-
"[orchestrate] llm=codex:
|
|
14412
|
+
"[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
14413
|
);
|
|
14178
14414
|
} else {
|
|
14179
14415
|
process.stderr.write(
|
|
@@ -14218,14 +14454,24 @@ async function orchestrate(config) {
|
|
|
14218
14454
|
}))
|
|
14219
14455
|
};
|
|
14220
14456
|
};
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
|
|
14457
|
+
if (llm === "openai") {
|
|
14458
|
+
surgeon = new SurgeonOpenAI({
|
|
14459
|
+
snapshot,
|
|
14460
|
+
model: config.surgeonModel ?? "gpt-5.5"
|
|
14461
|
+
});
|
|
14462
|
+
} else if (llm === "codex") {
|
|
14463
|
+
surgeon = new SurgeonCodex({
|
|
14464
|
+
snapshot,
|
|
14465
|
+
useLlm: config.surgeonUseLlm ?? true,
|
|
14466
|
+
model: config.surgeonModel
|
|
14467
|
+
});
|
|
14468
|
+
} else {
|
|
14469
|
+
surgeon = new Surgeon({
|
|
14470
|
+
snapshot,
|
|
14471
|
+
useLlm: config.surgeonUseLlm ?? false,
|
|
14472
|
+
model: config.surgeonModel ?? "opus"
|
|
14473
|
+
});
|
|
14474
|
+
}
|
|
14229
14475
|
surgeon.join(env);
|
|
14230
14476
|
}
|
|
14231
14477
|
let critic = null;
|
|
@@ -14234,13 +14480,22 @@ async function orchestrate(config) {
|
|
|
14234
14480
|
const targets = new Map(
|
|
14235
14481
|
prd.userStories.filter((s) => s.acceptance && s.acceptance.length > 0).map((s) => [s.id, s.acceptance])
|
|
14236
14482
|
);
|
|
14237
|
-
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14483
|
+
if (llm === "openai") {
|
|
14484
|
+
critic = new CriticOpenAI({
|
|
14485
|
+
targets,
|
|
14486
|
+
model: config.criticModel ?? "gpt-5.4-mini"
|
|
14487
|
+
});
|
|
14488
|
+
} else if (llm === "codex") {
|
|
14489
|
+
critic = new CriticCodex({
|
|
14490
|
+
targets,
|
|
14491
|
+
model: config.criticModel
|
|
14492
|
+
});
|
|
14493
|
+
} else {
|
|
14494
|
+
critic = new Critic({
|
|
14495
|
+
targets,
|
|
14496
|
+
model: config.criticModel ?? "haiku"
|
|
14497
|
+
});
|
|
14498
|
+
}
|
|
14244
14499
|
critic.join(env);
|
|
14245
14500
|
}
|
|
14246
14501
|
const finalizer = useGit ? new Finalizer({
|