baro-ai 0.63.0 → 0.65.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/runner.mjs CHANGED
@@ -3734,7 +3734,7 @@ var url = process.env.CONTROL_URL ?? "wss://api.baro.jigjoy.ai";
3734
3734
  var token = process.env.RUNNER_TOKEN;
3735
3735
  var httpBase = url.replace(/^ws/, "http").replace(/\/+$/, "");
3736
3736
  var credsPath = join(homedir(), ".baro", "credentials.json");
3737
- var VERSION = "0.63.0";
3737
+ var VERSION = "0.65.0";
3738
3738
  var updateCachePath = join(homedir(), ".baro", "update-check.json");
3739
3739
  function semverLt(a, b) {
3740
3740
  const pa = a.split(".").map(Number);
@@ -3844,6 +3844,7 @@ async function runGoal(d, emit, signal) {
3844
3844
  let cleanup;
3845
3845
  let diffBase;
3846
3846
  let scratch = false;
3847
+ let prUrl = null;
3847
3848
  if (d.repo && (d.githubToken || d.diffOnly)) {
3848
3849
  try {
3849
3850
  cwd = await cloneRepo(d.repo.fullName, d.githubToken, emit);
@@ -3922,6 +3923,7 @@ async function runGoal(d, emit, signal) {
3922
3923
  if (ev.type === "story_complete") passed++;
3923
3924
  else if (ev.type === "story_error") failed++;
3924
3925
  else if (ev.type === "done") doneSuccess = !!ev.success;
3926
+ else if (ev.type === "finalize_complete") prUrl = ev.data?.pr_url ?? ev.pr_url ?? prUrl;
3925
3927
  const d2 = ev.data ?? {};
3926
3928
  const msg = d2.error ?? d2.message ?? ev.error;
3927
3929
  if (typeof msg === "string" && msg.trim() && (String(ev.type).includes("error") || String(ev.type).includes("fail") || ev.type === "done" && ev.success === false)) {
@@ -3936,14 +3938,16 @@ async function runGoal(d, emit, signal) {
3936
3938
  child.on("close", (code) => {
3937
3939
  const ok = doneSuccess ?? (code === 0 && failed === 0 && passed > 0);
3938
3940
  const goalLines = new Set(d.goal.split("\n").map((s) => s.trim()).filter(Boolean));
3939
- const errTail = stderrTail.trim().split("\n").map((s) => s.trim()).filter((l) => l && l !== "User goal:" && !l.startsWith("User goal:") && !goalLines.has(l)).slice(-3).join(" \xB7 ").slice(-500);
3941
+ const isNoise = (l) => /no stdin data received|redirect stdin explicitly|proceeding without it/i.test(l);
3942
+ const errTail = stderrTail.trim().split("\n").map((s) => s.trim()).filter((l) => l && l !== "User goal:" && !l.startsWith("User goal:") && !goalLines.has(l) && !isNoise(l)).slice(-3).join(" \xB7 ").slice(-500);
3943
+ const cliHint = `the agent CLI on this runner produced no output \u2014 make sure \`claude\` (or \`codex\`) is installed and signed in here (run it once), or run on baro's cloud instead (no setup)`;
3940
3944
  resolve({
3941
3945
  success: ok,
3942
3946
  durationSecs: secs(),
3943
3947
  storiesPassed: passed,
3944
3948
  storiesTotal: stories.size || passed + failed,
3945
3949
  // Prefer the real reason from the stream, then cleaned stderr, then a fallback.
3946
- error: ok ? null : lastErr || errTail || (doneSuccess === false ? "run reported failure" : `exit ${code} \u2014 the run ended without a result (is the claude/codex CLI signed in on this runner?)`)
3950
+ error: ok ? null : lastErr || errTail || (doneSuccess === false ? "run reported failure" : cliHint)
3947
3951
  });
3948
3952
  });
3949
3953
  child.on("error", (e) => resolve({ success: false, durationSecs: secs(), error: e.message }));
@@ -3951,9 +3955,55 @@ async function runGoal(d, emit, signal) {
3951
3955
  if ((d.diffOnly || scratch) && diffBase) {
3952
3956
  outcome.diff = captureDiff(cwd, diffBase);
3953
3957
  }
3958
+ if (process.env.BARO_PR_DOCTOR === "1" && d.repo && !d.diffOnly && !scratch && outcome.success && prUrl) {
3959
+ try {
3960
+ await watchCi(cwd, emit, signal);
3961
+ } catch (e) {
3962
+ emit({ type: "story_log", agentId: "_ci", data: { type: "story_log", id: "_ci", line: `[pr-doctor] CI watch error: ${e.message}` } });
3963
+ }
3964
+ }
3954
3965
  cleanup?.();
3955
3966
  return outcome;
3956
3967
  }
3968
+ function gh(args, cwd) {
3969
+ try {
3970
+ const out = execFileSync("gh", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
3971
+ return { code: 0, out };
3972
+ } catch (e) {
3973
+ const err = e;
3974
+ return {
3975
+ code: typeof err.status === "number" ? err.status : 1,
3976
+ out: `${err.stdout?.toString() ?? ""}${err.stderr?.toString() ?? ""}`
3977
+ };
3978
+ }
3979
+ }
3980
+ async function watchCi(cwd, emit, signal) {
3981
+ const log = (line) => emit({ type: "story_log", agentId: "_ci", data: { type: "story_log", id: "_ci", line } });
3982
+ const timeoutMs = Number(process.env.BARO_PR_DOCTOR_CI_TIMEOUT ?? 900) * 1e3;
3983
+ const deadline = Date.now() + timeoutMs;
3984
+ log("watching the pull request's CI\u2026");
3985
+ while (Date.now() < deadline && !signal.aborted) {
3986
+ const r = gh(["pr", "checks"], cwd);
3987
+ const out = r.out.toLowerCase();
3988
+ if (out.includes("no checks") || out.includes("no commit statuses")) {
3989
+ log("no CI configured on this repo \u2014 nothing to watch.");
3990
+ return;
3991
+ }
3992
+ if (r.code === 0) {
3993
+ log("\u2713 CI is green \u2014 all checks passed.");
3994
+ return;
3995
+ }
3996
+ if (r.code === 8 || out.includes("pending") || out.includes("in progress") || out.includes("queued")) {
3997
+ await new Promise((res) => setTimeout(res, 2e4));
3998
+ continue;
3999
+ }
4000
+ const fails = r.out.split("\n").filter((l) => /fail|error|✗|×/i.test(l)).slice(0, 8).join("\n");
4001
+ log(`\u2717 CI is failing:
4002
+ ${fails || r.out.slice(-500)}`);
4003
+ return;
4004
+ }
4005
+ log("CI watch timed out while checks were still pending.");
4006
+ }
3957
4007
  var rejected;
3958
4008
  var currentWs = null;
3959
4009
  var inflight = /* @__PURE__ */ new Map();