usebeeline 0.0.37 → 0.0.44

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.
Files changed (2) hide show
  1. package/dist/usebeeline.mjs +1880 -500
  2. package/package.json +1 -1
@@ -307,14 +307,14 @@ __export(self_update_exports, {
307
307
  writeUpdateAttemptFixture: () => writeUpdateAttemptFixture,
308
308
  writeUpdateState: () => writeUpdateState
309
309
  });
310
- import { createHash as createHash2 } from "node:crypto";
310
+ import { createHash as createHash3 } from "node:crypto";
311
311
  import { constants as fsConstants } from "node:fs";
312
- import { access, chmod as chmod3, lstat as lstat2, mkdir as mkdir9, open, readFile as readFile4, rename as rename3, rm as rm4, symlink as symlink2, writeFile as writeFile6 } from "node:fs/promises";
312
+ import { access, chmod as chmod3, lstat as lstat2, mkdir as mkdir10, open, readFile as readFile8, rename as rename3, rm as rm4, symlink as symlink2, writeFile as writeFile8 } from "node:fs/promises";
313
313
  import { spawn as spawn4 } from "node:child_process";
314
314
  import { homedir as homedir9 } from "node:os";
315
- import { dirname as dirname8, join as join6, resolve as resolve14 } from "node:path";
315
+ import { dirname as dirname9, join as join6, resolve as resolve18 } from "node:path";
316
316
  function anchorLayout(rawLibDir) {
317
- const libDir = resolve14(rawLibDir);
317
+ const libDir = resolve18(rawLibDir);
318
318
  const segments = libDir.split(/[/\\]/);
319
319
  const idx = segments.lastIndexOf(RELEASES_SEGMENT);
320
320
  if (idx >= 2 && segments[idx - 1] === "lib") {
@@ -330,9 +330,9 @@ function anchorLayout(rawLibDir) {
330
330
  // prefix's bin, NOT <prefix>/lib/bin — deriving it one level up was the
331
331
  // defect that made activateRelease write its stable forwarders where
332
332
  // nothing executed them, leaving stale raw wrappers in <prefix>/bin.
333
- binDir: resolve14(libDir, "../../bin"),
333
+ binDir: resolve18(libDir, "../../bin"),
334
334
  libDir,
335
- releasesRoot: resolve14(libDir, `../${RELEASES_SEGMENT}`)
335
+ releasesRoot: resolve18(libDir, `../${RELEASES_SEGMENT}`)
336
336
  };
337
337
  }
338
338
  function beelineInstallLayout(env = process.env) {
@@ -343,7 +343,7 @@ function beelineInstallLayout(env = process.env) {
343
343
  }
344
344
  function defaultBeelineInstallLayout(env = process.env) {
345
345
  const home = env.HOME?.trim() || homedir9();
346
- return anchorLayout(resolve14(home, ".local", "lib", "beeline"));
346
+ return anchorLayout(resolve18(home, ".local", "lib", "beeline"));
347
347
  }
348
348
  function hostPlatformKey() {
349
349
  const os = process.platform === "linux" ? "linux" : process.platform === "darwin" ? "darwin" : "";
@@ -359,7 +359,7 @@ async function readBundleJson(bundleDir) {
359
359
  let raw;
360
360
  for (const candidate of bundleJsonCandidates(bundleDir)) {
361
361
  try {
362
- raw = await readFile4(candidate, "utf8");
362
+ raw = await readFile8(candidate, "utf8");
363
363
  break;
364
364
  } catch {
365
365
  }
@@ -381,14 +381,14 @@ function updateStatePath(layout) {
381
381
  }
382
382
  async function readUpdateState(layout) {
383
383
  try {
384
- return JSON.parse(await readFile4(updateStatePath(layout), "utf8"));
384
+ return JSON.parse(await readFile8(updateStatePath(layout), "utf8"));
385
385
  } catch {
386
386
  return {};
387
387
  }
388
388
  }
389
389
  async function writeUpdateState(layout, state) {
390
- await mkdir9(join6(layout.releasesRoot, ".state"), { recursive: true });
391
- await writeFile6(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
390
+ await mkdir10(join6(layout.releasesRoot, ".state"), { recursive: true });
391
+ await writeFile8(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
392
392
  `, "utf8");
393
393
  }
394
394
  async function readInstalledBundleIdentity(layout, _state = {}) {
@@ -489,29 +489,29 @@ function requiredBundlePaths() {
489
489
  }
490
490
  async function stageRelease(layout, manifestUrl, published, opts = {}) {
491
491
  const fetchImpl = opts.fetchImpl ?? fetch;
492
- const log = opts.logger ?? ((line) => console.log(`[body] self-update: ${line}`));
492
+ const log2 = opts.logger ?? ((line) => console.log(`[body] self-update: ${line}`));
493
493
  const releaseId = sanitizeReleaseId(published.commit ?? published.version ?? `release-${Date.now()}`);
494
494
  const releaseDir = join6(layout.releasesRoot, releaseId);
495
495
  const okMarker = join6(releaseDir, ".stage-ok");
496
496
  let previouslyVerified = false;
497
497
  try {
498
- const recorded = await readFile4(okMarker, "utf8");
498
+ const recorded = await readFile8(okMarker, "utf8");
499
499
  if (recorded.trim() === published.sha256)
500
500
  return releaseId;
501
501
  previouslyVerified = true;
502
502
  } catch {
503
503
  }
504
- await mkdir9(releaseDir, { recursive: true });
504
+ await mkdir10(releaseDir, { recursive: true });
505
505
  const tempArchive = join6(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
506
506
  try {
507
- log(`downloading ${published.file}`);
507
+ log2(`downloading ${published.file}`);
508
508
  const response = await fetchImpl(archiveUrlFor(manifestUrl, published.file), {
509
509
  signal: AbortSignal.timeout(10 * 6e4)
510
510
  });
511
511
  if (!response.ok || !response.body) {
512
512
  throw new Error(`downloading ${published.file} failed: HTTP ${response.status}`);
513
513
  }
514
- const hash = createHash2("sha256");
514
+ const hash = createHash3("sha256");
515
515
  const chunks = [];
516
516
  for await (const chunk of response.body) {
517
517
  const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
@@ -522,7 +522,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
522
522
  if (actual !== published.sha256.toLowerCase()) {
523
523
  throw new Error(`checksum mismatch for ${published.file}: expected ${published.sha256}, got ${actual} \u2014 aborting without touching the installed bundle`);
524
524
  }
525
- await writeFile6(tempArchive, Buffer.concat(chunks), { mode: 384 });
525
+ await writeFile8(tempArchive, Buffer.concat(chunks), { mode: 384 });
526
526
  const entries = (await new Promise((resolveList, rejectList) => {
527
527
  const child = spawn4("tar", ["-tzf", tempArchive], { stdio: ["ignore", "pipe", "inherit"] });
528
528
  let out = "";
@@ -553,9 +553,9 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
553
553
  throw new Error(`staged bundle failed its startup smoke test (--version exited ${probe.status})${probe.stderr ? `: ${probe.stderr.trim()}` : ""}`);
554
554
  }
555
555
  }
556
- await writeFile6(okMarker, `${published.sha256}
556
+ await writeFile8(okMarker, `${published.sha256}
557
557
  `, "utf8");
558
- log(`staged release ${releaseId} (sha256 verified)`);
558
+ log2(`staged release ${releaseId} (sha256 verified)`);
559
559
  return releaseId;
560
560
  } catch (error) {
561
561
  if (!previouslyVerified)
@@ -581,15 +581,15 @@ function forwarderScript(tool) {
581
581
  }
582
582
  async function replaceFile(path, contents, mode) {
583
583
  const temp = `${path}.new-${process.pid}`;
584
- await writeFile6(temp, contents, { mode });
584
+ await writeFile8(temp, contents, { mode });
585
585
  await chmod3(temp, mode);
586
586
  await rename3(temp, path);
587
587
  }
588
588
  async function activateRelease(layout, releaseId) {
589
589
  const releaseDir = join6(layout.releasesRoot, releaseId);
590
590
  await access(join6(releaseDir, BUNDLE_ENTRYPOINT), fsConstants.F_OK);
591
- await mkdir9(layout.releasesRoot, { recursive: true });
592
- await mkdir9(layout.binDir, { recursive: true });
591
+ await mkdir10(layout.releasesRoot, { recursive: true });
592
+ await mkdir10(layout.binDir, { recursive: true });
593
593
  let previousReleaseId = await activeReleaseId(layout);
594
594
  const kind = await pathKind(layout.libDir);
595
595
  if (kind === "directory") {
@@ -611,7 +611,7 @@ async function activateRelease(layout, releaseId) {
611
611
  await rm4(tempLink, { force: true });
612
612
  await symlink2(join6("beeline-releases", releaseId), tempLink);
613
613
  await rename3(tempLink, layout.libDir);
614
- await fsyncDir(dirname8(layout.libDir));
614
+ await fsyncDir(dirname9(layout.libDir));
615
615
  await writeBinForwarders(layout, releaseDir);
616
616
  return { previousReleaseId };
617
617
  }
@@ -628,7 +628,7 @@ async function normalizeLegacyBundleShape(bundleDir) {
628
628
  }
629
629
  if (!anyFlat)
630
630
  return;
631
- await mkdir9(innerLib, { recursive: true });
631
+ await mkdir10(innerLib, { recursive: true });
632
632
  for (const name of LEGACY_FLAT_BUNDLE_FILES) {
633
633
  try {
634
634
  await access(join6(innerLib, name), fsConstants.F_OK);
@@ -655,13 +655,13 @@ async function repairInstallForwarders(layout, opts = {}) {
655
655
  const forwarderPath = join6(layout.binDir, "beeline");
656
656
  let current;
657
657
  try {
658
- current = await readFile4(forwarderPath, "utf8");
658
+ current = await readFile8(forwarderPath, "utf8");
659
659
  } catch {
660
660
  current = void 0;
661
661
  }
662
662
  if (current === forwarderScript("beeline"))
663
663
  return false;
664
- await mkdir9(layout.binDir, { recursive: true });
664
+ await mkdir10(layout.binDir, { recursive: true });
665
665
  await writeBinForwarders(layout, layout.libDir);
666
666
  opts.logger?.(`[body] self-update: repaired <prefix>/bin forwarders to follow the active-bundle anchor (${layout.libDir})`);
667
667
  return true;
@@ -676,14 +676,14 @@ async function rollbackToPreviousRelease(layout, previousReleaseId) {
676
676
  await rm4(tempLink, { force: true });
677
677
  await symlink2(join6("beeline-releases", previousReleaseId), tempLink);
678
678
  await rename3(tempLink, layout.libDir);
679
- await fsyncDir(dirname8(layout.libDir));
679
+ await fsyncDir(dirname9(layout.libDir));
680
680
  }
681
681
  function updateAttemptPath(layout) {
682
682
  return join6(layout.releasesRoot, ".state", "update-attempt.json");
683
683
  }
684
684
  async function readUpdateAttempt(layout) {
685
685
  try {
686
- const raw = JSON.parse(await readFile4(updateAttemptPath(layout), "utf8"));
686
+ const raw = JSON.parse(await readFile8(updateAttemptPath(layout), "utf8"));
687
687
  if (raw.version !== 1 || typeof raw.appliedAt !== "number" || typeof raw.confirmBy !== "number" || typeof raw.releaseId !== "string" || !["pending", "confirmed", "reverted"].includes(raw.status)) {
688
688
  return void 0;
689
689
  }
@@ -693,10 +693,10 @@ async function readUpdateAttempt(layout) {
693
693
  }
694
694
  }
695
695
  async function writeUpdateAttempt(layout, record2) {
696
- await mkdir9(join6(layout.releasesRoot, ".state"), { recursive: true });
696
+ await mkdir10(join6(layout.releasesRoot, ".state"), { recursive: true });
697
697
  const path = updateAttemptPath(layout);
698
698
  const staged = `${path}.${process.pid}.tmp`;
699
- await writeFile6(staged, `${JSON.stringify(record2, null, 2)}
699
+ await writeFile8(staged, `${JSON.stringify(record2, null, 2)}
700
700
  `, { mode: 384 });
701
701
  await rename3(staged, path);
702
702
  }
@@ -955,8 +955,8 @@ var init_self_update = __esm({
955
955
  });
956
956
 
957
957
  // apps/body/dist/cli.js
958
- import { dirname as dirname13, resolve as resolve21 } from "node:path";
959
- import { readFile as readFile9, unlink as unlink3, writeFile as writeFile12 } from "node:fs/promises";
958
+ import { dirname as dirname15, resolve as resolve25 } from "node:path";
959
+ import { readFile as readFile13, unlink as unlink3, writeFile as writeFile14 } from "node:fs/promises";
960
960
  import { stdin as stdin4, stdout as stdout5 } from "node:process";
961
961
 
962
962
  // node_modules/@clack/core/dist/index.mjs
@@ -2057,6 +2057,49 @@ var MULTISELECT_INSTRUCTIONS = [
2057
2057
  `${styleText2("dim", "Space:")} select`,
2058
2058
  `${styleText2("dim", "Enter:")} confirm`
2059
2059
  ];
2060
+ var log = {
2061
+ message: (s = [], {
2062
+ symbol: e = styleText2("gray", S_BAR),
2063
+ secondarySymbol: r2 = styleText2("gray", S_BAR),
2064
+ output: m2 = process.stdout,
2065
+ spacing: l2 = 1,
2066
+ withGuide: c2
2067
+ } = {}) => {
2068
+ const t2 = [], o = c2 ?? settings.withGuide, f = o ? r2 : "", O = o ? `${e} ` : "", u4 = o ? `${r2} ` : "";
2069
+ for (let i3 = 0; i3 < l2; i3++)
2070
+ t2.push(f);
2071
+ const g2 = Array.isArray(s) ? s : s.split(`
2072
+ `);
2073
+ if (g2.length > 0) {
2074
+ const [i3, ...y] = g2;
2075
+ i3.length > 0 ? t2.push(`${O}${i3}`) : t2.push(o ? e : "");
2076
+ for (const p of y)
2077
+ p.length > 0 ? t2.push(`${u4}${p}`) : t2.push(o ? r2 : "");
2078
+ }
2079
+ m2.write(`${t2.join(`
2080
+ `)}
2081
+ `);
2082
+ },
2083
+ info: (s, e) => {
2084
+ log.message(s, { ...e, symbol: styleText2("blue", S_INFO) });
2085
+ },
2086
+ success: (s, e) => {
2087
+ log.message(s, { ...e, symbol: styleText2("green", S_SUCCESS) });
2088
+ },
2089
+ step: (s, e) => {
2090
+ log.message(s, { ...e, symbol: styleText2("green", S_STEP_SUBMIT) });
2091
+ },
2092
+ warn: (s, e) => {
2093
+ log.message(s, { ...e, symbol: styleText2("yellow", S_WARN) });
2094
+ },
2095
+ /** alias for `log.warn()`. */
2096
+ warning: (s, e) => {
2097
+ log.warn(s, e);
2098
+ },
2099
+ error: (s, e) => {
2100
+ log.message(s, { ...e, symbol: styleText2("red", S_ERROR) });
2101
+ }
2102
+ };
2060
2103
  var cancel = (o = "", t2) => {
2061
2104
  const i3 = t2?.output ?? process.stdout, e = t2?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
2062
2105
  i3.write(`${e}${styleText2("red", o)}
@@ -3099,6 +3142,9 @@ function agentMessageChunkText(update) {
3099
3142
  }
3100
3143
  var CHUNK_CONTINUES_PREVIOUS_WORD = /^[\s'\u2018\u2019\u02bc.,!?;:%)\]}-]/;
3101
3144
  var PI_ACP_HARNESS = /(^|[/\\])pi-acp(?:\.[a-z]+)?$/i;
3145
+ function isPiAcpHarness(agentLabel) {
3146
+ return Boolean(agentLabel && PI_ACP_HARNESS.test(agentLabel));
3147
+ }
3102
3148
  function withoutOneTrailingLineEnding(text2) {
3103
3149
  if (/\r?\n\r?\n$/.test(text2))
3104
3150
  return text2;
@@ -3166,6 +3212,19 @@ function finalAgentMessageText(updates, agentLabel) {
3166
3212
  return "";
3167
3213
  return last;
3168
3214
  }
3215
+ function describeEmptyTurn(result, agentLabel) {
3216
+ const counts = /* @__PURE__ */ new Map();
3217
+ for (const { update } of result.updates) {
3218
+ const kind = typeof update.sessionUpdate === "string" ? update.sessionUpdate : "unknown";
3219
+ if (kind === "session_info_update" || kind === "available_commands_update")
3220
+ continue;
3221
+ counts.set(kind, (counts.get(kind) ?? 0) + 1);
3222
+ }
3223
+ const stream = counts.size ? `the stream carried only ${[...counts].map(([kind, count]) => `${kind}\xD7${count}`).join(", ")}` : "the stream carried no content updates";
3224
+ const lastRun = agentMessageRuns(result.updates, agentLabel).at(-1);
3225
+ const narration = lastRun && isPureRetryNarration(lastRun) ? `; the last message was retry narration "${lastRun.trim().slice(0, 80)}"` : "";
3226
+ return `harness ended the turn (${result.stopReason}) with no answer text; ${stream}${narration}`;
3227
+ }
3169
3228
  function updateText(update) {
3170
3229
  const content = update.content;
3171
3230
  if (typeof content === "string")
@@ -3186,7 +3245,7 @@ var THOUGHT_UPDATE_TYPES = /* @__PURE__ */ new Set([
3186
3245
  ]);
3187
3246
  function agentStreamSnapshot(updates, agentLabel) {
3188
3247
  const completedMessages = [];
3189
- let messageText = "";
3248
+ let messageText2 = "";
3190
3249
  let lastWasMessage = false;
3191
3250
  let thoughtText = "";
3192
3251
  let thoughtRunOpen = false;
@@ -3196,20 +3255,20 @@ function agentStreamSnapshot(updates, agentLabel) {
3196
3255
  const delta = normalizeStreamDelta(agentMessageChunkText(update), agentLabel);
3197
3256
  if (!delta)
3198
3257
  continue;
3199
- if (!lastWasMessage && messageText && !/\s$/.test(messageText) && !CHUNK_CONTINUES_PREVIOUS_WORD.test(delta)) {
3200
- if (!completedMessages.includes(messageText))
3201
- completedMessages.push(messageText);
3202
- messageText = "";
3258
+ if (!lastWasMessage && messageText2 && !/\s$/.test(messageText2) && !CHUNK_CONTINUES_PREVIOUS_WORD.test(delta)) {
3259
+ if (!completedMessages.includes(messageText2))
3260
+ completedMessages.push(messageText2);
3261
+ messageText2 = "";
3203
3262
  }
3204
- messageText += delta;
3263
+ messageText2 += delta;
3205
3264
  lastWasMessage = true;
3206
3265
  thoughtRunOpen = false;
3207
3266
  continue;
3208
3267
  }
3209
- if (lastWasMessage && messageText) {
3210
- if (!completedMessages.includes(messageText))
3211
- completedMessages.push(messageText);
3212
- messageText = "";
3268
+ if (lastWasMessage && messageText2) {
3269
+ if (!completedMessages.includes(messageText2))
3270
+ completedMessages.push(messageText2);
3271
+ messageText2 = "";
3213
3272
  }
3214
3273
  lastWasMessage = false;
3215
3274
  if (THOUGHT_UPDATE_TYPES.has(kind)) {
@@ -3225,7 +3284,7 @@ function agentStreamSnapshot(updates, agentLabel) {
3225
3284
  }
3226
3285
  }
3227
3286
  return {
3228
- messageText,
3287
+ messageText: messageText2,
3229
3288
  ...thoughtText || completedMessages.length ? { thoughtText: thoughtText || completedMessages.at(-1) } : {}
3230
3289
  };
3231
3290
  }
@@ -3720,7 +3779,7 @@ var AcpClient = class extends EventEmitter {
3720
3779
  const current = this.activeRunIds.get(sessionId);
3721
3780
  if (current)
3722
3781
  return Promise.resolve(current);
3723
- return new Promise((resolve22, reject) => {
3782
+ return new Promise((resolve26, reject) => {
3724
3783
  const onUpdate = (update) => {
3725
3784
  if (update.sessionId !== sessionId)
3726
3785
  return;
@@ -3728,7 +3787,7 @@ var AcpClient = class extends EventEmitter {
3728
3787
  if (!runId)
3729
3788
  return;
3730
3789
  cleanup();
3731
- resolve22(runId);
3790
+ resolve26(runId);
3732
3791
  };
3733
3792
  const timer = setTimeout(() => {
3734
3793
  cleanup();
@@ -3748,23 +3807,23 @@ var AcpClient = class extends EventEmitter {
3748
3807
  const tracked = metadataKey ? this.toolCallMetadata.get(metadataKey) : void 0;
3749
3808
  if (tracked)
3750
3809
  p.toolCall = { ...tracked, ...p.toolCall };
3751
- let decision = this.autoApprove ? "allow" : "reject";
3810
+ let decision2 = this.autoApprove ? "allow" : "reject";
3752
3811
  if (!this.autoApprove && this.permissionAllowlist) {
3753
3812
  try {
3754
- decision = this.permissionAllowlist(p) ? "allow" : "reject";
3813
+ decision2 = this.permissionAllowlist(p) ? "allow" : "reject";
3755
3814
  } catch (error) {
3756
3815
  this.emit("permission/error", error);
3757
- decision = "reject";
3816
+ decision2 = "reject";
3758
3817
  }
3759
3818
  } else if (this.permissionHandler) {
3760
3819
  try {
3761
- decision = await this.permissionHandler(p);
3820
+ decision2 = await this.permissionHandler(p);
3762
3821
  } catch (error) {
3763
3822
  this.emit("permission/error", error);
3764
- decision = "reject";
3823
+ decision2 = "reject";
3765
3824
  }
3766
3825
  }
3767
- if (decision === "allow") {
3826
+ if (decision2 === "allow") {
3768
3827
  const allow = p?.options?.find((o) => o.kind === "allow_once" || o.kind === "allow_always") ?? p?.options?.[0];
3769
3828
  if (allow?.optionId) {
3770
3829
  if (metadataKey)
@@ -3812,13 +3871,13 @@ var AcpClient = class extends EventEmitter {
3812
3871
  }
3813
3872
  const id = this.nextId++;
3814
3873
  const payload = { jsonrpc: "2.0", id, method, params };
3815
- return new Promise((resolve22, reject) => {
3874
+ return new Promise((resolve26, reject) => {
3816
3875
  const timer = setTimeout(() => {
3817
3876
  this.pending.delete(id);
3818
3877
  reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart)));
3819
3878
  }, timeoutMs);
3820
3879
  this.pending.set(id, {
3821
- resolve: resolve22,
3880
+ resolve: resolve26,
3822
3881
  reject,
3823
3882
  timer,
3824
3883
  method,
@@ -4157,12 +4216,25 @@ async function applyAgentModelSelection(client, sessionId, advertisedOptions, se
4157
4216
  }
4158
4217
 
4159
4218
  // apps/body/dist/model-catalog.js
4219
+ function modelCatalogProbeEnvironment(agent, agentEnv, scratchCwd) {
4220
+ if (agent.kind !== "goose")
4221
+ return agentEnv;
4222
+ return {
4223
+ ...agentEnv,
4224
+ GOOSE_PATH_ROOT: resolve4(scratchCwd, "goose")
4225
+ };
4226
+ }
4227
+ function filterAgentModelCatalog(agent, raw, agentEnv) {
4228
+ const allowed = filterAllowedModelConfigOptions(raw);
4229
+ return agent.kind === "goose" ? allowed : filterModelOptionsByCredentials(allowed, agentEnv);
4230
+ }
4160
4231
  async function withAgentModelCatalog(agent, agentEnv, selection, inspect) {
4161
4232
  const scratchCwd = await mkdtemp(resolve4(tmpdir(), "beeline-pair-model-check-"));
4233
+ const probeEnv = modelCatalogProbeEnvironment(agent, agentEnv, scratchCwd);
4162
4234
  const client = new AcpClient({
4163
4235
  agentCommand: agent.command,
4164
4236
  agentArgs: agentArgsWithModelSelection(agent, selection),
4165
- agentEnv,
4237
+ agentEnv: probeEnv,
4166
4238
  agentCwd: scratchCwd,
4167
4239
  // The wizard probe runs on the human's own machine for a few seconds —
4168
4240
  // inherit the caller's environment so harness launchers resolve (`pi`,
@@ -4175,7 +4247,7 @@ async function withAgentModelCatalog(agent, agentEnv, selection, inspect) {
4175
4247
  await client.start();
4176
4248
  const { sessionId, raw: sessionRaw } = await client.sessionNew({ cwd: scratchCwd });
4177
4249
  const raw = parseAdvertisedConfigOptions(sessionRaw, selection?.model, isGrokAgentCommand(agent));
4178
- const catalog = filterModelOptionsByCredentials(filterAllowedModelConfigOptions(raw), agentEnv);
4250
+ const catalog = filterAgentModelCatalog(agent, raw, probeEnv);
4179
4251
  return await inspect({ client, sessionId, raw, catalog });
4180
4252
  } finally {
4181
4253
  await client.stop().catch(() => void 0);
@@ -4236,31 +4308,433 @@ async function applyRuntimeModelPreflight(config, agent, selection, validate = v
4236
4308
  config.modelUnavailable = await revalidateRuntimeModelSelection(agent, config.agentEnv, selection, validate);
4237
4309
  }
4238
4310
 
4239
- // apps/body/dist/room-runtime.js
4240
- import { execFile as execFile3 } from "node:child_process";
4311
+ // apps/body/dist/model-catalog-sync.js
4241
4312
  import { createHash } from "node:crypto";
4313
+ import { readFile, writeFile } from "node:fs/promises";
4314
+ import { resolve as resolve5 } from "node:path";
4315
+ var MODEL_CATALOG_PROBE_TIMEOUT_MS = 3e4;
4316
+ var MODEL_CATALOG_HASH_FILE = "model-catalog.sha256";
4317
+ function modelCatalogHash(options, selection) {
4318
+ return createHash("sha256").update(JSON.stringify({ options, selection: selection ?? null })).digest("hex");
4319
+ }
4320
+ async function withTimeout(work, timeoutMs, what) {
4321
+ let timer;
4322
+ const expiry = new Promise((_, reject) => {
4323
+ timer = setTimeout(() => reject(new Error(`${what} timed out after ${timeoutMs}ms`)), timeoutMs);
4324
+ });
4325
+ try {
4326
+ return await Promise.race([work, expiry]);
4327
+ } finally {
4328
+ clearTimeout(timer);
4329
+ work.catch(() => void 0);
4330
+ }
4331
+ }
4332
+ async function syncAgentModelCatalog(input) {
4333
+ const log2 = input.log ?? ((line) => console.log(line));
4334
+ const fetchCatalog = input.fetchCatalog ?? fetchAgentModelCatalog;
4335
+ const hashPath = resolve5(input.runtimeDir, MODEL_CATALOG_HASH_FILE);
4336
+ try {
4337
+ const configuration = await input.api.execute("getAgentConfiguration", {
4338
+ agentId: input.agentId
4339
+ });
4340
+ const selection = configuration.model || configuration.effort ? {
4341
+ ...configuration.model ? { model: configuration.model } : {},
4342
+ ...configuration.effort ? { effort: configuration.effort } : {}
4343
+ } : input.runtimeSelection;
4344
+ const { catalog } = await withTimeout(fetchCatalog(input.agent, input.agentEnv, selection), input.timeoutMs ?? MODEL_CATALOG_PROBE_TIMEOUT_MS, "model catalog probe");
4345
+ const hash = modelCatalogHash(catalog, selection);
4346
+ const previous = await readFile(hashPath, "utf8").catch(() => "");
4347
+ if (previous.trim() === hash)
4348
+ return "unchanged";
4349
+ await input.api.execute("postAgentModelCatalog", {
4350
+ agentId: input.agentId,
4351
+ workspaceId: input.workspaceId,
4352
+ // `fetchAgentModelCatalog` already applied the category allow-list.
4353
+ options: catalog,
4354
+ ...selection ? { selection } : {}
4355
+ });
4356
+ await writeFile(hashPath, `${hash}
4357
+ `, { mode: 384 });
4358
+ log2(`[body] model catalog posted: ${catalog.length} axis(es)` + (selection?.model ? `, model ${selection.model}` : "") + (selection?.effort ? `, effort ${selection.effort}` : ""));
4359
+ return "posted";
4360
+ } catch (error) {
4361
+ log2(`[body] model catalog not posted this activation: ${error instanceof Error ? error.message : String(error)}`);
4362
+ return "failed";
4363
+ }
4364
+ }
4365
+
4366
+ // apps/body/dist/room-runtime.js
4367
+ import { execFile as execFile4 } from "node:child_process";
4368
+ import { createHash as createHash2 } from "node:crypto";
4242
4369
  import { existsSync as existsSync4, mkdirSync } from "node:fs";
4243
- import { mkdir as mkdir6, rm as rm3 } from "node:fs/promises";
4244
- import { dirname as dirname4, resolve as resolve10 } from "node:path";
4370
+ import { mkdir as mkdir8, rm as rm3 } from "node:fs/promises";
4371
+ import { dirname as dirname6, resolve as resolve15 } from "node:path";
4245
4372
  import { promisify as promisify3 } from "node:util";
4246
4373
 
4374
+ // apps/body/dist/grant-runner.js
4375
+ import { execFile } from "node:child_process";
4376
+ import { randomBytes } from "node:crypto";
4377
+ import { readFile as readFile3 } from "node:fs/promises";
4378
+ import { createServer } from "node:http";
4379
+ import { dirname as dirname3, resolve as resolve7 } from "node:path";
4380
+
4381
+ // packages/api-contract/dist/agent-grants.js
4382
+ var AGENT_GRANT_KINDS = ["path", "host", "secret", "device", "budget", "command"];
4383
+ var SHELL_METACHARACTERS = /[;&|<>$`\\'"(){}\n\r\t*?[\]~#!]/;
4384
+ var SECRET_NAME = /^[A-Z][A-Z0-9_]{0,63}$/;
4385
+ function parseCommandGrantTarget(target) {
4386
+ if (typeof target !== "string" || !target.trim()) {
4387
+ throw new Error("command target is required");
4388
+ }
4389
+ if (target !== target.trim() || /\s{2,}/.test(target)) {
4390
+ throw new Error("command target must be one line with single spaces");
4391
+ }
4392
+ if (SHELL_METACHARACTERS.test(target)) {
4393
+ throw new Error("command target must not contain shell metacharacters");
4394
+ }
4395
+ const words = target.split(" ");
4396
+ const argv = [];
4397
+ const secrets = [];
4398
+ for (let index = 0; index < words.length; index += 1) {
4399
+ const word = words[index];
4400
+ if (word === "--with") {
4401
+ const name = words[index + 1];
4402
+ if (!name || !SECRET_NAME.test(name)) {
4403
+ throw new Error("--with must name one UPPER_CASE secret");
4404
+ }
4405
+ if (!secrets.includes(name))
4406
+ secrets.push(name);
4407
+ index += 1;
4408
+ continue;
4409
+ }
4410
+ if (secrets.length)
4411
+ throw new Error("--with suffixes must come after the command words");
4412
+ argv.push(word);
4413
+ }
4414
+ if (!argv.length)
4415
+ throw new Error("command target must name a command");
4416
+ return { argv, secrets };
4417
+ }
4418
+ function commandGrantMatches(rule, requested) {
4419
+ if (requested.length < rule.argv.length)
4420
+ return false;
4421
+ return rule.argv.every((word, index) => requested[index] === word);
4422
+ }
4423
+ var DECISION_LINE = new RegExp(`^(.+?) (approved once|approved|declined) (${AGENT_GRANT_KINDS.join("|")}) (.+)$`, "s");
4424
+ function parseGrantDecisionLine(body) {
4425
+ const match = DECISION_LINE.exec(body);
4426
+ if (!match)
4427
+ return void 0;
4428
+ const decision2 = match[2] === "approved once" ? "once" : match[2] === "approved" ? "always" : "deny";
4429
+ return {
4430
+ deciderName: match[1],
4431
+ decision: decision2,
4432
+ kind: match[3],
4433
+ target: match[4]
4434
+ };
4435
+ }
4436
+
4437
+ // apps/body/dist/provider-key-store.js
4438
+ import { chmod, mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
4439
+ import { homedir as homedir2 } from "node:os";
4440
+ import { dirname as dirname2, resolve as resolve6 } from "node:path";
4441
+ var PROVIDER_KEY_ENV_VARS = {
4442
+ openrouter: "OPENROUTER_API_KEY",
4443
+ openai: "OPENAI_API_KEY",
4444
+ anthropic: "ANTHROPIC_API_KEY",
4445
+ google: "GOOGLE_API_KEY",
4446
+ xai: "XAI_API_KEY"
4447
+ };
4448
+ var GOOGLE_ENV_ALIAS = "GEMINI_API_KEY";
4449
+ function providerKeyStorePath(env = process.env) {
4450
+ const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve6(homedir2(), ".config");
4451
+ return resolve6(configRoot, "beeline", "providers.json");
4452
+ }
4453
+ async function readProviderKeyStore(env = process.env) {
4454
+ const path = providerKeyStorePath(env);
4455
+ const raw = await readFile2(path, "utf8").catch(() => void 0);
4456
+ if (!raw)
4457
+ return {};
4458
+ try {
4459
+ const parsed = JSON.parse(raw);
4460
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
4461
+ return {};
4462
+ const entries = Object.entries(parsed).filter((entry) => entry[0] in PROVIDER_KEY_ENV_VARS && typeof entry[1] === "string" && entry[1].length > 0);
4463
+ return Object.fromEntries(entries);
4464
+ } catch {
4465
+ return {};
4466
+ }
4467
+ }
4468
+ async function readSavedProviderKey(provider, env = process.env) {
4469
+ return (await readProviderKeyStore(env))[provider];
4470
+ }
4471
+ async function saveProviderKey(provider, key, env = process.env) {
4472
+ const path = providerKeyStorePath(env);
4473
+ const store = { ...await readProviderKeyStore(env), [provider]: key };
4474
+ await mkdir(dirname2(path), { recursive: true, mode: 448 });
4475
+ await writeFile2(path, `${JSON.stringify(store, null, 2)}
4476
+ `, { mode: 384 });
4477
+ await chmod(path, 384);
4478
+ }
4479
+ function providerKeyFromEnvironment(provider, env = process.env) {
4480
+ const primary = env[PROVIDER_KEY_ENV_VARS[provider]]?.trim();
4481
+ if (primary)
4482
+ return primary;
4483
+ if (provider === "google")
4484
+ return env[GOOGLE_ENV_ALIAS]?.trim() || void 0;
4485
+ return void 0;
4486
+ }
4487
+ function maskProviderKey(key) {
4488
+ const trimmed = key.trim();
4489
+ if (trimmed.length <= 9)
4490
+ return "\u2026";
4491
+ return `${trimmed.slice(0, 6)}\u2026${trimmed.slice(-3)}`;
4492
+ }
4493
+
4494
+ // apps/body/dist/grant-runner.js
4495
+ var GRANT_COMMAND_TIMEOUT_MS = 10 * 6e4;
4496
+ var GRANT_COMMAND_OUTPUT_CAP_BYTES = 64 * 1024;
4497
+ var ARGV_MAX_WORDS = 256;
4498
+ var ARGV_WORD_MAX_LENGTH = 4096;
4499
+ function operatorSecretResolver(env = process.env) {
4500
+ const providerByEnvVar = new Map(Object.entries(PROVIDER_KEY_ENV_VARS).map(([provider, envVar]) => [envVar, provider]));
4501
+ return async (name) => {
4502
+ const provider = providerByEnvVar.get(name);
4503
+ if (provider) {
4504
+ const saved = (await readProviderKeyStore(env))[provider];
4505
+ if (saved)
4506
+ return saved;
4507
+ }
4508
+ const raw = await readFile3(resolve7(dirname3(providerKeyStorePath(env)), "secrets.json"), "utf8").catch(() => void 0);
4509
+ if (!raw)
4510
+ return void 0;
4511
+ try {
4512
+ const parsed = JSON.parse(raw);
4513
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
4514
+ return void 0;
4515
+ const value = parsed[name];
4516
+ return typeof value === "string" && value.length > 0 ? value : void 0;
4517
+ } catch {
4518
+ return void 0;
4519
+ }
4520
+ };
4521
+ }
4522
+ function validateGrantArgv(value) {
4523
+ if (!Array.isArray(value) || value.length === 0)
4524
+ throw new Error("argv must be a non-empty array");
4525
+ if (value.length > ARGV_MAX_WORDS)
4526
+ throw new Error(`argv exceeds ${ARGV_MAX_WORDS} words`);
4527
+ return value.map((word) => {
4528
+ if (typeof word !== "string" || !word)
4529
+ throw new Error("argv words must be non-empty strings");
4530
+ if (word.length > ARGV_WORD_MAX_LENGTH || /[\0\r\n]/.test(word)) {
4531
+ throw new Error("argv words must be single-line and bounded");
4532
+ }
4533
+ return word;
4534
+ });
4535
+ }
4536
+ function matchCommandGrant(grants, workspaceId, argv) {
4537
+ for (const grant of grants) {
4538
+ if (grant.kind !== "command" || grant.workspaceId !== workspaceId)
4539
+ continue;
4540
+ let rule;
4541
+ try {
4542
+ rule = parseCommandGrantTarget(grant.target);
4543
+ } catch {
4544
+ continue;
4545
+ }
4546
+ if (commandGrantMatches(rule, argv))
4547
+ return { grant, rule };
4548
+ }
4549
+ return void 0;
4550
+ }
4551
+ function capOutput(value, cap) {
4552
+ if (Buffer.byteLength(value) <= cap)
4553
+ return value;
4554
+ const half = Math.floor(cap / 2);
4555
+ const bytes = Buffer.from(value);
4556
+ return `${bytes.subarray(0, half).toString("utf8")}
4557
+ \u2026[${bytes.length - cap} bytes omitted]\u2026
4558
+ ${bytes.subarray(bytes.length - half).toString("utf8")}`;
4559
+ }
4560
+ function scrubSecrets(value, secrets) {
4561
+ let scrubbed = value;
4562
+ for (const [name, secret] of secrets) {
4563
+ if (secret.length >= 4)
4564
+ scrubbed = scrubbed.split(secret).join(`[${name}]`);
4565
+ }
4566
+ return scrubbed;
4567
+ }
4568
+ var GrantCommandRunner = class {
4569
+ options;
4570
+ rooms = /* @__PURE__ */ new Map();
4571
+ resolveSecret;
4572
+ constructor(options) {
4573
+ this.options = options;
4574
+ this.resolveSecret = options.resolveSecret ?? operatorSecretResolver(options.env ?? process.env);
4575
+ }
4576
+ register(roomId, room) {
4577
+ this.rooms.set(roomId, room);
4578
+ }
4579
+ unregister(roomId) {
4580
+ this.rooms.delete(roomId);
4581
+ }
4582
+ async run(input) {
4583
+ if (typeof input.roomId !== "string" || !input.roomId)
4584
+ throw new Error("roomId is required");
4585
+ const room = this.rooms.get(input.roomId);
4586
+ if (!room)
4587
+ throw new Error("this daemon is not serving that Room");
4588
+ const argv = validateGrantArgv(input.argv);
4589
+ const live = await this.options.api.execute("listAgentGrants", { agentId: this.options.agentId });
4590
+ const match = matchCommandGrant(live.grants, room.workspaceId, argv);
4591
+ if (!match) {
4592
+ throw new Error(`no approved command grant matches: ${argv.join(" ")}. Ask with request_grant kind=command first.`);
4593
+ }
4594
+ const { grant, rule } = match;
4595
+ const secrets = /* @__PURE__ */ new Map();
4596
+ for (const name of rule.secrets) {
4597
+ const value = await this.resolveSecret(name);
4598
+ if (!value)
4599
+ throw new Error(`secret ${name} is not in the operator key store`);
4600
+ secrets.set(name, value);
4601
+ }
4602
+ if (grant.status === "once") {
4603
+ await this.options.api.execute("consumeAgentGrant", { grantId: grant.grantId });
4604
+ }
4605
+ const source = this.options.env ?? process.env;
4606
+ const env = {
4607
+ ...source.PATH ? { PATH: source.PATH } : {},
4608
+ ...source.HOME ? { HOME: source.HOME } : {},
4609
+ ...Object.fromEntries(secrets)
4610
+ };
4611
+ const cap = this.options.outputCapBytes ?? GRANT_COMMAND_OUTPUT_CAP_BYTES;
4612
+ const outcome = await new Promise((resolveRun) => {
4613
+ const child = execFile(argv[0], argv.slice(1), {
4614
+ cwd: room.cwd,
4615
+ env,
4616
+ timeout: this.options.timeoutMs ?? GRANT_COMMAND_TIMEOUT_MS,
4617
+ killSignal: "SIGKILL",
4618
+ maxBuffer: cap * 4,
4619
+ encoding: "utf8"
4620
+ }, (error, stdout6, stderr) => {
4621
+ const combined = [stdout6, stderr].filter(Boolean).join(stderr && stdout6 ? "\n" : "");
4622
+ const failure = error;
4623
+ const spawnFailure = Boolean(failure && typeof failure.code === "string");
4624
+ resolveRun({
4625
+ exitCode: spawnFailure ? null : child.exitCode ?? (typeof failure?.code === "number" ? failure.code : 0),
4626
+ ...failure?.signal ? { signal: failure.signal } : {},
4627
+ timedOut: Boolean(failure?.killed && failure?.signal === "SIGKILL"),
4628
+ output: spawnFailure ? `${combined}${combined ? "\n" : ""}${failure.message}` : combined
4629
+ });
4630
+ });
4631
+ });
4632
+ const output = capOutput(scrubSecrets(outcome.output, secrets), cap);
4633
+ const turn = room.turn();
4634
+ const requester = turn?.requester ?? {
4635
+ pubkey: grant.requestedBy,
4636
+ ...grant.requestedByName ? { name: grant.requestedByName } : {}
4637
+ };
4638
+ const status = outcome.timedOut ? "timed out" : outcome.exitCode === null ? "error" : `exit ${outcome.exitCode}`;
4639
+ await this.options.api.execute("postAgentActivity", {
4640
+ agentId: this.options.agentId,
4641
+ roomId: input.roomId,
4642
+ requestId: turn?.requestId ?? `grant:${grant.grantId}`,
4643
+ activity: [
4644
+ {
4645
+ kind: "tool",
4646
+ title: `ran ${argv.join(" ")} under grant ${grant.grantId} \xB7 asked by ${requester.name ?? requester.pubkey.slice(0, 12)}`,
4647
+ operation: "execute",
4648
+ status,
4649
+ command: argv.join(" "),
4650
+ ...output ? { output } : {},
4651
+ requestedBy: requester
4652
+ }
4653
+ ]
4654
+ });
4655
+ return {
4656
+ grantId: grant.grantId,
4657
+ exitCode: outcome.exitCode,
4658
+ ...outcome.signal ? { signal: outcome.signal } : {},
4659
+ timedOut: outcome.timedOut,
4660
+ output
4661
+ };
4662
+ }
4663
+ };
4664
+ var GrantRunnerServer = class {
4665
+ runner;
4666
+ server;
4667
+ endpoint;
4668
+ constructor(runner) {
4669
+ this.runner = runner;
4670
+ }
4671
+ async start() {
4672
+ if (this.endpoint)
4673
+ return this.endpoint;
4674
+ const token = randomBytes(32).toString("base64url");
4675
+ const server = createServer((request, response) => {
4676
+ void this.handle(request, response, token);
4677
+ });
4678
+ await new Promise((resolveListen, reject) => {
4679
+ server.once("error", reject);
4680
+ server.listen(0, "127.0.0.1", () => resolveListen());
4681
+ });
4682
+ server.unref?.();
4683
+ const address = server.address();
4684
+ this.server = server;
4685
+ this.endpoint = { url: `http://127.0.0.1:${address.port}`, token };
4686
+ return this.endpoint;
4687
+ }
4688
+ async close() {
4689
+ const server = this.server;
4690
+ this.server = void 0;
4691
+ this.endpoint = void 0;
4692
+ if (!server)
4693
+ return;
4694
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
4695
+ }
4696
+ async handle(request, response, token) {
4697
+ const send = (status, body) => {
4698
+ response.writeHead(status, { "content-type": "application/json" });
4699
+ response.end(JSON.stringify(body));
4700
+ };
4701
+ if (request.headers.authorization !== `Bearer ${token}`) {
4702
+ send(401, { error: "grant runner token required" });
4703
+ return;
4704
+ }
4705
+ if (request.method !== "POST" || request.url !== "/run") {
4706
+ send(404, { error: "not found" });
4707
+ return;
4708
+ }
4709
+ const chunks = [];
4710
+ for await (const chunk of request)
4711
+ chunks.push(chunk);
4712
+ try {
4713
+ const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
4714
+ send(200, await this.runner.run({ roomId: body.roomId, argv: body.argv }));
4715
+ } catch (error) {
4716
+ send(400, { error: error instanceof Error ? error.message : String(error) });
4717
+ }
4718
+ }
4719
+ };
4720
+
4247
4721
  // apps/body/dist/monolith-corner-turn.js
4248
- import { execFile as execFile2 } from "node:child_process";
4249
- import { mkdir as mkdir4 } from "node:fs/promises";
4250
- import { homedir as homedir5 } from "node:os";
4722
+ import { execFile as execFile3 } from "node:child_process";
4723
+ import { mkdir as mkdir6 } from "node:fs/promises";
4724
+ import { homedir as homedir6 } from "node:os";
4251
4725
  import { join as join4 } from "node:path";
4252
4726
  import { promisify as promisify2 } from "node:util";
4253
4727
 
4254
4728
  // apps/body/dist/agent-home.js
4255
4729
  import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
4256
4730
  import { randomUUID } from "node:crypto";
4257
- import { chmod, copyFile, lstat, mkdir, readdir, realpath, rename, rm as rm2, symlink, unlink, writeFile } from "node:fs/promises";
4258
- import { homedir as homedir2 } from "node:os";
4259
- import { basename as basename3, dirname as dirname2, relative, resolve as resolve6, sep } from "node:path";
4731
+ import { chmod as chmod2, copyFile, lstat, mkdir as mkdir3, readdir, realpath, rename, rm as rm2, symlink, unlink, writeFile as writeFile4 } from "node:fs/promises";
4732
+ import { homedir as homedir3 } from "node:os";
4733
+ import { basename as basename3, dirname as dirname4, relative, resolve as resolve10, sep } from "node:path";
4260
4734
 
4261
4735
  // apps/body/dist/beeline-skill.js
4262
4736
  import { readFileSync as readFileSync3 } from "node:fs";
4263
- import { resolve as resolve5 } from "node:path";
4737
+ import { resolve as resolve8 } from "node:path";
4264
4738
  var USING_BEELINE_SKILL_NAME = "using-beeline";
4265
4739
  var BEELINE_ROOM_CAPABILITIES = [
4266
4740
  "The repository filesystem is read-only in this Room session.",
@@ -4272,6 +4746,7 @@ var BEELINE_ROOM_CAPABILITIES = [
4272
4746
  "To send a file, call beeline-agent attach_file with a path inside your checkout; it is attached to your reply.",
4273
4747
  "To run something later or repeatedly, call beeline-agent create_schedule (interval in minutes or a 5-field cron, optional maxRuns); list_schedules / delete_schedule manage them.",
4274
4748
  "When repository work is needed, you MUST call beeline-agent open_corner with a complete objective of no more than 24 words. The host-governed call is the only way to start write work.",
4749
+ "When open_corner succeeds, the server posts the corner card: do not announce or restate the opening. End the turn with nothing more unless the person asked something else.",
4275
4750
  "Never claim an action or reply happened unless the prompt or a tool result proves it."
4276
4751
  ].join(" ");
4277
4752
  var BEELINE_DM_CAPABILITIES = [
@@ -4304,7 +4779,7 @@ function runningBeelineReleaseId(env = process.env, read = (path) => readFileSyn
4304
4779
  const lib = env.BEELINE_LIB_DIR;
4305
4780
  if (!lib)
4306
4781
  return "source";
4307
- const manifest = JSON.parse(read(resolve5(lib, "bundle.json")));
4782
+ const manifest = JSON.parse(read(resolve8(lib, "bundle.json")));
4308
4783
  return [manifest.version, manifest.commit].filter(Boolean).join("-") || "source";
4309
4784
  } catch {
4310
4785
  return "source";
@@ -4340,6 +4815,226 @@ var SQUIRE_GOVERNED_TOOLS = [
4340
4815
  ];
4341
4816
  var SQUIRE_GOVERNED_TOOL_SET = new Set(SQUIRE_GOVERNED_TOOLS);
4342
4817
 
4818
+ // apps/body/dist/openrouter-routing.js
4819
+ import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
4820
+ import { resolve as resolve9 } from "node:path";
4821
+ var OPENROUTER_ENDPOINTS_BASE_URL = "https://openrouter.ai/api/v1/models";
4822
+ var OPENROUTER_ROUTING_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
4823
+ var OPENROUTER_ROUTING_FETCH_TIMEOUT_MS = 1e4;
4824
+ var OPENROUTER_UPTIME_BAR = 98;
4825
+ var OPENROUTER_UPTIME_BAR_RELAXED = 95;
4826
+ var OPENROUTER_MIN_PROVIDERS = 2;
4827
+ var OPENROUTER_FALLBACK_PROVIDERS = ["deepinfra", "novita"];
4828
+ function openRouterModelId(model, env = {}) {
4829
+ const trimmed = model?.trim();
4830
+ if (!trimmed)
4831
+ return void 0;
4832
+ if (trimmed.startsWith("openrouter/")) {
4833
+ const id = trimmed.slice("openrouter/".length);
4834
+ return id.includes("/") ? id : void 0;
4835
+ }
4836
+ if (env.OPENROUTER_API_KEY?.trim() && /^[^/\s]+\/[^/\s][^\s]*$/.test(trimmed))
4837
+ return trimmed;
4838
+ return void 0;
4839
+ }
4840
+ function parseOpenRouterEndpoints(payload) {
4841
+ const data = payload?.data;
4842
+ const record2 = data && typeof data === "object" ? data : {};
4843
+ const raw = Array.isArray(record2.endpoints) ? record2.endpoints : [];
4844
+ const endpoints = [];
4845
+ for (const entry of raw) {
4846
+ if (!entry || typeof entry !== "object")
4847
+ continue;
4848
+ const endpoint2 = entry;
4849
+ const tag = typeof endpoint2.tag === "string" ? endpoint2.tag : "";
4850
+ const provider = tag.split("/")[0]?.trim() ?? "";
4851
+ if (!provider)
4852
+ continue;
4853
+ const uptime = typeof endpoint2.uptime_last_30m === "number" ? endpoint2.uptime_last_30m : 0;
4854
+ const contextLength = typeof endpoint2.context_length === "number" ? endpoint2.context_length : 0;
4855
+ const supported = Array.isArray(endpoint2.supported_parameters) ? endpoint2.supported_parameters : [];
4856
+ endpoints.push({ provider, uptime, contextLength, tools: supported.includes("tools") });
4857
+ }
4858
+ return {
4859
+ endpoints,
4860
+ contextLength: typeof record2.context_length === "number" ? record2.context_length : advertisedContextLength(endpoints)
4861
+ };
4862
+ }
4863
+ function advertisedContextLength(endpoints) {
4864
+ const counts = /* @__PURE__ */ new Map();
4865
+ for (const endpoint2 of endpoints) {
4866
+ if (!endpoint2.tools || endpoint2.contextLength <= 0)
4867
+ continue;
4868
+ counts.set(endpoint2.contextLength, (counts.get(endpoint2.contextLength) ?? 0) + 1);
4869
+ }
4870
+ let best;
4871
+ for (const [length, count] of counts) {
4872
+ if (best === void 0) {
4873
+ best = length;
4874
+ continue;
4875
+ }
4876
+ const bestCount = counts.get(best) ?? 0;
4877
+ if (count > bestCount || count === bestCount && length > best)
4878
+ best = length;
4879
+ }
4880
+ return best;
4881
+ }
4882
+ function selectReliableOpenRouterProviders(endpoints, contextLength) {
4883
+ const eligible = endpoints.filter((endpoint2) => endpoint2.tools && (contextLength === void 0 || endpoint2.contextLength >= contextLength));
4884
+ const atBar = (bar) => {
4885
+ const seen = /* @__PURE__ */ new Set();
4886
+ return eligible.filter((endpoint2) => endpoint2.uptime >= bar).sort((left, right) => right.uptime - left.uptime).map((endpoint2) => endpoint2.provider).filter((provider) => seen.has(provider) ? false : (seen.add(provider), true));
4887
+ };
4888
+ const strict = atBar(OPENROUTER_UPTIME_BAR);
4889
+ if (strict.length >= OPENROUTER_MIN_PROVIDERS) {
4890
+ return { providers: strict, bar: OPENROUTER_UPTIME_BAR, contextLength };
4891
+ }
4892
+ const relaxed = atBar(OPENROUTER_UPTIME_BAR_RELAXED);
4893
+ if (relaxed.length > 0) {
4894
+ return { providers: relaxed, bar: OPENROUTER_UPTIME_BAR_RELAXED, contextLength };
4895
+ }
4896
+ return { providers: [], bar: null, contextLength };
4897
+ }
4898
+ function openRouterRoutingFor(providers) {
4899
+ return {
4900
+ only: [...providers],
4901
+ order: [...providers],
4902
+ allow_fallbacks: true,
4903
+ require_parameters: false
4904
+ };
4905
+ }
4906
+ function openRouterRoutingCacheDir(runtimeDir) {
4907
+ return resolve9(runtimeDir, "openrouter-routing");
4908
+ }
4909
+ function cachePath(cacheDir, model) {
4910
+ return resolve9(cacheDir, `${model.replace(/[^A-Za-z0-9._-]+/g, "_")}.json`);
4911
+ }
4912
+ async function readCache(cacheDir, model) {
4913
+ try {
4914
+ const parsed = JSON.parse(await readFile4(cachePath(cacheDir, model), "utf8"));
4915
+ if (!parsed || typeof parsed !== "object")
4916
+ return void 0;
4917
+ const cached = parsed;
4918
+ if (cached.model !== model || typeof cached.fetchedAt !== "number" || !Array.isArray(cached.providers) || !cached.providers.every((provider) => typeof provider === "string" && provider.length > 0)) {
4919
+ return void 0;
4920
+ }
4921
+ return {
4922
+ model,
4923
+ fetchedAt: cached.fetchedAt,
4924
+ providers: cached.providers,
4925
+ bar: typeof cached.bar === "number" ? cached.bar : null
4926
+ };
4927
+ } catch {
4928
+ return void 0;
4929
+ }
4930
+ }
4931
+ async function writeCache(cacheDir, value) {
4932
+ await mkdir2(cacheDir, { recursive: true, mode: 448 });
4933
+ await writeFile3(cachePath(cacheDir, value.model), `${JSON.stringify(value, null, 2)}
4934
+ `, {
4935
+ mode: 384
4936
+ });
4937
+ }
4938
+ function decision(model, providers, bar, source, note) {
4939
+ const criteria = bar === null ? "fallback pair" : `uptime \u2265${bar}%, tools`;
4940
+ const suffix = [
4941
+ bar === OPENROUTER_UPTIME_BAR_RELAXED ? "bar lowered: fewer than 2 providers at 98%" : "",
4942
+ source === "cache" ? "cached" : "",
4943
+ source === "stale-cache" ? "stale cache" : "",
4944
+ note ?? ""
4945
+ ].filter(Boolean).join("; ");
4946
+ return {
4947
+ model,
4948
+ routing: openRouterRoutingFor(providers),
4949
+ providers: [...providers],
4950
+ bar,
4951
+ source,
4952
+ line: `[body] openrouter routing for ${model}: ${providers.join(", ")} (${criteria}` + (suffix ? `; ${suffix})` : ")")
4953
+ };
4954
+ }
4955
+ async function resolveOpenRouterRouting(input) {
4956
+ const now2 = input.now ?? Date.now;
4957
+ const cached = await readCache(input.cacheDir, input.model);
4958
+ if (cached && now2() - cached.fetchedAt < OPENROUTER_ROUTING_CACHE_TTL_MS) {
4959
+ return decision(input.model, cached.providers, cached.bar, "cache");
4960
+ }
4961
+ let failure;
4962
+ try {
4963
+ const doFetch = input.fetchImpl ?? fetch;
4964
+ const response = await doFetch(`${OPENROUTER_ENDPOINTS_BASE_URL}/${input.model}/endpoints`, {
4965
+ signal: AbortSignal.timeout(input.timeoutMs ?? OPENROUTER_ROUTING_FETCH_TIMEOUT_MS)
4966
+ });
4967
+ if (!response.ok)
4968
+ throw new Error(`HTTP ${response.status}`);
4969
+ const { endpoints, contextLength } = parseOpenRouterEndpoints(await response.json());
4970
+ if (endpoints.length === 0)
4971
+ throw new Error("no endpoints listed");
4972
+ const selected = selectReliableOpenRouterProviders(endpoints, contextLength);
4973
+ if (selected.providers.length === 0) {
4974
+ return decision(input.model, OPENROUTER_FALLBACK_PROVIDERS, null, "fallback", "no provider met the bar");
4975
+ }
4976
+ await writeCache(input.cacheDir, {
4977
+ model: input.model,
4978
+ fetchedAt: now2(),
4979
+ providers: selected.providers,
4980
+ bar: selected.bar
4981
+ }).catch(() => void 0);
4982
+ return decision(input.model, selected.providers, selected.bar, "live");
4983
+ } catch (error) {
4984
+ failure = error instanceof Error ? error.message : String(error);
4985
+ }
4986
+ if (cached) {
4987
+ return decision(input.model, cached.providers, cached.bar, "stale-cache", `api unreachable: ${failure}`);
4988
+ }
4989
+ return decision(input.model, OPENROUTER_FALLBACK_PROVIDERS, null, "fallback", `api unreachable: ${failure}`);
4990
+ }
4991
+ function withOpenRouterModelRouting(value, pin) {
4992
+ const root = value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
4993
+ const applyOverride = (provider) => {
4994
+ if (!pin)
4995
+ return provider;
4996
+ const overrides = provider.modelOverrides && typeof provider.modelOverrides === "object" && !Array.isArray(provider.modelOverrides) ? { ...provider.modelOverrides } : {};
4997
+ const existing = overrides[pin.model];
4998
+ const override = existing && typeof existing === "object" && !Array.isArray(existing) ? { ...existing } : {};
4999
+ const compat = override.compat && typeof override.compat === "object" && !Array.isArray(override.compat) ? { ...override.compat } : {};
5000
+ override.compat = { ...compat, openRouterRouting: pin.routing };
5001
+ overrides[pin.model] = override;
5002
+ return { ...provider, modelOverrides: overrides };
5003
+ };
5004
+ if (Array.isArray(root.providers)) {
5005
+ if (!pin)
5006
+ return root;
5007
+ const providers2 = root.providers.map((provider) => provider && typeof provider === "object" ? { ...provider } : provider);
5008
+ const index = providers2.findIndex((provider) => provider && typeof provider === "object" && provider.name === "openrouter");
5009
+ const current = applyOverride(index >= 0 ? providers2[index] : { name: "openrouter" });
5010
+ if (index >= 0)
5011
+ providers2[index] = current;
5012
+ else
5013
+ providers2.push(current);
5014
+ root.providers = providers2;
5015
+ return root;
5016
+ }
5017
+ const providers = root.providers && typeof root.providers === "object" ? { ...root.providers } : {};
5018
+ if (pin) {
5019
+ const current = providers.openrouter && typeof providers.openrouter === "object" && !Array.isArray(providers.openrouter) ? { ...providers.openrouter } : {};
5020
+ providers.openrouter = applyOverride(current);
5021
+ }
5022
+ root.providers = providers;
5023
+ return root;
5024
+ }
5025
+ function openRouterRoutingInput(config, selection, fetchImpl) {
5026
+ const model = openRouterModelId(selection?.model, config.agentEnv);
5027
+ if (!model || !config.openRouterRoutingCacheDir)
5028
+ return {};
5029
+ return {
5030
+ openRouterRouting: {
5031
+ model,
5032
+ cacheDir: config.openRouterRoutingCacheDir,
5033
+ ...fetchImpl ? { fetchImpl } : {}
5034
+ }
5035
+ };
5036
+ }
5037
+
4343
5038
  // apps/body/dist/toml-section.js
4344
5039
  function scanLine(line, openString) {
4345
5040
  if (openString.kind) {
@@ -4523,54 +5218,21 @@ var PI_CUSTOM_MODEL_CONFIG = {
4523
5218
  source: ".pi/agent/models.json",
4524
5219
  target: "models.json"
4525
5220
  };
4526
- var OPENROUTER_RELIABLE_PROVIDERS = ["deepinfra", "novita"];
4527
- function withReliableOpenRouterRouting(value) {
4528
- const root = value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
4529
- const routing = {
4530
- only: [...OPENROUTER_RELIABLE_PROVIDERS],
4531
- order: [...OPENROUTER_RELIABLE_PROVIDERS],
4532
- allow_fallbacks: false,
4533
- require_parameters: true
4534
- };
4535
- if (Array.isArray(root.providers)) {
4536
- const providers2 = root.providers.map((provider) => provider && typeof provider === "object" ? { ...provider } : provider);
4537
- const index = providers2.findIndex((provider) => provider && typeof provider === "object" && provider.name === "openrouter");
4538
- const current2 = index >= 0 ? providers2[index] : { name: "openrouter" };
4539
- const compat2 = current2.compat && typeof current2.compat === "object" && !Array.isArray(current2.compat) ? { ...current2.compat } : {};
4540
- current2.compat = { ...compat2, openRouterRouting: routing };
4541
- if (index >= 0)
4542
- providers2[index] = current2;
4543
- else
4544
- providers2.push(current2);
4545
- root.providers = providers2;
4546
- return root;
4547
- }
4548
- const providers = root.providers && typeof root.providers === "object" ? { ...root.providers } : {};
4549
- const current = providers.openrouter && typeof providers.openrouter === "object" && !Array.isArray(providers.openrouter) ? { ...providers.openrouter } : {};
4550
- const compat = current.compat && typeof current.compat === "object" && !Array.isArray(current.compat) ? { ...current.compat } : {};
4551
- current.compat = {
4552
- ...compat,
4553
- openRouterRouting: routing
4554
- };
4555
- providers.openrouter = current;
4556
- root.providers = providers;
4557
- return root;
4558
- }
4559
5221
  var CODEX_ROOM_AGENT_LOCKDOWN_TOML = "[agents]\nenabled = false\n";
4560
5222
  var CODEX_ROOM_WEB_SEARCH_TOML = "[features]\nstandalone_web_search = true\n";
4561
5223
  var HOME_SUBDIRS = ["user", "claude", "codex", "grok", "pi", "state", "cache", "tmp"];
4562
5224
  async function prepareRoomAgentHome(input) {
4563
- const root = resolve6(input.root);
4564
- const operatorHome = input.operatorHome ?? homedir2();
5225
+ const root = resolve10(input.root);
5226
+ const operatorHome = input.operatorHome ?? homedir3();
4565
5227
  try {
4566
- await mkdir(root, { recursive: true, mode: 448 });
5228
+ await mkdir3(root, { recursive: true, mode: 448 });
4567
5229
  const rootStats = await lstat(root);
4568
5230
  if (!rootStats.isDirectory() || rootStats.isSymbolicLink()) {
4569
5231
  throw new AgentHomeSecurityError(`agent home root is not an ordinary directory: ${root}`);
4570
5232
  }
4571
5233
  for (const subdir of HOME_SUBDIRS) {
4572
- const path = resolve6(root, subdir);
4573
- await mkdir(path, { recursive: true, mode: 448 });
5234
+ const path = resolve10(root, subdir);
5235
+ await mkdir3(path, { recursive: true, mode: 448 });
4574
5236
  await assertRealContainedDirectory(path, root);
4575
5237
  }
4576
5238
  } catch (error) {
@@ -4580,14 +5242,14 @@ async function prepareRoomAgentHome(input) {
4580
5242
  return {};
4581
5243
  }
4582
5244
  for (const credential of SHARED_CREDENTIALS) {
4583
- const source = resolve6(operatorHome, credential.source);
4584
- const target = resolve6(root, credential.dir, credential.target);
5245
+ const source = resolve10(operatorHome, credential.source);
5246
+ const target = resolve10(root, credential.dir, credential.target);
4585
5247
  if (!existsSync3(source) || existsSync3(target))
4586
5248
  continue;
4587
5249
  await symlink(source, target).catch(() => void 0);
4588
5250
  }
4589
5251
  const prior = agentHomeProvisionQueues.get(root) ?? Promise.resolve();
4590
- const provision = prior.catch(() => void 0).then(() => provisionAgentSkillsAndMcp(root, operatorHome, input.skillReleaseId ?? runningBeelineReleaseId(), input.failClosed ?? false, input.sharedSkills ?? []));
5252
+ const provision = prior.catch(() => void 0).then(() => provisionAgentSkillsAndMcp(root, operatorHome, input.skillReleaseId ?? runningBeelineReleaseId(), input.failClosed ?? false, input.sharedSkills ?? [], input.openRouterRouting));
4591
5253
  agentHomeProvisionQueues.set(root, provision);
4592
5254
  try {
4593
5255
  await provision;
@@ -4597,19 +5259,19 @@ async function prepareRoomAgentHome(input) {
4597
5259
  }
4598
5260
  return roomAgentHomeEnv(root);
4599
5261
  }
4600
- async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, failClosed, sharedSkills) {
5262
+ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, failClosed, sharedSkills, openRouterRouting) {
4601
5263
  const managedSkills = [
4602
5264
  { name: USING_BEELINE_SKILL_NAME, content: usingBeelineSkillMarkdown(skillReleaseId) }
4603
5265
  ];
4604
5266
  const shared = await resolveSharedSkillSources(operatorHome, sharedSkills);
4605
5267
  for (const dir of AGENT_SKILL_DIRS) {
4606
- const target = resolve6(root, dir, "skills");
5268
+ const target = resolve10(root, dir, "skills");
4607
5269
  await provisionManagedSkillsDir(target, managedSkills, shared, sharedSkills.length === 0);
4608
5270
  }
4609
5271
  for (const config of HARNESS_MCP_CONFIGS) {
4610
5272
  try {
4611
- const source = resolve6(operatorHome, config.toml);
4612
- const target = resolve6(root, config.dir, "config.toml");
5273
+ const source = resolve10(operatorHome, config.toml);
5274
+ const target = resolve10(root, config.dir, "config.toml");
4613
5275
  const mcpSection = existsSync3(source) ? filteredHarnessMcpToml(readFileSync4(source, "utf8")) : void 0;
4614
5276
  const section = config.dir === "codex" ? [CODEX_ROOM_AGENT_LOCKDOWN_TOML, CODEX_ROOM_WEB_SEARCH_TOML, mcpSection].filter(Boolean).join("\n") : mcpSection;
4615
5277
  if (!section) {
@@ -4624,8 +5286,8 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
4624
5286
  }
4625
5287
  }
4626
5288
  try {
4627
- const claudeJson = resolve6(operatorHome, ".claude.json");
4628
- const claudeTarget = resolve6(root, "claude", ".claude.json");
5289
+ const claudeJson = resolve10(operatorHome, ".claude.json");
5290
+ const claudeTarget = resolve10(root, "claude", ".claude.json");
4629
5291
  const mcpServers = existsSync3(claudeJson) ? readClaudeUserScopeMcpServers(claudeJson) : void 0;
4630
5292
  if (mcpServers && Object.keys(mcpServers).length > 0) {
4631
5293
  await writeIsolatedHarnessFile(claudeTarget, `${JSON.stringify({ mcpServers }, null, 2)}
@@ -4640,22 +5302,28 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
4640
5302
  }
4641
5303
  try {
4642
5304
  const settings2 = { permissions: { allow: ["WebSearch"] } };
4643
- await writeIsolatedHarnessFile(resolve6(root, "claude", "settings.json"), `${JSON.stringify(settings2, null, 2)}
5305
+ await writeIsolatedHarnessFile(resolve10(root, "claude", "settings.json"), `${JSON.stringify(settings2, null, 2)}
4644
5306
  `);
4645
5307
  } catch (error) {
4646
5308
  if (failClosed)
4647
5309
  throw error;
4648
5310
  console.warn("[body] claude web-search settings provisioning failed:", error);
4649
5311
  }
4650
- await provisionPiCustomModelConfig(root, operatorHome, failClosed);
5312
+ await provisionPiCustomModelConfig(root, operatorHome, failClosed, openRouterRouting);
4651
5313
  }
4652
- async function provisionPiCustomModelConfig(root, operatorHome, failClosed) {
4653
- const source = resolve6(operatorHome, PI_CUSTOM_MODEL_CONFIG.source);
4654
- const target = resolve6(root, "pi", PI_CUSTOM_MODEL_CONFIG.target);
5314
+ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, openRouterRouting) {
5315
+ const source = resolve10(operatorHome, PI_CUSTOM_MODEL_CONFIG.source);
5316
+ const target = resolve10(root, "pi", PI_CUSTOM_MODEL_CONFIG.target);
5317
+ let decision2;
5318
+ if (openRouterRouting) {
5319
+ decision2 = await resolveOpenRouterRouting(openRouterRouting);
5320
+ console.log(decision2.line);
5321
+ }
5322
+ const pin = decision2 ? { model: decision2.model, routing: decision2.routing } : void 0;
4655
5323
  try {
4656
5324
  const sourceStats = await lstat(source).catch(() => void 0);
4657
5325
  if (!sourceStats) {
4658
- await writeIsolatedHarnessFile(target, `${JSON.stringify(withReliableOpenRouterRouting({}), null, 2)}
5326
+ await writeIsolatedHarnessFile(target, `${JSON.stringify(withOpenRouterModelRouting({}, pin), null, 2)}
4659
5327
  `);
4660
5328
  return;
4661
5329
  }
@@ -4667,7 +5335,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed) {
4667
5335
  throw new AgentHomeSecurityError(`Pi custom model config resolves through a link: ${source}`);
4668
5336
  }
4669
5337
  const sourceValue = JSON.parse(readFileSync4(resolvedSource, "utf8"));
4670
- await writeIsolatedHarnessFile(target, `${JSON.stringify(withReliableOpenRouterRouting(sourceValue), null, 2)}
5338
+ await writeIsolatedHarnessFile(target, `${JSON.stringify(withOpenRouterModelRouting(sourceValue, pin), null, 2)}
4671
5339
  `);
4672
5340
  } catch (error) {
4673
5341
  await unlink(target).catch(() => void 0);
@@ -4702,16 +5370,16 @@ function filteredHarnessMcpToml(source) {
4702
5370
  return extractTomlSections(source, ["mcp_servers"], excluded);
4703
5371
  }
4704
5372
  async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, optionalShares) {
4705
- const parent = dirname2(target);
4706
- await assertRealContainedDirectory(parent, dirname2(parent));
4707
- const staged = resolve6(parent, `.skills.${process.pid}.${randomUUID()}.tmp`);
4708
- await mkdir(staged, { mode: 448 });
5373
+ const parent = dirname4(target);
5374
+ await assertRealContainedDirectory(parent, dirname4(parent));
5375
+ const staged = resolve10(parent, `.skills.${process.pid}.${randomUUID()}.tmp`);
5376
+ await mkdir3(staged, { mode: 448 });
4709
5377
  const names = new Set(managedSkills.map((skill) => skill.name));
4710
5378
  try {
4711
5379
  for (const skill of managedSkills) {
4712
- const skillDir = resolve6(staged, skill.name);
4713
- await mkdir(skillDir, { recursive: true });
4714
- await writeIsolatedHarnessFile(resolve6(skillDir, "SKILL.md"), skill.content);
5380
+ const skillDir = resolve10(staged, skill.name);
5381
+ await mkdir3(skillDir, { recursive: true });
5382
+ await writeIsolatedHarnessFile(resolve10(skillDir, "SKILL.md"), skill.content);
4715
5383
  }
4716
5384
  for (const shared of sharedSkills) {
4717
5385
  if (names.has(shared.name)) {
@@ -4719,7 +5387,7 @@ async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, op
4719
5387
  }
4720
5388
  names.add(shared.name);
4721
5389
  try {
4722
- await copySafeSkillTree(shared.source, resolve6(staged, shared.name), shared.source);
5390
+ await copySafeSkillTree(shared.source, resolve10(staged, shared.name), shared.source);
4723
5391
  } catch (error) {
4724
5392
  if (!optionalShares)
4725
5393
  throw error;
@@ -4740,20 +5408,20 @@ async function resolveSharedSkillSources(operatorHome, names) {
4740
5408
  const seen = /* @__PURE__ */ new Set();
4741
5409
  const resolved = [];
4742
5410
  for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
4743
- const sourceRoot = resolve6(operatorHome, relativeRoot);
5411
+ const sourceRoot = resolve10(operatorHome, relativeRoot);
4744
5412
  const rootStats = await lstat(sourceRoot).catch(() => void 0);
4745
5413
  if (!rootStats?.isDirectory() || rootStats.isSymbolicLink())
4746
5414
  continue;
4747
5415
  for (const entry of await readdir(sourceRoot)) {
4748
5416
  if (!isSharedSkillName(entry) || seen.has(entry))
4749
5417
  continue;
4750
- const candidate = resolve6(sourceRoot, entry);
5418
+ const candidate = resolve10(sourceRoot, entry);
4751
5419
  try {
4752
5420
  const candidateStats = await lstat(candidate);
4753
5421
  if (!candidateStats.isDirectory() || candidateStats.isSymbolicLink())
4754
5422
  continue;
4755
5423
  assertContained(sourceRoot, candidate);
4756
- const skillMd = resolve6(candidate, "SKILL.md");
5424
+ const skillMd = resolve10(candidate, "SKILL.md");
4757
5425
  const skillStats = await lstat(skillMd);
4758
5426
  if (!skillStats.isFile() || skillStats.isSymbolicLink() || skillStats.nlink !== 1) {
4759
5427
  throw new Error(`shared skill requires an ordinary SKILL.md: ${entry}`);
@@ -4777,8 +5445,8 @@ async function resolveExplicitSkillSources(operatorHome, names) {
4777
5445
  for (const name of unique) {
4778
5446
  const matches = [];
4779
5447
  for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
4780
- const sourceRoot = resolve6(operatorHome, relativeRoot);
4781
- const candidate = resolve6(sourceRoot, name);
5448
+ const sourceRoot = resolve10(operatorHome, relativeRoot);
5449
+ const candidate = resolve10(sourceRoot, name);
4782
5450
  const rootStats = await lstat(sourceRoot).catch(() => void 0);
4783
5451
  const candidateStats = await lstat(candidate).catch(() => void 0);
4784
5452
  if (!candidateStats)
@@ -4795,7 +5463,7 @@ async function resolveExplicitSkillSources(operatorHome, names) {
4795
5463
  if (matches.length !== 1) {
4796
5464
  throw new Error(matches.length === 0 ? `shared skill is unavailable: ${name}` : `shared skill source is ambiguous: ${name}`);
4797
5465
  }
4798
- const skillMd = resolve6(matches[0], "SKILL.md");
5466
+ const skillMd = resolve10(matches[0], "SKILL.md");
4799
5467
  const skillStats = await lstat(skillMd).catch(() => void 0);
4800
5468
  if (!skillStats?.isFile() || skillStats.isSymbolicLink() || skillStats.nlink !== 1) {
4801
5469
  throw new Error(`shared skill requires an ordinary SKILL.md: ${name}`);
@@ -4806,7 +5474,7 @@ async function resolveExplicitSkillSources(operatorHome, names) {
4806
5474
  }
4807
5475
  function assertContained(root, candidate) {
4808
5476
  const rel = relative(root, candidate);
4809
- if (rel === ".." || rel.startsWith(`..${sep}`) || resolve6(root, rel) !== resolve6(candidate)) {
5477
+ if (rel === ".." || rel.startsWith(`..${sep}`) || resolve10(root, rel) !== resolve10(candidate)) {
4810
5478
  throw new Error(`path escapes the agent skill boundary: ${candidate}`);
4811
5479
  }
4812
5480
  }
@@ -4821,7 +5489,7 @@ var BLOCKED_SHARED_FILENAMES = /^(?:\.env(?:\..*)?|auth\.json|\.credentials\.jso
4821
5489
  async function copySafeSkillTree(source, target, sourceRoot) {
4822
5490
  assertContained(sourceRoot, source);
4823
5491
  const resolvedSource = await realpath(source);
4824
- if (resolvedSource !== resolve6(source)) {
5492
+ if (resolvedSource !== resolve10(source)) {
4825
5493
  throw new Error(`shared skill path resolves through a link: ${source}`);
4826
5494
  }
4827
5495
  assertContained(sourceRoot, resolvedSource);
@@ -4832,11 +5500,11 @@ async function copySafeSkillTree(source, target, sourceRoot) {
4832
5500
  throw new Error(`shared skill contains credential or configuration material: ${source}`);
4833
5501
  }
4834
5502
  if (stats.isDirectory()) {
4835
- await mkdir(target, { mode: 448 });
5503
+ await mkdir3(target, { mode: 448 });
4836
5504
  for (const entry of await readdir(resolvedSource)) {
4837
5505
  if (entry === "." || entry === "..")
4838
5506
  throw new Error("invalid shared skill entry");
4839
- await copySafeSkillTree(resolve6(source, entry), resolve6(target, entry), sourceRoot);
5507
+ await copySafeSkillTree(resolve10(source, entry), resolve10(target, entry), sourceRoot);
4840
5508
  }
4841
5509
  return;
4842
5510
  }
@@ -4844,34 +5512,34 @@ async function copySafeSkillTree(source, target, sourceRoot) {
4844
5512
  throw new Error(`shared skill contains a nonordinary file: ${source}`);
4845
5513
  }
4846
5514
  await copyFile(resolvedSource, target);
4847
- await chmod(target, 384);
5515
+ await chmod2(target, 384);
4848
5516
  }
4849
5517
  async function writeIsolatedHarnessFile(path, content) {
4850
- const parent = dirname2(path);
5518
+ const parent = dirname4(path);
4851
5519
  const parentStats = await lstat(parent);
4852
5520
  if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
4853
5521
  throw new Error(`isolated harness parent is not a real directory: ${parent}`);
4854
5522
  }
4855
- const temporary = resolve6(parent, `.${basename3(path)}.${process.pid}.${randomUUID()}.tmp`);
5523
+ const temporary = resolve10(parent, `.${basename3(path)}.${process.pid}.${randomUUID()}.tmp`);
4856
5524
  try {
4857
- await writeFile(temporary, content, { mode: 384, flag: "wx" });
4858
- await chmod(temporary, 384);
5525
+ await writeFile4(temporary, content, { mode: 384, flag: "wx" });
5526
+ await chmod2(temporary, 384);
4859
5527
  await rename(temporary, path);
4860
5528
  } finally {
4861
5529
  await unlink(temporary).catch(() => void 0);
4862
5530
  }
4863
5531
  }
4864
5532
  function roomAgentHomeEnv(root) {
4865
- const resolved = resolve6(root);
5533
+ const resolved = resolve10(root);
4866
5534
  return {
4867
- HOME: resolve6(resolved, "user"),
4868
- CLAUDE_CONFIG_DIR: resolve6(resolved, "claude"),
4869
- CODEX_HOME: resolve6(resolved, "codex"),
4870
- GROK_HOME: resolve6(resolved, "grok"),
4871
- PI_CODING_AGENT_DIR: resolve6(resolved, "pi"),
4872
- XDG_STATE_HOME: resolve6(resolved, "state"),
4873
- XDG_CACHE_HOME: resolve6(resolved, "cache"),
4874
- TMPDIR: resolve6(resolved, "tmp")
5535
+ HOME: resolve10(resolved, "user"),
5536
+ CLAUDE_CONFIG_DIR: resolve10(resolved, "claude"),
5537
+ CODEX_HOME: resolve10(resolved, "codex"),
5538
+ GROK_HOME: resolve10(resolved, "grok"),
5539
+ PI_CODING_AGENT_DIR: resolve10(resolved, "pi"),
5540
+ XDG_STATE_HOME: resolve10(resolved, "state"),
5541
+ XDG_CACHE_HOME: resolve10(resolved, "cache"),
5542
+ TMPDIR: resolve10(resolved, "tmp")
4875
5543
  };
4876
5544
  }
4877
5545
  var HARNESS_STATE_ENV_VARS = [
@@ -4888,14 +5556,14 @@ function harnessStateDirsFromEnv(env) {
4888
5556
  for (const name of HARNESS_STATE_ENV_VARS) {
4889
5557
  const value = env[name];
4890
5558
  if (value)
4891
- stateDirs.push(resolve6(value));
5559
+ stateDirs.push(resolve10(value));
4892
5560
  }
4893
5561
  const tmp = env.TMPDIR;
4894
- return { stateDirs, ...tmp ? { tmpDir: resolve6(tmp) } : {} };
5562
+ return { stateDirs, ...tmp ? { tmpDir: resolve10(tmp) } : {} };
4895
5563
  }
4896
5564
 
4897
5565
  // apps/body/dist/attachment-delivery.js
4898
- import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
5566
+ import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
4899
5567
  import { basename as basename4, extname, join as join2 } from "node:path";
4900
5568
  var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
4901
5569
  var FETCH_TIMEOUT_MS = 3e4;
@@ -4913,7 +5581,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
4913
5581
  if (!attachments.length)
4914
5582
  return [];
4915
5583
  const taken = /* @__PURE__ */ new Set();
4916
- await mkdir2(dir, { recursive: true });
5584
+ await mkdir4(dir, { recursive: true });
4917
5585
  return Promise.all(attachments.map(async (attachment, index) => {
4918
5586
  const tooLarge = (bytes) => ({
4919
5587
  attachment,
@@ -4934,7 +5602,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
4934
5602
  if (bytes.length > MAX_ATTACHMENT_BYTES)
4935
5603
  return tooLarge(bytes.length);
4936
5604
  const path = join2(dir, safeFileName(attachment, index, taken));
4937
- await writeFile2(path, bytes);
5605
+ await writeFile5(path, bytes);
4938
5606
  const mimeType = attachment.mimeType ?? response.headers.get("content-type") ?? "";
4939
5607
  return {
4940
5608
  attachment,
@@ -5046,9 +5714,70 @@ function sanitizeAgentReply(message) {
5046
5714
  }
5047
5715
  return lines.slice(1).join("\n").trim();
5048
5716
  }
5717
+ var CORNER_OPEN_ECHO = /^(?:(?:ok(?:ay)?|done|sure|great|alright)[,.!:]?\s+)?(?:i(?:'ve| have|'ll| will|'m| am)?\s+)?(?:just\s+)?open(?:ed|ing)?\s+(?:up\s+)?(?:a\s+|the\s+|your\s+)?(?:new\s+|write(?:-enabled)?\s+|repository\s+)*corner\b/iu;
5718
+ var CORNER_OPEN_ECHO_MAX_CHARS = 320;
5719
+ function stripCornerOpenEcho(message) {
5720
+ const visible = message.trim();
5721
+ if (!visible)
5722
+ return "";
5723
+ const paragraphs = visible.split(/\n\s*\n/);
5724
+ const first = paragraphs[0].trim();
5725
+ if (first.length > CORNER_OPEN_ECHO_MAX_CHARS || !CORNER_OPEN_ECHO.test(first))
5726
+ return visible;
5727
+ return paragraphs.slice(1).join("\n\n").trim();
5728
+ }
5729
+ var STATUS_FILLER = new Set("a an the this that it its is are was were be been being has have had do does did now still remains remain remaining ready for review reviewing pr pull request all every both and or so to of in on at as with by no not nothing new further more else needed needs need required action actions change changes changed status state update updates updated waiting wait awaiting pending running progress idle done ok okay good great well fine confirmed confirm already again yet just currently right i we will can should would github remote upstream branch head latest current report reported noted note see looks look like everything nothing appears appear seems seem there here which what from without any".split(/\s+/));
5730
+ var STATUS_SYNONYMS = {
5731
+ passed: ["pass", "passed", "passing", "passes", "green", "succeeded", "success", "successful", "successfully"],
5732
+ failed: ["fail", "failed", "failing", "fails", "red", "broke", "broken", "failure", "failures"],
5733
+ check: ["check", "checks", "ci", "run", "runs", "workflow", "workflows", "build", "builds", "test", "tests", "suite"],
5734
+ started: ["start", "started", "starting", "began", "begun", "kicked", "off", "queued"],
5735
+ merged: ["merge", "merged", "merging", "landed", "closed"]
5736
+ };
5737
+ var STATUS_RESTATEMENT_MAX_CHARS = 200;
5738
+ var STATUS_RESTATEMENT_MAX_SENTENCES = 2;
5739
+ function statusWords(text2) {
5740
+ return (text2.toLowerCase().match(/[\p{L}\p{N}'-]+/gu) ?? []).map((word) => word.replace(/^'+|'+$/g, "").replace(/'s$/, ""));
5741
+ }
5742
+ function isCornerStatusRestatement(reply, systemLines) {
5743
+ const text2 = reply.trim();
5744
+ if (!text2)
5745
+ return true;
5746
+ if (text2.length > STATUS_RESTATEMENT_MAX_CHARS)
5747
+ return false;
5748
+ if (/https?:\/\/\S+/i.test(text2))
5749
+ return false;
5750
+ const sentences = text2.split(/[.!?]+(?:\s+|$)/).filter((part) => part.trim());
5751
+ if (sentences.length > STATUS_RESTATEMENT_MAX_SENTENCES)
5752
+ return false;
5753
+ const admitted = new Set(STATUS_FILLER);
5754
+ for (const line of systemLines) {
5755
+ for (const word of statusWords(line)) {
5756
+ admitted.add(word);
5757
+ for (const synonym of STATUS_SYNONYMS[word] ?? [])
5758
+ admitted.add(synonym);
5759
+ }
5760
+ }
5761
+ return statusWords(text2).every((word) => !word || admitted.has(word));
5762
+ }
5763
+
5764
+ // apps/body/dist/turn-failure-reason.js
5765
+ var TURN_FAILURE_REASON_MAX = 200;
5766
+ function redactToolDetail(value) {
5767
+ return value.replace(/\b(["']?)(api[_-]?key|token|secret|password|passwd|authorization|credential|cookie|private[_-]?key)\1\s*[:=]\s*(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,}\]]+)/gi, '"$2": "[REDACTED]"').replace(/\b(?:export\s+)?[A-Za-z_][A-Za-z0-9_]*=(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\S+)/g, (assignment) => `${assignment.slice(0, assignment.indexOf("="))}=[REDACTED]`).replace(/\b(?:gh[pousr]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})\b/gi, "[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\b(Bearer\s+)[^\s,]+/gi, "$1[REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g, "[REDACTED]").replace(/(--?(?:api[_-]?key|token|secret|password|authorization|credential|cookie)\s+)(?:"[^"]*"|'[^']*'|\S+)/gi, "$1[REDACTED]");
5768
+ }
5769
+ function distillTurnFailureReason(error) {
5770
+ const raw = error instanceof Error ? error.message : typeof error === "string" ? error : error && typeof error === "object" && "message" in error ? String(error.message) : error == null ? "" : String(error);
5771
+ const firstLine = raw.split(/\r?\n/).map((line) => line.trim()).find((line) => line && !/^at\s/.test(line)) ?? "";
5772
+ const stripped = firstLine.replace(/^(?:[A-Za-z]*Error|Error):\s*/, "").replace(/\s+/g, " ");
5773
+ const clean4 = redactToolDetail(stripped).trim();
5774
+ if (!clean4)
5775
+ return "turn failed";
5776
+ return clean4.length > TURN_FAILURE_REASON_MAX ? `${clean4.slice(0, TURN_FAILURE_REASON_MAX - 1)}\u2026` : clean4;
5777
+ }
5049
5778
 
5050
5779
  // apps/body/dist/room-session.js
5051
- import { resolve as resolve7 } from "node:path";
5780
+ import { resolve as resolve11 } from "node:path";
5052
5781
 
5053
5782
  // apps/body/dist/read-only-policy.js
5054
5783
  var READ_ONLY_MCP_SERVER_NAME = "beeline-readonly-mcp";
@@ -5180,7 +5909,11 @@ function beelineAgentMcpServer(config, api, context) {
5180
5909
  { name: "BEELINE_DAEMON_ROOM_ID", value: context.roomId },
5181
5910
  { name: "BEELINE_DAEMON_WORKSPACE_ID", value: context.workspaceId },
5182
5911
  ...context.cornerId ? [{ name: "BEELINE_DAEMON_CORNER_ID", value: context.cornerId }] : [],
5183
- ...context.attachRoot ? [{ name: "BEELINE_ATTACH_ROOT", value: context.attachRoot }] : []
5912
+ ...context.attachRoot ? [{ name: "BEELINE_ATTACH_ROOT", value: context.attachRoot }] : [],
5913
+ ...context.grantRunner ? [
5914
+ { name: "BEELINE_GRANT_RUNNER_URL", value: context.grantRunner.url },
5915
+ { name: "BEELINE_GRANT_RUNNER_TOKEN", value: context.grantRunner.token }
5916
+ ] : []
5184
5917
  ]
5185
5918
  };
5186
5919
  }
@@ -5194,14 +5927,14 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
5194
5927
  command: config.readonlyMcpCommand,
5195
5928
  args: [...config.readonlyMcpArgs ?? []],
5196
5929
  env: [
5197
- { name: "BEELINE_READONLY_ROOT", value: resolve7(cwd) },
5930
+ { name: "BEELINE_READONLY_ROOT", value: resolve11(cwd) },
5198
5931
  ...config.agentHomeRoot ? [
5199
5932
  {
5200
5933
  name: "BEELINE_READONLY_AGENT_SKILLS_ROOT",
5201
- value: resolve7(config.agentHomeRoot, skillDir, "skills")
5934
+ value: resolve11(config.agentHomeRoot, skillDir, "skills")
5202
5935
  }
5203
5936
  ] : [],
5204
- ...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value: resolve7(agentMemoryDir) }] : []
5937
+ ...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value: resolve11(agentMemoryDir) }] : []
5205
5938
  ]
5206
5939
  };
5207
5940
  }
@@ -5209,8 +5942,8 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
5209
5942
  // apps/body/dist/bwrap-sandbox.js
5210
5943
  import { spawnSync } from "node:child_process";
5211
5944
  import { lstatSync as lstatSync2 } from "node:fs";
5212
- import { homedir as homedir3 } from "node:os";
5213
- import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve8 } from "node:path";
5945
+ import { homedir as homedir4 } from "node:os";
5946
+ import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve12 } from "node:path";
5214
5947
  var DEFAULT_SANDBOX_POLICY = "bwrap";
5215
5948
  function isSandboxPolicy(value) {
5216
5949
  return value === "bwrap" || value === "off";
@@ -5242,12 +5975,12 @@ var HARNESS_HOME_STATE_DIRS = [
5242
5975
  dirs: [".grok"]
5243
5976
  }
5244
5977
  ];
5245
- function harnessHomeStateDirs(agentCommand, home = homedir3()) {
5978
+ function harnessHomeStateDirs(agentCommand, home = homedir4()) {
5246
5979
  if (!agentCommand)
5247
5980
  return [];
5248
5981
  for (const { match, dirs } of HARNESS_HOME_STATE_DIRS) {
5249
5982
  if (match.test(agentCommand))
5250
- return dirs.map((dir) => resolve8(home, dir));
5983
+ return dirs.map((dir) => resolve12(home, dir));
5251
5984
  }
5252
5985
  return [];
5253
5986
  }
@@ -5259,7 +5992,7 @@ var KNOWN_CREDENTIAL_MASK_PATHS = [
5259
5992
  ".git-credentials",
5260
5993
  ".secrets.env"
5261
5994
  ];
5262
- function credentialMaskPaths(extraPaths, home = homedir3(), stat3 = (path) => {
5995
+ function credentialMaskPaths(extraPaths, home = homedir4(), stat3 = (path) => {
5263
5996
  try {
5264
5997
  const info = lstatSync2(path);
5265
5998
  return { isDirectory: info.isDirectory() };
@@ -5267,10 +6000,10 @@ function credentialMaskPaths(extraPaths, home = homedir3(), stat3 = (path) => {
5267
6000
  return void 0;
5268
6001
  }
5269
6002
  }, requiredPaths = []) {
5270
- const required = new Set(requiredPaths.map((path) => resolve8(path)));
6003
+ const required = new Set(requiredPaths.map((path) => resolve12(path)));
5271
6004
  const candidates = [
5272
- ...KNOWN_CREDENTIAL_MASK_PATHS.map((entry) => resolve8(home, entry)),
5273
- ...(extraPaths ?? []).map((entry) => resolve8(entry))
6005
+ ...KNOWN_CREDENTIAL_MASK_PATHS.map((entry) => resolve12(home, entry)),
6006
+ ...(extraPaths ?? []).map((entry) => resolve12(entry))
5274
6007
  ];
5275
6008
  const seen = /* @__PURE__ */ new Set();
5276
6009
  const masks = [];
@@ -5297,7 +6030,7 @@ function normalize(paths) {
5297
6030
  for (const path of paths) {
5298
6031
  if (!path)
5299
6032
  continue;
5300
- seen.add(resolve8(path));
6033
+ seen.add(resolve12(path));
5301
6034
  }
5302
6035
  return Array.from(seen).sort();
5303
6036
  }
@@ -5335,7 +6068,7 @@ function sandboxMountPlan(spec) {
5335
6068
  writable,
5336
6069
  quotaTmpfs: spec.workbench ? [
5337
6070
  {
5338
- target: resolve8(spec.workbench.dir),
6071
+ target: resolve12(spec.workbench.dir),
5339
6072
  maxBytes: spec.workbench.maxBytes,
5340
6073
  maxInodes: spec.workbench.maxInodes,
5341
6074
  blockGit: true
@@ -5390,7 +6123,7 @@ function buildBwrapArgv(input) {
5390
6123
  for (const binding of quotaTmpfs) {
5391
6124
  args.push("--dir", binding.target, "--size", String(binding.maxBytes), "--tmpfs", binding.target);
5392
6125
  if (binding.blockGit)
5393
- args.push("--ro-bind", "/dev/null", resolve8(binding.target, ".git"));
6126
+ args.push("--ro-bind", "/dev/null", resolve12(binding.target, ".git"));
5394
6127
  }
5395
6128
  args.push("--chdir", input.cwd);
5396
6129
  args.push("--die-with-parent");
@@ -5454,13 +6187,176 @@ function detectBwrapSandbox(options = {}) {
5454
6187
  };
5455
6188
  }
5456
6189
 
6190
+ // apps/body/dist/pi-turn-record.js
6191
+ import { readdir as readdir2, readFile as readFile5 } from "node:fs/promises";
6192
+ import { resolve as resolve13 } from "node:path";
6193
+ function summarizeProviderError(errorMessage2) {
6194
+ const trimmed = errorMessage2.trim();
6195
+ const statusMatch = /^(\d{3}):\s*([\s\S]*)$/.exec(trimmed);
6196
+ const status = statusMatch ? Number(statusMatch[1]) : void 0;
6197
+ let body = statusMatch ? statusMatch[2].trim() : trimmed;
6198
+ if (body.startsWith("{")) {
6199
+ try {
6200
+ const parsed = JSON.parse(body);
6201
+ const message = typeof parsed.message === "string" ? parsed.message : typeof parsed.error === "string" ? parsed.error : typeof parsed.error?.message === "string" ? parsed.error.message : void 0;
6202
+ if (message)
6203
+ body = message;
6204
+ } catch {
6205
+ }
6206
+ }
6207
+ const firstLine = body.split(/\r?\n/).find((line) => line.trim()) ?? "";
6208
+ const reason = `provider error${status === void 0 ? "" : ` ${status}`}${firstLine ? `: ${firstLine.trim()}` : ""}`;
6209
+ return status === void 0 ? { reason } : { reason, status };
6210
+ }
6211
+ async function sessionFileFromMap(home, sessionId) {
6212
+ try {
6213
+ const raw = await readFile5(resolve13(home, ".pi", "pi-acp", "session-map.json"), "utf8");
6214
+ const map = JSON.parse(raw);
6215
+ const file = map.sessions?.[sessionId]?.sessionFile;
6216
+ return typeof file === "string" && file ? file : void 0;
6217
+ } catch {
6218
+ return void 0;
6219
+ }
6220
+ }
6221
+ async function sessionFileFromLayout(piDir, sessionId) {
6222
+ const sessionsRoot = resolve13(piDir, "sessions");
6223
+ const suffix = `_${sessionId}.jsonl`;
6224
+ let projects;
6225
+ try {
6226
+ projects = await readdir2(sessionsRoot);
6227
+ } catch {
6228
+ return void 0;
6229
+ }
6230
+ for (const project of projects) {
6231
+ const dir = resolve13(sessionsRoot, project);
6232
+ let files;
6233
+ try {
6234
+ files = await readdir2(dir);
6235
+ } catch {
6236
+ continue;
6237
+ }
6238
+ const match = files.find((file) => file.endsWith(suffix));
6239
+ if (match)
6240
+ return resolve13(dir, match);
6241
+ }
6242
+ return void 0;
6243
+ }
6244
+ function messageText(content) {
6245
+ if (!Array.isArray(content))
6246
+ return "";
6247
+ return content.map((block2) => block2 && typeof block2 === "object" && block2.type === "text" ? String(block2.text ?? "") : "").join("").trim();
6248
+ }
6249
+ async function readPiTurnRecord(input) {
6250
+ const piDir = input.agentEnv.PI_CODING_AGENT_DIR;
6251
+ if (!piDir || !input.sessionId)
6252
+ return void 0;
6253
+ const file = (input.agentEnv.HOME ? await sessionFileFromMap(input.agentEnv.HOME, input.sessionId) : void 0) ?? await sessionFileFromLayout(piDir, input.sessionId);
6254
+ if (!file)
6255
+ return void 0;
6256
+ let raw;
6257
+ try {
6258
+ raw = await readFile5(file, "utf8");
6259
+ } catch {
6260
+ return void 0;
6261
+ }
6262
+ let sawUser = false;
6263
+ let last;
6264
+ for (const line of raw.split(/\r?\n/)) {
6265
+ if (!line.trim())
6266
+ continue;
6267
+ let entry;
6268
+ try {
6269
+ entry = JSON.parse(line);
6270
+ } catch {
6271
+ continue;
6272
+ }
6273
+ if (entry.type !== "message" || !entry.message)
6274
+ continue;
6275
+ if (entry.message.role === "user") {
6276
+ sawUser = true;
6277
+ last = void 0;
6278
+ } else if (entry.message.role === "assistant") {
6279
+ last = entry.message;
6280
+ }
6281
+ }
6282
+ if (!sawUser && !last)
6283
+ return void 0;
6284
+ if (!last)
6285
+ return { kind: "missing" };
6286
+ if (last.stopReason === "error") {
6287
+ return {
6288
+ kind: "error",
6289
+ ...summarizeProviderError(typeof last.errorMessage === "string" && last.errorMessage.trim() ? last.errorMessage : "unknown error")
6290
+ };
6291
+ }
6292
+ const text2 = messageText(last.content);
6293
+ if (text2)
6294
+ return { kind: "answer", text: text2 };
6295
+ return {
6296
+ kind: "empty",
6297
+ stopReason: typeof last.stopReason === "string" ? last.stopReason : "unknown"
6298
+ };
6299
+ }
6300
+
6301
+ // apps/body/dist/empty-turn.js
6302
+ async function explainEmptyAgentTurn(input) {
6303
+ const streamFact = describeEmptyTurn(input.result, input.agentLabel);
6304
+ if (!isPiAcpHarness(input.agentLabel))
6305
+ return { reason: streamFact };
6306
+ const record2 = await readPiTurnRecord({ agentEnv: input.agentEnv, sessionId: input.sessionId });
6307
+ if (!record2)
6308
+ return { reason: `pi left no readable turn record; ${streamFact}` };
6309
+ switch (record2.kind) {
6310
+ case "error":
6311
+ return { reason: record2.reason, record: record2 };
6312
+ case "empty":
6313
+ return {
6314
+ reason: `the model ended its turn with no text (stop reason ${record2.stopReason})`,
6315
+ record: record2
6316
+ };
6317
+ case "answer":
6318
+ return {
6319
+ recoveredText: record2.text,
6320
+ reason: "pi recorded the answer but the ACP stream delivered no text",
6321
+ record: record2
6322
+ };
6323
+ case "missing":
6324
+ return { reason: `pi recorded no assistant message for this turn; ${streamFact}`, record: record2 };
6325
+ }
6326
+ }
6327
+ function isAccountOrProviderRefusal(record2) {
6328
+ if (!record2 || record2.kind !== "error" || record2.status === void 0)
6329
+ return false;
6330
+ return [401, 402, 403, 407, 408, 429].includes(record2.status) || record2.status >= 500;
6331
+ }
6332
+
6333
+ // apps/body/dist/corner-checks.js
6334
+ var COMPLETED_CHECK_NOTE = /\b(passed|failed) a check\b/i;
6335
+ var STARTED_CHECK_NOTE = /\bstarted a check\b/i;
6336
+ function verbOf(item) {
6337
+ return item.systemEvent?.verb ?? item.body;
6338
+ }
6339
+ function completedCheckNote(item) {
6340
+ if (item.type !== "system")
6341
+ return void 0;
6342
+ const match = COMPLETED_CHECK_NOTE.exec(verbOf(item));
6343
+ return match ? match[1].toLowerCase() : void 0;
6344
+ }
6345
+ function isCheckStartNote(item) {
6346
+ return item.type === "system" && STARTED_CHECK_NOTE.test(verbOf(item));
6347
+ }
6348
+ function checksStateFromLifecycle(lifecycle) {
6349
+ const state = lifecycle?.checksSummary?.status ?? lifecycle?.checks;
6350
+ return state === "passing" || state === "failing" || state === "pending" ? state : void 0;
6351
+ }
6352
+
5457
6353
  // apps/body/dist/runtime.js
5458
- import { randomBytes as randomBytes5 } from "node:crypto";
5459
- import { execFile } from "node:child_process";
6354
+ import { randomBytes as randomBytes6 } from "node:crypto";
6355
+ import { execFile as execFile2 } from "node:child_process";
5460
6356
  import { closeSync, openSync } from "node:fs";
5461
- import { mkdir as mkdir3, readFile, readdir as readdir2, rename as rename2, stat, writeFile as writeFile3 } from "node:fs/promises";
5462
- import { homedir as homedir4 } from "node:os";
5463
- import { dirname as dirname3, resolve as resolve9 } from "node:path";
6357
+ import { mkdir as mkdir5, readFile as readFile6, readdir as readdir3, rename as rename2, stat, writeFile as writeFile6 } from "node:fs/promises";
6358
+ import { homedir as homedir5 } from "node:os";
6359
+ import { dirname as dirname5, resolve as resolve14 } from "node:path";
5464
6360
  import { spawn as spawn2 } from "node:child_process";
5465
6361
  import { promisify } from "node:util";
5466
6362
 
@@ -5608,7 +6504,7 @@ function createHasher(hashCons, info = {}) {
5608
6504
  Object.assign(hashC, info);
5609
6505
  return Object.freeze(hashC);
5610
6506
  }
5611
- function randomBytes(bytesLength = 32) {
6507
+ function randomBytes2(bytesLength = 32) {
5612
6508
  anumber(bytesLength, "bytesLength");
5613
6509
  const cr = typeof globalThis === "object" ? globalThis.crypto : null;
5614
6510
  if (typeof cr?.getRandomValues !== "function")
@@ -5926,7 +6822,7 @@ var bytesToHex2 = bytesToHex;
5926
6822
  var concatBytes2 = (...arrays) => concatBytes(...arrays);
5927
6823
  var hexToBytes2 = (hex) => hexToBytes(hex);
5928
6824
  var isBytes2 = isBytes;
5929
- var randomBytes2 = (bytesLength) => randomBytes(bytesLength);
6825
+ var randomBytes3 = (bytesLength) => randomBytes2(bytesLength);
5930
6826
  var _0n = /* @__PURE__ */ BigInt(0);
5931
6827
  var _1n = /* @__PURE__ */ BigInt(1);
5932
6828
  var atitle2 = (title) => title ? `"${title}" ` : "";
@@ -6518,18 +7414,18 @@ function validateTableBytes(numPoints, fpBytes) {
6518
7414
  if (bytes > TABLE_BYTES_MAX)
6519
7415
  throw new Error("invalid window size: table would need ~" + Math.ceil(bytes / 2 ** 20) + " MiB, max " + TABLE_BYTES_MAX / 2 ** 20 + " MiB");
6520
7416
  }
6521
- function probeRandomBytes(randomBytes6, length) {
6522
- if (randomBytes6 === void 0)
7417
+ function probeRandomBytes(randomBytes7, length) {
7418
+ if (randomBytes7 === void 0)
6523
7419
  return void 0;
6524
- afunction(randomBytes6, "randomBytes");
7420
+ afunction(randomBytes7, "randomBytes");
6525
7421
  try {
6526
- const probe = randomBytes6(length);
7422
+ const probe = randomBytes7(length);
6527
7423
  if (!isBytes2(probe) || probe.length !== length)
6528
7424
  return void 0;
6529
7425
  } catch {
6530
7426
  return void 0;
6531
7427
  }
6532
- return randomBytes6;
7428
+ return randomBytes7;
6533
7429
  }
6534
7430
  function validateMSMPoints(points, c2) {
6535
7431
  aarray(points, "points");
@@ -6622,9 +7518,9 @@ var ScalarMultiplier = class {
6622
7518
  baseCanBeBlinded;
6623
7519
  bits;
6624
7520
  // Parametrized with a given Point class (not individual point)
6625
- constructor(Point, randomBytes6) {
7521
+ constructor(Point, randomBytes7) {
6626
7522
  validatePointCons(Point);
6627
- this.randomBytes = probeRandomBytes(randomBytes6, BLIND_BYTES);
7523
+ this.randomBytes = probeRandomBytes(randomBytes7, BLIND_BYTES);
6628
7524
  this.Point = Point;
6629
7525
  this.BASE = Point.BASE;
6630
7526
  this.ZERO = Point.ZERO;
@@ -6912,7 +7808,7 @@ function weierstrass(params, extraOpts = {}) {
6912
7808
  randomBytes: "function"
6913
7809
  });
6914
7810
  const { endo, allowInfinityPoint } = extraOpts;
6915
- const randomBytes6 = extraOpts.randomBytes === void 0 ? randomBytes2 : extraOpts.randomBytes;
7811
+ const randomBytes7 = extraOpts.randomBytes === void 0 ? randomBytes3 : extraOpts.randomBytes;
6916
7812
  if (endo) {
6917
7813
  if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
6918
7814
  throw new Error('invalid endo: expected "beta": bigint and "basises": array');
@@ -7324,7 +8220,7 @@ function weierstrass(params, extraOpts = {}) {
7324
8220
  }
7325
8221
  }
7326
8222
  const normalize2 = (points) => normalizeZ(Point, points);
7327
- const wnaf = new ScalarMultiplier(Point, randomBytes6);
8223
+ const wnaf = new ScalarMultiplier(Point, randomBytes7);
7328
8224
  if (wnaf.bits >= 6)
7329
8225
  Point.BASE.precompute(6);
7330
8226
  Object.freeze(Point.prototype);
@@ -7433,7 +8329,7 @@ function challenge(...args) {
7433
8329
  function schnorrGetPublicKey(secretKey) {
7434
8330
  return schnorrGetExtPubKey(secretKey).bytes;
7435
8331
  }
7436
- function schnorrSign(message, secretKey, auxRand = randomBytes(32)) {
8332
+ function schnorrSign(message, secretKey, auxRand = randomBytes2(32)) {
7437
8333
  const { Fn, BASE } = Pointk1;
7438
8334
  const m2 = abytes2(message, void 0, "message");
7439
8335
  const { bytes: px, scalar: d } = schnorrGetExtPubKey(secretKey);
@@ -7483,7 +8379,7 @@ var schnorr = /* @__PURE__ */ (() => {
7483
8379
  const size = 32;
7484
8380
  const seedLength = 48;
7485
8381
  const randomSecretKey = (seed) => {
7486
- seed = seed === void 0 ? randomBytes(seedLength) : seed;
8382
+ seed = seed === void 0 ? randomBytes2(seedLength) : seed;
7487
8383
  return mapHashToField(abytes2(seed, seedLength, "seed"), secp256k1_CURVE.n);
7488
8384
  };
7489
8385
  return Object.freeze({
@@ -7630,7 +8526,7 @@ function createHasher2(hashCons, info = {}) {
7630
8526
  Object.assign(hashC, info);
7631
8527
  return Object.freeze(hashC);
7632
8528
  }
7633
- function randomBytes3(bytesLength = 32) {
8529
+ function randomBytes4(bytesLength = 32) {
7634
8530
  const cr = typeof globalThis === "object" ? globalThis.crypto : null;
7635
8531
  if (typeof cr?.getRandomValues !== "function")
7636
8532
  throw new Error("crypto.getRandomValues must be defined");
@@ -9326,7 +10222,7 @@ function getWLengths2(Fp, Fn) {
9326
10222
  }
9327
10223
  function ecdh(Point, ecdhOpts = {}) {
9328
10224
  const { Fn } = Point;
9329
- const randomBytes_ = ecdhOpts.randomBytes || randomBytes3;
10225
+ const randomBytes_ = ecdhOpts.randomBytes || randomBytes4;
9330
10226
  const lengths = Object.assign(getWLengths2(Point.Fp, Fn), { seed: getMinHashLength2(Fn.ORDER) });
9331
10227
  function isValidSecretKey(secretKey) {
9332
10228
  try {
@@ -9391,7 +10287,7 @@ function ecdsa2(Point, hash, ecdsaOpts = {}) {
9391
10287
  bits2int_modN: "function"
9392
10288
  });
9393
10289
  ecdsaOpts = Object.assign({}, ecdsaOpts);
9394
- const randomBytes6 = ecdsaOpts.randomBytes || randomBytes3;
10290
+ const randomBytes7 = ecdsaOpts.randomBytes || randomBytes4;
9395
10291
  const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
9396
10292
  const { Fp, Fn } = Point;
9397
10293
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
@@ -9533,7 +10429,7 @@ function ecdsa2(Point, hash, ecdsaOpts = {}) {
9533
10429
  throw new Error("invalid private key");
9534
10430
  const seedArgs = [int2octets(d), int2octets(h1int)];
9535
10431
  if (extraEntropy != null && extraEntropy !== false) {
9536
- const e = extraEntropy === true ? randomBytes6(lengths.secretKey) : extraEntropy;
10432
+ const e = extraEntropy === true ? randomBytes7(lengths.secretKey) : extraEntropy;
9537
10433
  seedArgs.push(abytes3(e, void 0, "extraEntropy"));
9538
10434
  }
9539
10435
  const seed = concatBytes3(...seedArgs);
@@ -9700,7 +10596,7 @@ function challenge2(...args) {
9700
10596
  function schnorrGetPublicKey2(secretKey) {
9701
10597
  return schnorrGetExtPubKey2(secretKey).bytes;
9702
10598
  }
9703
- function schnorrSign2(message, secretKey, auxRand = randomBytes3(32)) {
10599
+ function schnorrSign2(message, secretKey, auxRand = randomBytes4(32)) {
9704
10600
  const { Fn } = Pointk12;
9705
10601
  const m2 = abytes3(message, void 0, "message");
9706
10602
  const { bytes: px, scalar: d } = schnorrGetExtPubKey2(secretKey);
@@ -9742,7 +10638,7 @@ function schnorrVerify2(signature, message, publicKey) {
9742
10638
  var schnorr2 = /* @__PURE__ */ (() => {
9743
10639
  const size = 32;
9744
10640
  const seedLength = 48;
9745
- const randomSecretKey = (seed = randomBytes3(seedLength)) => {
10641
+ const randomSecretKey = (seed = randomBytes4(seedLength)) => {
9746
10642
  return mapHashToField2(seed, secp256k1_CURVE2.n);
9747
10643
  };
9748
10644
  return {
@@ -12106,7 +13002,7 @@ function encrypt2(secretKey, pubkey, text2) {
12106
13002
  const privkey = secretKey instanceof Uint8Array ? secretKey : hexToBytes3(secretKey);
12107
13003
  const key = secp256k1.getSharedSecret(privkey, hexToBytes3("02" + pubkey));
12108
13004
  const normalizedKey = getNormalizedX(key);
12109
- let iv = Uint8Array.from(randomBytes3(16));
13005
+ let iv = Uint8Array.from(randomBytes4(16));
12110
13006
  let plaintext = utf8Encoder.encode(text2);
12111
13007
  let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext);
12112
13008
  let ctb64 = base64.encode(new Uint8Array(ciphertext));
@@ -12477,7 +13373,7 @@ function decodePayload(payload) {
12477
13373
  mac: data.subarray(-32)
12478
13374
  };
12479
13375
  }
12480
- function encrypt22(plaintext, conversationKey, nonce = randomBytes3(32)) {
13376
+ function encrypt22(plaintext, conversationKey, nonce = randomBytes4(32)) {
12481
13377
  const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);
12482
13378
  const padded = pad(plaintext);
12483
13379
  const ciphertext = chacha20(chacha_key, chacha_nonce, padded);
@@ -13992,23 +14888,23 @@ function decodeNsec(nsec) {
13992
14888
  }
13993
14889
 
13994
14890
  // apps/body/dist/runtime.js
13995
- var execFileAsync = promisify(execFile);
14891
+ var execFileAsync = promisify(execFile2);
13996
14892
  var DEFAULT_AGENT_IDENTITY_NAME = "beeline-agent";
13997
14893
  var DEFAULT_BODY_IDENTITY_NAME = "beeline-body";
13998
14894
  var DEFAULT_DAEMON_MONOLITH_BASE_URL = "https://server.usebeeline.app";
13999
14895
  function defaultSupervisorRoot(env = process.env) {
14000
- return resolve9(env.XDG_STATE_HOME ?? resolve9(homedir4(), ".local", "state"));
14896
+ return resolve14(env.XDG_STATE_HOME ?? resolve14(homedir5(), ".local", "state"));
14001
14897
  }
14002
14898
  function runtimeDirectory(supervisorRoot, publicKey) {
14003
14899
  if (!/^[0-9a-f]{64}$/i.test(publicKey))
14004
14900
  throw new Error("invalid agent public key");
14005
- return resolve9(supervisorRoot, "beeline", "agents", publicKey.toLowerCase());
14901
+ return resolve14(supervisorRoot, "beeline", "agents", publicKey.toLowerCase());
14006
14902
  }
14007
14903
  function runtimeConfigPath(supervisorRoot, publicKey) {
14008
- return resolve9(runtimeDirectory(supervisorRoot, publicKey), "runtime.json");
14904
+ return resolve14(runtimeDirectory(supervisorRoot, publicKey), "runtime.json");
14009
14905
  }
14010
14906
  function identityFromKey(value, name) {
14011
- const secretKey = value ? value.startsWith("nsec1") ? decodeNsec(value) : Uint8Array.from(Buffer.from(value, "hex")) : randomBytes5(32);
14907
+ const secretKey = value ? value.startsWith("nsec1") ? decodeNsec(value) : Uint8Array.from(Buffer.from(value, "hex")) : randomBytes6(32);
14012
14908
  if (secretKey.length !== 32)
14013
14909
  throw new Error("identity secret key must be 32 bytes");
14014
14910
  return { name, secretKey, publicKey: getPublicKey2(secretKey) };
@@ -14035,15 +14931,15 @@ function runtimeAgentCommand(runtime) {
14035
14931
  }
14036
14932
  async function writeRuntimeRecord(runtime) {
14037
14933
  const path = runtimeConfigPath(runtime.supervisorRoot, runtime.agent.publicKey);
14038
- await mkdir3(dirname3(path), { recursive: true, mode: 448 });
14934
+ await mkdir5(dirname5(path), { recursive: true, mode: 448 });
14039
14935
  const staged = `${path}.${process.pid}.tmp`;
14040
- await writeFile3(staged, `${JSON.stringify(runtime, null, 2)}
14936
+ await writeFile6(staged, `${JSON.stringify(runtime, null, 2)}
14041
14937
  `, { mode: 384 });
14042
14938
  await rename2(staged, path);
14043
14939
  return path;
14044
14940
  }
14045
14941
  async function readRuntimeRecord(path) {
14046
- const parsed = JSON.parse(await readFile(path, "utf8"));
14942
+ const parsed = JSON.parse(await readFile6(path, "utf8"));
14047
14943
  if (parsed.version !== 2 || !parsed.agent || !parsed.body || !parsed.communityId) {
14048
14944
  throw new Error(`invalid agent runtime record: ${path}`);
14049
14945
  }
@@ -14061,7 +14957,7 @@ async function migrateRuntimeRecordAccessPolicy(path) {
14061
14957
  return { runtime, migrated: true };
14062
14958
  }
14063
14959
  async function stageMonolithAgentRuntime(input) {
14064
- const supervisorRoot = input.supervisorRoot ? resolve9(input.supervisorRoot) : defaultSupervisorRoot();
14960
+ const supervisorRoot = input.supervisorRoot ? resolve14(input.supervisorRoot) : defaultSupervisorRoot();
14065
14961
  const configPath = runtimeConfigPath(supervisorRoot, input.agentIdentity.publicKey);
14066
14962
  const configuredBaseUrl = input.monolithBaseUrl ?? DEFAULT_DAEMON_MONOLITH_BASE_URL;
14067
14963
  const baseUrl = new URL(configuredBaseUrl).origin;
@@ -14106,9 +15002,9 @@ async function stageMonolithAgentRuntime(input) {
14106
15002
  return { runtime, configPath };
14107
15003
  }
14108
15004
  async function runtimePaths(root) {
14109
- const agents = resolve9(root, "beeline", "agents");
14110
- const entries = await readdir2(agents, { withFileTypes: true }).catch(() => []);
14111
- return entries.filter((entry) => entry.isDirectory()).map((entry) => resolve9(agents, entry.name, "runtime.json"));
15005
+ const agents = resolve14(root, "beeline", "agents");
15006
+ const entries = await readdir3(agents, { withFileTypes: true }).catch(() => []);
15007
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => resolve14(agents, entry.name, "runtime.json"));
14112
15008
  }
14113
15009
  async function findAgentRuntimeConfigPaths(env = process.env, _cwd = process.cwd()) {
14114
15010
  return runtimePaths(defaultSupervisorRoot(env));
@@ -14117,13 +15013,13 @@ async function findRuntimeConfigPaths(cwd = process.cwd(), env = process.env) {
14117
15013
  return findAgentRuntimeConfigPaths(env, cwd);
14118
15014
  }
14119
15015
  async function resolveRuntimeConfigPath(path) {
14120
- return resolve9(path);
15016
+ return resolve14(path);
14121
15017
  }
14122
15018
  async function selectRuntimeConfigPaths(options) {
14123
15019
  const hostScope = true;
14124
15020
  const configs = await options.findHostRuntimes(options.cwd);
14125
15021
  const requestedPubkey = options.requestedPubkey;
14126
- const paths = requestedPubkey ? configs.filter((path) => dirname3(path).endsWith(requestedPubkey)) : [...new Set(configs)];
15022
+ const paths = requestedPubkey ? configs.filter((path) => dirname5(path).endsWith(requestedPubkey)) : [...new Set(configs)];
14127
15023
  if (!paths.length)
14128
15024
  throw new Error(options.noRuntimeMessage(hostScope));
14129
15025
  if (options.requestedPubkey && paths.length > 1)
@@ -14132,7 +15028,7 @@ async function selectRuntimeConfigPaths(options) {
14132
15028
  }
14133
15029
  async function runtimeDaemonPid(configPath) {
14134
15030
  try {
14135
- const pid = Number((await readFile(resolve9(dirname3(configPath), "daemon.pid"), "utf8")).trim());
15031
+ const pid = Number((await readFile6(resolve14(dirname5(configPath), "daemon.pid"), "utf8")).trim());
14136
15032
  if (!Number.isSafeInteger(pid) || pid <= 0)
14137
15033
  return null;
14138
15034
  process.kill(pid, 0);
@@ -14143,13 +15039,13 @@ async function runtimeDaemonPid(configPath) {
14143
15039
  }
14144
15040
  async function daemonIsThisRuntime(pid, configPath) {
14145
15041
  try {
14146
- const argv = (await readFile(`/proc/${pid}/cmdline`, "utf8")).split("\0").filter(Boolean);
15042
+ const argv = (await readFile6(`/proc/${pid}/cmdline`, "utf8")).split("\0").filter(Boolean);
14147
15043
  const flag = argv.lastIndexOf("--config");
14148
- return flag > 0 && argv[flag - 1] === "daemon" && resolve9(argv[flag + 1]) === resolve9(configPath);
15044
+ return flag > 0 && argv[flag - 1] === "daemon" && resolve14(argv[flag + 1]) === resolve14(configPath);
14149
15045
  } catch {
14150
15046
  try {
14151
15047
  const { stdout: stdout6 } = await execFileAsync("ps", ["-p", String(pid), "-o", "command="]);
14152
- return stdout6.includes(" daemon ") && stdout6.includes(resolve9(configPath));
15048
+ return stdout6.includes(" daemon ") && stdout6.includes(resolve14(configPath));
14153
15049
  } catch {
14154
15050
  return false;
14155
15051
  }
@@ -14175,14 +15071,14 @@ async function stopRuntimeDaemon(path, opts = {}) {
14175
15071
  throw new Error(`agent daemon ${pid} did not stop after ${timeout}ms`);
14176
15072
  }
14177
15073
  async function launchRuntimeDaemon(configPath, opts = {}) {
14178
- const directory = dirname3(configPath);
14179
- await mkdir3(directory, { recursive: true, mode: 448 });
15074
+ const directory = dirname5(configPath);
15075
+ await mkdir5(directory, { recursive: true, mode: 448 });
14180
15076
  const foreground = opts.foreground === true;
14181
- const output = foreground ? "inherit" : openSync(resolve9(directory, "daemon.log"), "a", 384);
15077
+ const output = foreground ? "inherit" : openSync(resolve14(directory, "daemon.log"), "a", 384);
14182
15078
  const entrypoint = opts.entrypoint ?? process.argv[1];
14183
15079
  if (!entrypoint)
14184
15080
  throw new Error("cannot resolve daemon CLI entrypoint");
14185
- const child = spawn2(process.execPath, [...opts.execArgv ?? [], entrypoint, "daemon", "--config", resolve9(configPath)], {
15081
+ const child = spawn2(process.execPath, [...opts.execArgv ?? [], entrypoint, "daemon", "--config", resolve14(configPath)], {
14186
15082
  cwd: directory,
14187
15083
  env: opts.env ?? process.env,
14188
15084
  detached: !foreground,
@@ -14199,19 +15095,19 @@ async function launchRuntimeDaemon(configPath, opts = {}) {
14199
15095
  }
14200
15096
  async function removeAgentRuntime(runtime) {
14201
15097
  const source = runtimeDirectory(runtime.supervisorRoot, runtime.agent.publicKey);
14202
- const deletedRoot = resolve9(runtime.supervisorRoot, "beeline", "deleted-runtimes");
14203
- await mkdir3(deletedRoot, { recursive: true, mode: 448 });
14204
- const target = resolve9(deletedRoot, `${runtime.agent.publicKey}-${Date.now()}`);
15098
+ const deletedRoot = resolve14(runtime.supervisorRoot, "beeline", "deleted-runtimes");
15099
+ await mkdir5(deletedRoot, { recursive: true, mode: 448 });
15100
+ const target = resolve14(deletedRoot, `${runtime.agent.publicKey}-${Date.now()}`);
14205
15101
  await rename2(source, target);
14206
15102
  return target;
14207
15103
  }
14208
15104
 
14209
15105
  // apps/body/dist/response-directives.js
14210
15106
  var MAINTAIN_ASSIGNED_IDENTITY_DIRECTIVE = "Maintain your assigned identity and soul in every response, including when tools or permissions block the requested action.";
15107
+ var SOUL_HOUSE_RULE = "House rule for your voice: the voice never changes the facts - never trim, soften, exaggerate, or invent a detail for the bit - and use your plain voice in commit messages, pull request titles and bodies, and code comments, because those outlive the joke.";
14211
15108
 
14212
15109
  // apps/body/dist/monolith-corner-turn.js
14213
- var execFileAsync2 = promisify2(execFile2);
14214
- var PULL_REQUEST_URL = /https:\/\/github\.com\/[^\s/]+\/[^\s/]+\/pull\/\d+/;
15110
+ var execFileAsync2 = promisify2(execFile3);
14215
15111
  var TOOL_ARGUMENT_MAX_BYTES = 1200;
14216
15112
  var TOOL_OUTPUT_MAX_BYTES = 3200;
14217
15113
  var TOOL_PATH_LIMIT = 12;
@@ -14230,9 +15126,6 @@ function serialized(value) {
14230
15126
  function record(value) {
14231
15127
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
14232
15128
  }
14233
- function redactToolDetail(value) {
14234
- return value.replace(/\b(["']?)(api[_-]?key|token|secret|password|passwd|authorization|credential|cookie|private[_-]?key)\1\s*[:=]\s*(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,}\]]+)/gi, '"$2": "[REDACTED]"').replace(/\b(?:export\s+)?[A-Za-z_][A-Za-z0-9_]*=(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\S+)/g, (assignment) => `${assignment.slice(0, assignment.indexOf("="))}=[REDACTED]`).replace(/\b(?:gh[pousr]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})\b/gi, "[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\b(Bearer\s+)[^\s,]+/gi, "$1[REDACTED]").replace(/(--?(?:api[_-]?key|token|secret|password|authorization|credential|cookie)\s+)(?:"[^"]*"|'[^']*'|\S+)/gi, "$1[REDACTED]");
14235
- }
14236
15129
  function clampBytes(value, maxBytes) {
14237
15130
  const clean4 = value.trim();
14238
15131
  if (Buffer.byteLength(clean4) <= maxBytes)
@@ -14313,7 +15206,7 @@ function isSuccessfulCommit(call) {
14313
15206
  return false;
14314
15207
  return /\bgit\s+commit\b|\bcommit(?:ted)?\s+(?:changes|files?)\b/i.test(`${call.title ?? ""} ${serialized(call.rawInput)}`);
14315
15208
  }
14316
- async function cornerToolActivity(call, worktreePath) {
15209
+ async function cornerToolActivity(call, worktreePath, requestedBy) {
14317
15210
  const operation = oneLine(call.kind ?? "") || "tool";
14318
15211
  let title = oneLine(redactToolDetail(call.title ?? "")) || `${operation} tool`;
14319
15212
  if (isSuccessfulCommit(call)) {
@@ -14336,6 +15229,7 @@ async function cornerToolActivity(call, worktreePath) {
14336
15229
  status: resultStatus(call),
14337
15230
  ...argumentsSummary,
14338
15231
  ...output ? { output } : {},
15232
+ ...requestedBy ? { requestedBy } : {},
14339
15233
  ...paths.length ? { files: paths.map((path) => ({ path })) } : {}
14340
15234
  };
14341
15235
  }
@@ -14348,6 +15242,8 @@ var MonolithCornerTurnLoop = class {
14348
15242
  agent;
14349
15243
  client;
14350
15244
  sessionId;
15245
+ /** The live session's environment, read back for pi's own turn record. */
15246
+ agentEnv = {};
14351
15247
  turnIdentityInstructions = "";
14352
15248
  busy = false;
14353
15249
  forcedStop = false;
@@ -14355,9 +15251,19 @@ var MonolithCornerTurnLoop = class {
14355
15251
  activityTail = Promise.resolve();
14356
15252
  /** Session scratch directory attachments are downloaded into (`TMPDIR/beeline-attachments`). */
14357
15253
  attachmentDir;
15254
+ /** The turn in flight and who asked for it, for ledger rows and the grant runner. */
15255
+ currentTurn;
15256
+ memberNames = /* @__PURE__ */ new Map();
15257
+ /** The last server check state that started a turn; the same state never starts another. */
15258
+ lastChecksState;
14358
15259
  constructor(options) {
14359
15260
  this.options = options;
14360
15261
  this.agent = runtimeIdentity(options.runtime.agent);
15262
+ options.grantRunner?.register(options.cornerId, {
15263
+ workspaceId: options.workspaceId,
15264
+ cwd: options.worktreePath,
15265
+ turn: () => this.currentTurn
15266
+ });
14361
15267
  }
14362
15268
  isBusy() {
14363
15269
  return this.busy;
@@ -14376,11 +15282,13 @@ var MonolithCornerTurnLoop = class {
14376
15282
  this.client.sessionCancel(this.sessionId);
14377
15283
  await this.options.scheduler.forceSuspend(this.options.cornerId);
14378
15284
  }
14379
- roster() {
14380
- return this.options.api.execute("getWorkspaceRoster", {
15285
+ async roster() {
15286
+ const roster = await this.options.api.execute("getWorkspaceRoster", {
14381
15287
  agentId: this.agent.publicKey,
14382
15288
  workspaceId: this.options.workspaceId
14383
15289
  });
15290
+ this.memberNames = new Map(roster.members.map((member) => [member.identityId, member.name]));
15291
+ return roster;
14384
15292
  }
14385
15293
  async activate() {
14386
15294
  if (this.client?.isAlive && this.sessionId)
@@ -14392,30 +15300,32 @@ var MonolithCornerTurnLoop = class {
14392
15300
  }),
14393
15301
  this.roster()
14394
15302
  ]);
14395
- await mkdir4(this.options.worktreePath, { recursive: true });
15303
+ await mkdir6(this.options.worktreePath, { recursive: true });
15304
+ const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
14396
15305
  const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
14397
15306
  root: this.options.config.agentHomeRoot,
14398
15307
  sharedSkills: this.options.config.sharedSkills ?? [],
14399
- ...this.options.config.operatorHome ? { operatorHome: this.options.config.operatorHome } : {}
15308
+ ...this.options.config.operatorHome ? { operatorHome: this.options.config.operatorHome } : {},
15309
+ ...openRouterRoutingInput(this.options.config, selection, this.options.fetchImpl)
14400
15310
  }) : {};
14401
15311
  const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
14402
- const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
14403
15312
  const agentEnv = {
14404
15313
  ...this.options.config.agentEnv,
14405
15314
  ...homeOverlay,
14406
15315
  GH_TOKEN: this.options.githubToken,
14407
15316
  GITHUB_TOKEN: this.options.githubToken
14408
15317
  };
15318
+ this.agentEnv = agentEnv;
14409
15319
  const agentArgs = agentArgsWithModelSelection({
14410
15320
  kind: this.options.config.agentKind,
14411
15321
  command,
14412
15322
  args: this.options.config.agentArgs ?? []
14413
15323
  }, selection);
14414
- const operatorHome = this.options.config.operatorHome ?? homedir5();
15324
+ const operatorHome = this.options.config.operatorHome ?? homedir6();
14415
15325
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
14416
15326
  this.attachmentDir = tmpDir ? join4(tmpDir, "beeline-attachments") : void 0;
14417
15327
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
14418
- await Promise.all(homeStateDirs.map((dir) => mkdir4(dir, { recursive: true })));
15328
+ await Promise.all(homeStateDirs.map((dir) => mkdir6(dir, { recursive: true })));
14419
15329
  const spawnCommand = wrapAgentCommand({
14420
15330
  bwrapPath: this.options.config.bwrapPath,
14421
15331
  spec: {
@@ -14461,13 +15371,17 @@ var MonolithCornerTurnLoop = class {
14461
15371
  roomId: this.options.parentRoomId,
14462
15372
  workspaceId: this.options.workspaceId,
14463
15373
  cornerId: this.options.cornerId,
14464
- attachRoot: this.options.worktreePath
15374
+ attachRoot: this.options.worktreePath,
15375
+ ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
14465
15376
  })
14466
15377
  ];
14467
15378
  const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
14468
15379
  const persona = configuration.soul ?? self?.soul;
14469
15380
  const identityInstructions = `Your Beeline identity is ${self?.name ?? this.agent.name}.`;
14470
- const personaInstructions = persona?.instructions ? `Human-authored Workspace persona: ${persona.name}. ${persona.instructions}` : "";
15381
+ const personaInstructions = [
15382
+ ...persona?.instructions ? [`Human-authored Workspace persona: ${persona.name}. ${persona.instructions}`] : [],
15383
+ SOUL_HOUSE_RULE
15384
+ ].join("\n");
14471
15385
  this.turnIdentityInstructions = harnessHonorsSessionSystemPrompt(command) ? "" : [identityInstructions, personaInstructions].filter(Boolean).join("\n\n");
14472
15386
  const opened = await this.client.sessionNew({
14473
15387
  cwd: this.options.worktreePath,
@@ -14483,6 +15397,7 @@ var MonolithCornerTurnLoop = class {
14483
15397
  "Merge the PR yourself only after the checks-passed event shows every check green; if any check failed or is still running, say exactly which and stop - never merge red.",
14484
15398
  "If any human in this corner says hold or do not merge, do not merge until a later human explicitly resumes it.",
14485
15399
  "Do not tag the user when a corner turn finishes: the server posts the merge summary card and its push already cover completion. Tag a human only mid-turn, and only when you need a decision or input.",
15400
+ 'GitHub check and merge notes are server lines already in the corner: never restate them (no "checks passed", "CI is green", "PR ready for review"). On a checks turn, say nothing unless you act - a merge or a pushed fix - and then one short line about that.',
14486
15401
  "A human approval in the app asks the server to merge. When approval is pending, wait for the server close request instead of racing it with gh. If checks passed, no hold exists, and no approval is pending, merge the pull request yourself with gh.",
14487
15402
  "Never push directly to the target branch. Never merge a different pull request."
14488
15403
  ].filter(Boolean).join("\n\n")
@@ -14506,8 +15421,14 @@ var MonolithCornerTurnLoop = class {
14506
15421
  }
14507
15422
  };
14508
15423
  }
14509
- async prompt(requestId, trigger, attachments = []) {
15424
+ async prompt(requestId, trigger, attachments = [], requestedById, restates) {
14510
15425
  const { api, cornerId } = this.options;
15426
+ const spoken = (text2) => restates && isCornerStatusRestatement(text2, restates) ? "" : text2;
15427
+ const requester = requestedById ? {
15428
+ pubkey: requestedById,
15429
+ ...this.memberNames.get(requestedById) ? { name: this.memberNames.get(requestedById) } : {}
15430
+ } : void 0;
15431
+ this.currentTurn = { requestId, ...requester ? { requester } : {} };
14511
15432
  await api.execute("postAgentTurnReceipt", {
14512
15433
  agentId: this.agent.publicKey,
14513
15434
  roomId: cornerId,
@@ -14526,6 +15447,9 @@ var MonolithCornerTurnLoop = class {
14526
15447
  this.attachmentDir && attachments.length ? deliverAttachments(attachments, join4(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : Promise.resolve([])
14527
15448
  ]);
14528
15449
  const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
15450
+ const requestedBy = requester && !requester.name && names.get(requester.pubkey) ? { ...requester, name: names.get(requester.pubkey) } : requester;
15451
+ if (requestedBy)
15452
+ this.currentTurn = { requestId, requester: requestedBy };
14529
15453
  const transcript = conversation.items.slice(-120).map((message) => `${names.get(message.authorId) ?? "Beeline"} [${message.type}]: ${message.body}`).join("\n");
14530
15454
  const prompt = [
14531
15455
  this.turnIdentityInstructions,
@@ -14557,7 +15481,7 @@ ${trigger}`, ...attachmentPromptLines(attachments, delivered)].join("\n"),
14557
15481
  const start = narrationPostedChars;
14558
15482
  narrationPostedChars = segmentEnd;
14559
15483
  narrationSegments += 1;
14560
- const trimmed = segment.trim();
15484
+ const trimmed = spoken(segment.trim());
14561
15485
  if (!trimmed)
14562
15486
  return;
14563
15487
  this.activityTail = this.activityTail.catch(() => void 0).then(async () => {
@@ -14578,7 +15502,7 @@ ${trigger}`, ...attachmentPromptLines(attachments, delivered)].join("\n"),
14578
15502
  return;
14579
15503
  publishedToolCalls.add(key);
14580
15504
  this.activityTail = this.activityTail.catch(() => void 0).then(async () => {
14581
- const activity = await cornerToolActivity(call, this.options.worktreePath);
15505
+ const activity = await cornerToolActivity(call, this.options.worktreePath, requestedBy);
14582
15506
  await api.execute("postAgentActivity", {
14583
15507
  agentId: this.agent.publicKey,
14584
15508
  roomId: cornerId,
@@ -14605,10 +15529,21 @@ ${trigger}`, ...attachmentPromptLines(attachments, delivered)].join("\n"),
14605
15529
  await this.activityTail;
14606
15530
  await this.draftTail;
14607
15531
  await this.activityTail;
14608
- const reply = stripAgentReplyPreamble(result.agentText).trim();
14609
- if (!reply)
14610
- throw new Error("ACP corner turn produced no durable reply");
14611
- const durableTail = narrationPostedChars > 0 ? stripAgentReplyPreamble(result.agentText.slice(narrationPostedChars)).trim() : reply;
15532
+ let reply = stripAgentReplyPreamble(result.agentText).trim();
15533
+ if (!reply) {
15534
+ const explained = await explainEmptyAgentTurn({
15535
+ agentLabel: this.options.config.agentCommand ?? this.options.config.agentBinary,
15536
+ agentEnv: this.agentEnv,
15537
+ sessionId,
15538
+ result
15539
+ });
15540
+ reply = explained.recoveredText ? stripAgentReplyPreamble(explained.recoveredText).trim() : "";
15541
+ if (!reply && !(restates && !isAccountOrProviderRefusal(explained.record))) {
15542
+ throw new Error(explained.reason);
15543
+ }
15544
+ console.warn(`[thin-core] corner ${cornerId} turn ${requestId}: ${explained.reason}`);
15545
+ }
15546
+ const durableTail = spoken(narrationPostedChars > 0 ? stripAgentReplyPreamble(result.agentText.slice(narrationPostedChars)).trim() : reply);
14612
15547
  if (durableTail) {
14613
15548
  await api.execute("postRoomMessage", {
14614
15549
  roomId: cornerId,
@@ -14617,17 +15552,6 @@ ${trigger}`, ...attachmentPromptLines(attachments, delivered)].join("\n"),
14617
15552
  presentation: "message"
14618
15553
  });
14619
15554
  }
14620
- const pullRequest = reply.match(PULL_REQUEST_URL)?.[0];
14621
- const alreadyReady = conversation.items.some((item) => /\bPR ready for review\b/i.test(item.body));
14622
- if (pullRequest && !alreadyReady) {
14623
- await api.execute("postRoomMessage", {
14624
- roomId: cornerId,
14625
- requestId,
14626
- text: `PR ready for review
14627
- ${pullRequest}`,
14628
- presentation: "system"
14629
- });
14630
- }
14631
15555
  await api.execute("retractAgentLiveOutput", {
14632
15556
  agentId: this.agent.publicKey,
14633
15557
  roomId: cornerId,
@@ -14648,12 +15572,28 @@ ${pullRequest}`,
14648
15572
  roomId: cornerId,
14649
15573
  requestId,
14650
15574
  status: "failed",
14651
- generationId: `${this.agent.publicKey}:${cornerId}`
15575
+ generationId: `${this.agent.publicKey}:${cornerId}`,
15576
+ reason: distillTurnFailureReason(error)
14652
15577
  });
14653
15578
  throw error;
14654
15579
  } finally {
14655
15580
  this.busy = false;
15581
+ this.currentTurn = void 0;
15582
+ }
15583
+ }
15584
+ /** The server's check state for this head, or the notes' own verdict when the server carries none. */
15585
+ async checksState(notes) {
15586
+ try {
15587
+ const restore = await this.options.api.execute("getCornerRestoreState", {
15588
+ cornerId: this.options.cornerId
15589
+ });
15590
+ const fromServer = checksStateFromLifecycle(restore.lifecycle);
15591
+ if (fromServer)
15592
+ return fromServer;
15593
+ } catch (error) {
15594
+ console.error(`[thin-core] corner ${this.options.cornerId} check state read failed:`, error);
14656
15595
  }
15596
+ return notes.some((note) => completedCheckNote(note) === "failed") ? "failing" : "passing";
14657
15597
  }
14658
15598
  async run() {
14659
15599
  const { api, cornerId, signal } = this.options;
@@ -14675,6 +15615,7 @@ ${pullRequest}`,
14675
15615
  await this.options.onCloseRequested();
14676
15616
  return;
14677
15617
  }
15618
+ const checkNotes = [];
14678
15619
  for (const item of inbox.items) {
14679
15620
  if (item.type === "message") {
14680
15621
  if (item.authorId === this.agent.publicKey)
@@ -14685,12 +15626,30 @@ ${pullRequest}`,
14685
15626
  });
14686
15627
  if (!authority.member || authority.principalKind !== "human")
14687
15628
  continue;
14688
- await this.prompt(item.id, item.body, item.attachments);
15629
+ await this.prompt(item.id, item.body, item.attachments, item.authorId);
15630
+ pollWithoutWait = true;
15631
+ continue;
15632
+ }
15633
+ const grantDecision = item.type === "system" && item.mentionIds.includes(this.agent.publicKey) && parseGrantDecisionLine(item.body) !== void 0;
15634
+ if (grantDecision) {
15635
+ await this.prompt(item.id, `${item.body}
15636
+ This answers your grant request; resume the paused work. If approved and it is a command grant, run it with run_granted_command and the exact argv; if declined, try another way or say what you cannot do.`, [], item.authorId);
14689
15637
  pollWithoutWait = true;
14690
15638
  continue;
14691
15639
  }
14692
- if (/\bchecks?\b/i.test(item.body)) {
14693
- await this.prompt(item.id, item.body);
15640
+ if (isCheckStartNote(item)) {
15641
+ this.lastChecksState = void 0;
15642
+ continue;
15643
+ }
15644
+ if (completedCheckNote(item))
15645
+ checkNotes.push(item);
15646
+ }
15647
+ if (checkNotes.length) {
15648
+ const state = await this.checksState(checkNotes);
15649
+ if (state && state !== "pending" && state !== this.lastChecksState) {
15650
+ this.lastChecksState = state;
15651
+ const lines = checkNotes.map((note) => note.body);
15652
+ await this.prompt(checkNotes[checkNotes.length - 1].id, lines.join("\n"), [], void 0, lines);
14694
15653
  pollWithoutWait = true;
14695
15654
  }
14696
15655
  }
@@ -14707,6 +15666,7 @@ ${pullRequest}`,
14707
15666
  }
14708
15667
  }
14709
15668
  } finally {
15669
+ this.options.grantRunner?.unregister(cornerId);
14710
15670
  await this.options.scheduler.suspend(cornerId);
14711
15671
  }
14712
15672
  }
@@ -14726,13 +15686,13 @@ async function wait(ms, signal) {
14726
15686
  }
14727
15687
 
14728
15688
  // apps/body/dist/monolith-room-turn.js
14729
- import { mkdir as mkdir5 } from "node:fs/promises";
14730
- import { homedir as homedir6 } from "node:os";
15689
+ import { mkdir as mkdir7 } from "node:fs/promises";
15690
+ import { homedir as homedir7 } from "node:os";
14731
15691
  import { join as join5 } from "node:path";
14732
15692
 
14733
15693
  // packages/api-contract/dist/scheduled-prompts.js
14734
15694
  var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
14735
- var SCHEDULED_PROMPT_PREFIX = "Scheduled: ";
15695
+ var SCHEDULE_RAN_VERB = "ran a schedule for";
14736
15696
 
14737
15697
  // apps/body/dist/monolith-room-turn.js
14738
15698
  function isRoomMcpPermissionRequest(request) {
@@ -14744,14 +15704,25 @@ function roomPrincipalMayAddressAgent(authority, humanPermitted) {
14744
15704
  return authority.member && (authority.principalKind === "agent" || authority.principalKind === "human" && humanPermitted);
14745
15705
  }
14746
15706
  function isScheduledPrompt(item, agentId) {
14747
- return item.type === "system" && item.body.startsWith(SCHEDULED_PROMPT_PREFIX) && item.mentionIds.includes(agentId);
15707
+ return item.type === "system" && item.systemEvent?.verb === SCHEDULE_RAN_VERB && item.mentionIds.includes(agentId);
15708
+ }
15709
+ function inboxItemPromptBody(item, agentId) {
15710
+ return isScheduledPrompt(item, agentId) ? item.systemEvent?.consequence ?? item.body : item.body;
15711
+ }
15712
+ function isGrantDecisionLine(item, agentId) {
15713
+ return item.type === "system" && item.mentionIds.includes(agentId) && parseGrantDecisionLine(item.body) !== void 0;
14748
15714
  }
14749
15715
  function inboxItemTriggersTurn(item, agentId) {
14750
15716
  if (item.authorId === agentId)
14751
15717
  return false;
14752
15718
  if (!item.mentionIds.includes(agentId))
14753
15719
  return false;
14754
- return item.type === "message" || isScheduledPrompt(item, agentId);
15720
+ return item.type === "message" || isScheduledPrompt(item, agentId) || isGrantDecisionLine(item, agentId);
15721
+ }
15722
+ function pendingGrantToolCall(call) {
15723
+ if (!/(?:^|[._:/-])request_grant$/i.test(call.title ?? ""))
15724
+ return false;
15725
+ return /pending, card posted/i.test(typeof call.content === "string" ? call.content : JSON.stringify(call.content ?? ""));
14755
15726
  }
14756
15727
  function escapeRegExp(value) {
14757
15728
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -14789,6 +15760,8 @@ var MonolithRoomTurnLoop = class {
14789
15760
  agent;
14790
15761
  client;
14791
15762
  sessionId;
15763
+ /** The live session's environment, read back for pi's own turn record. */
15764
+ agentEnv = {};
14792
15765
  busy = false;
14793
15766
  turnInstructionPrefix = "";
14794
15767
  draftTail = Promise.resolve();
@@ -14798,13 +15771,36 @@ var MonolithRoomTurnLoop = class {
14798
15771
  attachmentDir;
14799
15772
  /** Local copies already delivered this session, by message id, so transcript renders reuse them. */
14800
15773
  deliveredAttachments = /* @__PURE__ */ new Map();
15774
+ /** Names from the latest roster read, for ledger bylines the runner writes. */
15775
+ memberNames = /* @__PURE__ */ new Map();
15776
+ /** The request id of the turn that paused on a grant card, until its decision arrives. */
15777
+ pausedOnGrantRequestId;
14801
15778
  constructor(options) {
14802
15779
  this.options = options;
14803
15780
  this.agent = runtimeIdentity(options.runtime.agent);
15781
+ options.grantRunner?.register(options.roomId, {
15782
+ workspaceId: options.workspaceId,
15783
+ cwd: options.cwd,
15784
+ turn: () => this.currentTurnForRunner()
15785
+ });
14804
15786
  }
14805
15787
  isBusy() {
14806
15788
  return this.busy;
14807
15789
  }
15790
+ /** The turn a `request_grant` paused, if any (cleared when its decision resumes it). */
15791
+ pausedGrantRequestId() {
15792
+ return this.pausedOnGrantRequestId;
15793
+ }
15794
+ currentTurnForRunner() {
15795
+ const active = this.activeTurn;
15796
+ if (!active)
15797
+ return void 0;
15798
+ return { requestId: active.item.id, requester: this.requesterOf(active.item.authorId) };
15799
+ }
15800
+ requesterOf(authorId) {
15801
+ const name = this.memberNames.get(authorId);
15802
+ return { pubkey: authorId, ...name ? { name } : {} };
15803
+ }
14808
15804
  currentPrincipalCanDrive(_workspaceId, principalId) {
14809
15805
  return Promise.resolve(isSenderPermitted(this.options.config.accessPolicy ?? LEGACY_ACCESS_POLICY, principalId, this.options.config.accessOwnerPubkey, this.options.config.accessAllowlist));
14810
15806
  }
@@ -14818,11 +15814,13 @@ var MonolithRoomTurnLoop = class {
14818
15814
  this.client.sessionCancel(this.sessionId);
14819
15815
  await this.options.scheduler.forceSuspend(this.options.roomId);
14820
15816
  }
14821
- roster() {
14822
- return this.options.api.execute("getWorkspaceRoster", {
15817
+ async roster() {
15818
+ const roster = await this.options.api.execute("getWorkspaceRoster", {
14823
15819
  agentId: this.agent.publicKey,
14824
15820
  workspaceId: this.options.workspaceId
14825
15821
  });
15822
+ this.memberNames = new Map(roster.members.map((member) => [member.identityId, member.name]));
15823
+ return roster;
14826
15824
  }
14827
15825
  /** Download a message's attachments into the session scratch directory once. */
14828
15826
  async deliver(item) {
@@ -14847,25 +15845,27 @@ var MonolithRoomTurnLoop = class {
14847
15845
  this.options.api.execute("getRoomRepositoryState", { roomId: this.options.roomId })
14848
15846
  ]);
14849
15847
  const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
14850
- await mkdir5(this.options.cwd, { recursive: true });
15848
+ await mkdir7(this.options.cwd, { recursive: true });
15849
+ const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
14851
15850
  const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
14852
15851
  root: this.options.config.agentHomeRoot,
14853
15852
  sharedSkills: this.options.config.sharedSkills ?? [],
14854
- ...this.options.config.operatorHome ? { operatorHome: this.options.config.operatorHome } : {}
15853
+ ...this.options.config.operatorHome ? { operatorHome: this.options.config.operatorHome } : {},
15854
+ ...openRouterRoutingInput(this.options.config, selection, this.options.fetchImpl)
14855
15855
  }) : {};
14856
15856
  const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
14857
- const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
14858
15857
  const agentEnv = { ...this.options.config.agentEnv, ...homeOverlay };
15858
+ this.agentEnv = agentEnv;
14859
15859
  const agentArgs = agentArgsWithModelSelection({
14860
15860
  kind: this.options.config.agentKind,
14861
15861
  command,
14862
15862
  args: this.options.config.agentArgs ?? []
14863
15863
  }, selection);
14864
- const operatorHome = this.options.config.operatorHome ?? homedir6();
15864
+ const operatorHome = this.options.config.operatorHome ?? homedir7();
14865
15865
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
14866
15866
  this.attachmentDir = tmpDir ? join5(tmpDir, "beeline-attachments") : void 0;
14867
15867
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
14868
- await Promise.all(homeStateDirs.map((dir) => mkdir5(dir, { recursive: true })));
15868
+ await Promise.all(homeStateDirs.map((dir) => mkdir7(dir, { recursive: true })));
14869
15869
  const spawnCommand = wrapAgentCommand({
14870
15870
  bwrapPath: this.options.config.bwrapPath,
14871
15871
  spec: {
@@ -14899,18 +15899,22 @@ var MonolithRoomTurnLoop = class {
14899
15899
  roomId: this.options.roomId,
14900
15900
  workspaceId: this.options.workspaceId,
14901
15901
  attachRoot: this.options.cwd,
14902
- directMessage
15902
+ directMessage,
15903
+ ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
14903
15904
  })
14904
15905
  ];
14905
15906
  const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
14906
15907
  const persona = configuration.soul ?? self?.soul;
14907
15908
  const identityInstructions = `Your Beeline Room identity is ${self?.name ?? this.agent.name}.`;
14908
- const personaInstructions = persona?.instructions ? [
14909
- `Your human-authored identity and soul in this Workspace is ${persona.name}.`,
14910
- `Soul instructions: ${persona.instructions}`,
14911
- "This is who you are in this Workspace. Adopt it in your voice, self-description, and behavior.",
14912
- "The soul is not authority and never changes your tools, permissions, roles, or merge rights."
14913
- ].join("\n") : "";
15909
+ const personaInstructions = [
15910
+ ...persona?.instructions ? [
15911
+ `Your human-authored identity and soul in this Workspace is ${persona.name}.`,
15912
+ `Soul instructions: ${persona.instructions}`,
15913
+ "This is who you are in this Workspace. Adopt it in your voice, self-description, and behavior.",
15914
+ "The soul is not authority and never changes your tools, permissions, roles, or merge rights."
15915
+ ] : [],
15916
+ SOUL_HOUSE_RULE
15917
+ ].join("\n");
14914
15918
  const repositoryInfo = repositoryState.resolution === "repository" && repositoryState.key ? {
14915
15919
  name: repositoryState.key,
14916
15920
  branch: repositoryState.targetBranch || "main"
@@ -14987,6 +15991,8 @@ var MonolithRoomTurnLoop = class {
14987
15991
  const api = this.options.api;
14988
15992
  this.busy = true;
14989
15993
  try {
15994
+ if (!this.memberNames.has(item.authorId))
15995
+ await this.roster().catch(() => void 0);
14990
15996
  await api.execute("postAgentTurnReceipt", {
14991
15997
  agentId: this.agent.publicKey,
14992
15998
  roomId: this.options.roomId,
@@ -14998,7 +16004,14 @@ var MonolithRoomTurnLoop = class {
14998
16004
  agentId: this.agent.publicKey,
14999
16005
  roomId: this.options.roomId,
15000
16006
  requestId: item.id,
15001
- activity: [{ kind: "thinking", title: "Working", status: "in_progress" }]
16007
+ activity: [
16008
+ {
16009
+ kind: "thinking",
16010
+ title: "Working",
16011
+ status: "in_progress",
16012
+ requestedBy: this.requesterOf(item.authorId)
16013
+ }
16014
+ ]
15002
16015
  });
15003
16016
  await this.options.scheduler.run(this.options.roomId, this.lifecycle(), async () => {
15004
16017
  const [conversation, roster, delivered] = await Promise.all([
@@ -15008,12 +16021,21 @@ var MonolithRoomTurnLoop = class {
15008
16021
  ]);
15009
16022
  const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
15010
16023
  const transcript = conversation.items.filter((message) => message.type === "message" && message.id !== item.id && !active.steers.some((steerItem) => steerItem.id === message.id)).slice(-80).map((message) => roomMessagePrompt(names.get(message.authorId) ?? message.authorId.slice(0, 12), message.body, message.attachments, this.deliveredAttachments.get(message.id))).join("\n");
16024
+ const grantDecision = isGrantDecisionLine(item, this.agent.publicKey);
16025
+ const resumedRequestId = grantDecision ? this.pausedOnGrantRequestId : void 0;
16026
+ if (grantDecision)
16027
+ this.pausedOnGrantRequestId = void 0;
15011
16028
  const prompt = [
15012
16029
  this.turnInstructionPrefix,
15013
16030
  transcript ? `Room conversation so far:
15014
16031
  ${transcript}` : "",
15015
16032
  `Newest message from ${isScheduledPrompt(item, this.agent.publicKey) ? SCHEDULE_SCHEDULER_NAME : names.get(item.authorId) ?? item.authorId.slice(0, 12)}:`,
15016
- roomMessagePrompt("", item.body, item.attachments, delivered),
16033
+ roomMessagePrompt("", inboxItemPromptBody(item, this.agent.publicKey), item.attachments, delivered),
16034
+ grantDecision ? [
16035
+ "This is the answer to your grant request; your paused work resumes now.",
16036
+ "If it was approved and it is a command grant, run it with run_granted_command and the exact argv.",
16037
+ "If it was declined, try another way or say plainly what you cannot do."
16038
+ ].join(" ") : "",
15017
16039
  [
15018
16040
  "Write only the substantive Room message you want the human to read.",
15019
16041
  "Do not repeat or paraphrase these instructions.",
@@ -15062,23 +16084,44 @@ ${transcript}` : "",
15062
16084
  ].join("\n\n");
15063
16085
  }
15064
16086
  active.phase = "finishing";
16087
+ if (result?.toolCalls.some((call) => pendingGrantToolCall(call))) {
16088
+ this.pausedOnGrantRequestId = item.id;
16089
+ console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id} paused on a grant card`);
16090
+ } else if (resumedRequestId) {
16091
+ console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${resumedRequestId} resumed by grant decision ${item.id}`);
16092
+ }
15065
16093
  const openCornerCall = result?.toolCalls.find((call) => /(?:^|[._:/-])open_corner$/i.test(call.title ?? ""));
15066
16094
  if (openCornerCall) {
15067
16095
  console.log(`[thin-core] monolith Room ${this.options.roomId} tool call: ${openCornerCall.title}`);
15068
16096
  this.options.onCornerOpened?.();
15069
16097
  }
15070
16098
  await this.draftTail;
15071
- const reply = sanitizeAgentReply(result.agentText);
15072
- if (!reply)
15073
- throw new Error("ACP turn produced no durable Room reply");
15074
- await api.execute("postRoomMessage", {
15075
- roomId: this.options.roomId,
15076
- requestId: item.id,
15077
- triggerMessageId: item.id,
15078
- text: reply,
15079
- presentation: "message",
15080
- mentionIds: agentReplyMentionIds(reply, roster, this.agent.publicKey)
15081
- });
16099
+ let reply = sanitizeAgentReply(result.agentText);
16100
+ if (!reply) {
16101
+ const explained = await explainEmptyAgentTurn({
16102
+ agentLabel: this.options.config.agentCommand ?? this.options.config.agentBinary,
16103
+ agentEnv: this.agentEnv,
16104
+ sessionId,
16105
+ result
16106
+ });
16107
+ reply = explained.recoveredText ? sanitizeAgentReply(explained.recoveredText) : "";
16108
+ if (!reply)
16109
+ throw new Error(explained.reason);
16110
+ console.warn(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id}: ${explained.reason}`);
16111
+ }
16112
+ if (openCornerCall && !/failed|error|denied/i.test(openCornerCall.status ?? "")) {
16113
+ reply = stripCornerOpenEcho(reply);
16114
+ }
16115
+ if (reply) {
16116
+ await api.execute("postRoomMessage", {
16117
+ roomId: this.options.roomId,
16118
+ requestId: item.id,
16119
+ triggerMessageId: item.id,
16120
+ text: reply,
16121
+ presentation: "message",
16122
+ mentionIds: agentReplyMentionIds(reply, roster, this.agent.publicKey)
16123
+ });
16124
+ }
15082
16125
  await api.execute("retractAgentLiveOutput", {
15083
16126
  agentId: this.agent.publicKey,
15084
16127
  roomId: this.options.roomId,
@@ -15099,7 +16142,8 @@ ${transcript}` : "",
15099
16142
  roomId: this.options.roomId,
15100
16143
  requestId: item.id,
15101
16144
  status: "failed",
15102
- generationId: `${this.agent.publicKey}:${this.options.roomId}`
16145
+ generationId: `${this.agent.publicKey}:${this.options.roomId}`,
16146
+ reason: distillTurnFailureReason(error)
15103
16147
  });
15104
16148
  throw error;
15105
16149
  } finally {
@@ -15138,7 +16182,7 @@ ${transcript}` : "",
15138
16182
  for (const item of inbox.items) {
15139
16183
  if (!inboxItemTriggersTurn(item, this.agent.publicKey))
15140
16184
  continue;
15141
- if (!isScheduledPrompt(item, this.agent.publicKey)) {
16185
+ if (!isScheduledPrompt(item, this.agent.publicKey) && !isGrantDecisionLine(item, this.agent.publicKey)) {
15142
16186
  const authority = await api.execute("getRoomAuthority", {
15143
16187
  roomId,
15144
16188
  principalId: item.authorId
@@ -15168,6 +16212,7 @@ ${transcript}` : "",
15168
16212
  }
15169
16213
  } finally {
15170
16214
  clearInterval(heartbeat);
16215
+ this.options.grantRunner?.unregister(roomId);
15171
16216
  if (this.activeTurn?.phase === "prompting" && this.client && this.sessionId) {
15172
16217
  this.client.sessionCancel(this.sessionId);
15173
16218
  }
@@ -15547,7 +16592,7 @@ async function mapWithConcurrency(values, limit, visit) {
15547
16592
  }
15548
16593
  }));
15549
16594
  }
15550
- var execFileAsync3 = promisify3(execFile3);
16595
+ var execFileAsync3 = promisify3(execFile4);
15551
16596
  var RoomRuntimeCoordinator = class {
15552
16597
  configPath;
15553
16598
  baseConfig;
@@ -15567,6 +16612,9 @@ var RoomRuntimeCoordinator = class {
15567
16612
  workspaceRemovalConfirmations = 0;
15568
16613
  roomRemovalConfirmations = /* @__PURE__ */ new Map();
15569
16614
  confirmationPending = false;
16615
+ /** One command-grant runner per daemon; Rooms and corners register their checkouts on it. */
16616
+ grantRunner;
16617
+ grantRunnerServer;
15570
16618
  constructor(runtime, configPath, baseConfig, options) {
15571
16619
  this.configPath = configPath;
15572
16620
  this.baseConfig = baseConfig;
@@ -15576,6 +16624,11 @@ var RoomRuntimeCoordinator = class {
15576
16624
  this.runtime = runtime;
15577
16625
  this.agent = runtimeIdentity(runtime.agent);
15578
16626
  this.now = options.now ?? Date.now;
16627
+ this.grantRunner = new GrantCommandRunner({
16628
+ api: options.daemonApi,
16629
+ agentId: this.agent.publicKey
16630
+ });
16631
+ this.grantRunnerServer = new GrantRunnerServer(this.grantRunner);
15579
16632
  this.watchdogStaleMs = options.watchdogStaleMs ?? DEFAULT_ROOM_WATCHDOG_STALE_MS;
15580
16633
  this.reconcileHeartbeatMs = options.reconcileHeartbeatMs ?? DEFAULT_RECONCILE_HEARTBEAT_MS;
15581
16634
  this.drainDeadlineMs = options.drainDeadlineMs ?? DEFAULT_DRAIN_DEADLINE_MS;
@@ -15602,7 +16655,15 @@ var RoomRuntimeCoordinator = class {
15602
16655
  return this.reconcileHeartbeatMs;
15603
16656
  }
15604
16657
  isWorkspaceIdle() {
15605
- return [...this.running.values()].every((room) => !room.body.isBusy());
16658
+ return this.activeTurnCount() === 0;
16659
+ }
16660
+ /** Turns executing right now. Serving a Room or corner with no turn in flight is idle. */
16661
+ activeTurnCount() {
16662
+ let count = 0;
16663
+ for (const room of this.running.values())
16664
+ if (room.body.isBusy())
16665
+ count += 1;
16666
+ return count;
15606
16667
  }
15607
16668
  quiesceForUpdateIfIdle() {
15608
16669
  if (!this.isWorkspaceIdle())
@@ -15698,13 +16759,13 @@ var RoomRuntimeCoordinator = class {
15698
16759
  return this.runtime.rooms.find((room) => room.channelId === roomId);
15699
16760
  }
15700
16761
  roomRoot(roomId) {
15701
- return this.roomRecord(roomId)?.root ?? resolve10(dirname4(this.configPath), "rooms", roomId);
16762
+ return this.roomRecord(roomId)?.root ?? resolve15(dirname6(this.configPath), "rooms", roomId);
15702
16763
  }
15703
16764
  roomAgentHomeRoot(workspaceRoot, required = false) {
15704
16765
  const flag = process.env.BUZZY_BODY_ROOM_HOME;
15705
16766
  if (!required && flag === "0")
15706
16767
  return void 0;
15707
- const home = resolve10(workspaceRoot, "agent-home");
16768
+ const home = resolve15(workspaceRoot, "agent-home");
15708
16769
  if (!required && flag !== "1" && !existsSync4(home) && existsSync4(workspaceRoot))
15709
16770
  return void 0;
15710
16771
  try {
@@ -15721,19 +16782,30 @@ var RoomRuntimeCoordinator = class {
15721
16782
  return {
15722
16783
  ...this.baseConfig,
15723
16784
  workspaceRoot,
15724
- agentPrivateRoot: resolve10(workspaceRoot, "agent-private"),
15725
- agentMemoryRoot: resolve10(dirname4(this.configPath), "memory"),
16785
+ agentPrivateRoot: resolve15(workspaceRoot, "agent-private"),
16786
+ agentMemoryRoot: resolve15(dirname6(this.configPath), "memory"),
16787
+ openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname6(this.configPath)),
15726
16788
  ...agentHomeRoot ? { agentHomeRoot } : {}
15727
16789
  };
15728
16790
  }
16791
+ /** The loopback door for run_granted_command; started once, on first use. */
16792
+ grantRunnerEndpoint() {
16793
+ return this.grantRunnerServer.start().catch((error) => {
16794
+ console.error("[thin-core] grant runner unavailable; run_granted_command is off:", error);
16795
+ return void 0;
16796
+ });
16797
+ }
15729
16798
  async startRoom(roomId) {
15730
16799
  const controller = new AbortController();
15731
16800
  const cwd = await this.materializeRoomCheckout(roomId);
16801
+ const grantRunnerEndpoint = await this.grantRunnerEndpoint();
15732
16802
  const startedAt = this.now();
15733
16803
  const loop = new MonolithRoomTurnLoop({
15734
16804
  roomId,
15735
16805
  workspaceId: this.runtime.communityId,
15736
16806
  cwd,
16807
+ grantRunner: this.grantRunner,
16808
+ ...grantRunnerEndpoint ? { grantRunnerEndpoint } : {},
15737
16809
  runtime: this.runtime,
15738
16810
  config: this.roomConfig(roomId),
15739
16811
  api: this.options.daemonApi,
@@ -15778,12 +16850,12 @@ var RoomRuntimeCoordinator = class {
15778
16850
  return this.roomRoot(roomId);
15779
16851
  const remote = roomCheckoutRemote(repository.remote);
15780
16852
  const targetBranch = repository.targetBranch || "main";
15781
- const checkoutId = createHash("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
15782
- const path = resolve10(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
15783
- await mkdir6(dirname4(path), { recursive: true, mode: 448 });
16853
+ const checkoutId = createHash2("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
16854
+ const path = resolve15(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
16855
+ await mkdir8(dirname6(path), { recursive: true, mode: 448 });
15784
16856
  const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
15785
16857
  const env = token ? githubGitEnv(token.token) : process.env;
15786
- if (!existsSync4(resolve10(path, ".git"))) {
16858
+ if (!existsSync4(resolve15(path, ".git"))) {
15787
16859
  await execFileAsync3("git", ["clone", "--no-checkout", remote, path], {
15788
16860
  env,
15789
16861
  maxBuffer: 4 * 1024 * 1024
@@ -15845,9 +16917,12 @@ var RoomRuntimeCoordinator = class {
15845
16917
  });
15846
16918
  }
15847
16919
  const controller = new AbortController();
16920
+ const grantRunnerEndpoint = await this.grantRunnerEndpoint();
15848
16921
  const startedAt = this.now();
15849
16922
  const loop = new MonolithCornerTurnLoop({
15850
16923
  cornerId: corner.cornerId,
16924
+ grantRunner: this.grantRunner,
16925
+ ...grantRunnerEndpoint ? { grantRunnerEndpoint } : {},
15851
16926
  parentRoomId: corner.parentRoomId,
15852
16927
  workspaceId: this.runtime.communityId,
15853
16928
  objective,
@@ -15900,13 +16975,13 @@ var RoomRuntimeCoordinator = class {
15900
16975
  }
15901
16976
  async materializeCornerWorktree(input) {
15902
16977
  const remote = githubHttpsRemote(input.remote);
15903
- const repositoryHash = createHash("sha256").update(remote).digest("hex").slice(0, 24);
15904
- const gitCommonDir = resolve10(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
15905
- const path = resolve10(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
15906
- await mkdir6(dirname4(gitCommonDir), { recursive: true, mode: 448 });
15907
- await mkdir6(dirname4(path), { recursive: true, mode: 448 });
16978
+ const repositoryHash = createHash2("sha256").update(remote).digest("hex").slice(0, 24);
16979
+ const gitCommonDir = resolve15(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
16980
+ const path = resolve15(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
16981
+ await mkdir8(dirname6(gitCommonDir), { recursive: true, mode: 448 });
16982
+ await mkdir8(dirname6(path), { recursive: true, mode: 448 });
15908
16983
  const authEnv = githubGitEnv(input.token);
15909
- if (!existsSync4(resolve10(gitCommonDir, "HEAD"))) {
16984
+ if (!existsSync4(resolve15(gitCommonDir, "HEAD"))) {
15910
16985
  await execFileAsync3("git", ["clone", "--bare", remote, gitCommonDir], {
15911
16986
  env: authEnv,
15912
16987
  maxBuffer: 4 * 1024 * 1024
@@ -15919,7 +16994,7 @@ var RoomRuntimeCoordinator = class {
15919
16994
  "origin",
15920
16995
  `+refs/heads/${input.targetBranch}:refs/remotes/origin/${input.targetBranch}`
15921
16996
  ], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
15922
- if (!existsSync4(resolve10(path, ".git"))) {
16997
+ if (!existsSync4(resolve15(path, ".git"))) {
15923
16998
  await rm3(path, { recursive: true, force: true });
15924
16999
  await execFileAsync3("git", [
15925
17000
  `--git-dir=${gitCommonDir}`,
@@ -15956,7 +17031,7 @@ var RoomRuntimeCoordinator = class {
15956
17031
  `${this.agent.publicKey.slice(0, 16)}@users.noreply.github.com`
15957
17032
  ]);
15958
17033
  const top = await execFileAsync3("git", ["-C", path, "rev-parse", "--show-toplevel"]);
15959
- if (resolve10(top.stdout.trim()) !== resolve10(path)) {
17034
+ if (resolve15(top.stdout.trim()) !== resolve15(path)) {
15960
17035
  throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
15961
17036
  }
15962
17037
  return { path, gitCommonDir };
@@ -16023,6 +17098,7 @@ var RoomRuntimeCoordinator = class {
16023
17098
  await Promise.allSettled(rooms.map((room) => room.body.forceRecoverRoom()));
16024
17099
  await drained;
16025
17100
  }
17101
+ await this.grantRunnerServer.close();
16026
17102
  await this.scheduler.dispose();
16027
17103
  }
16028
17104
  };
@@ -16081,6 +17157,9 @@ var ThinDaemonCore = class {
16081
17157
  isWorkspaceIdle() {
16082
17158
  return this.roomRuntime.isWorkspaceIdle();
16083
17159
  }
17160
+ activeTurnCount() {
17161
+ return this.roomRuntime.activeTurnCount();
17162
+ }
16084
17163
  quiesceForUpdateIfIdle() {
16085
17164
  return this.roomRuntime.quiesceForUpdateIfIdle();
16086
17165
  }
@@ -16127,7 +17206,7 @@ var ThinDaemonCore = class {
16127
17206
  };
16128
17207
 
16129
17208
  // apps/body/dist/daemon-api-client.js
16130
- import { resolve as resolve11 } from "node:path";
17209
+ import { resolve as resolve16 } from "node:path";
16131
17210
  var DaemonApiError = class extends Error {
16132
17211
  status;
16133
17212
  retryable;
@@ -16186,8 +17265,8 @@ var DaemonApiClient = class {
16186
17265
  };
16187
17266
  async function activateDaemonTransport(path, fetchImpl = fetch) {
16188
17267
  const runtime = await readRuntimeRecord(path);
16189
- const expectedPath = resolve11(runtimeDirectory(runtime.supervisorRoot, runtime.agent.publicKey), "runtime.json");
16190
- if (resolve11(path) !== expectedPath) {
17268
+ const expectedPath = resolve16(runtimeDirectory(runtime.supervisorRoot, runtime.agent.publicKey), "runtime.json");
17269
+ if (resolve16(path) !== expectedPath) {
16191
17270
  throw new Error(`refusing daemon token exchange outside canonical runtime path: ${path}`);
16192
17271
  }
16193
17272
  const transport = runtime.transport;
@@ -16226,17 +17305,17 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
16226
17305
  }
16227
17306
 
16228
17307
  // apps/body/dist/start-command.js
16229
- import { dirname as dirname6 } from "node:path";
17308
+ import { dirname as dirname8 } from "node:path";
16230
17309
  var import_picocolors = __toESM(require_picocolors(), 1);
16231
17310
 
16232
17311
  // apps/body/dist/systemd.js
16233
- import { execFile as execFile4 } from "node:child_process";
16234
- import { mkdir as mkdir7, readFile as readFile2, writeFile as writeFile4 } from "node:fs/promises";
16235
- import { homedir as homedir7 } from "node:os";
16236
- import { dirname as dirname5, resolve as resolve12 } from "node:path";
17312
+ import { execFile as execFile5 } from "node:child_process";
17313
+ import { mkdir as mkdir9, readFile as readFile7, writeFile as writeFile7 } from "node:fs/promises";
17314
+ import { homedir as homedir8 } from "node:os";
17315
+ import { dirname as dirname7, resolve as resolve17 } from "node:path";
16237
17316
  import { setTimeout as sleep } from "node:timers/promises";
16238
17317
  import { promisify as promisify4 } from "node:util";
16239
- var execFileAsync4 = promisify4(execFile4);
17318
+ var execFileAsync4 = promisify4(execFile5);
16240
17319
  var DELIBERATE_REMOVAL_EXIT_STATUS = 78;
16241
17320
  var DAEMON_DISTRESS_EXIT_STATUS = 77;
16242
17321
  var UNKNOWN_AGENT_EXIT_STATUS = 79;
@@ -16274,10 +17353,10 @@ WantedBy=default.target
16274
17353
  `;
16275
17354
  }
16276
17355
  function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
16277
- const home = env.HOME?.trim() || homedir7();
16278
- const expectedLibDir = resolve12(home, ".local", "lib", "beeline");
17356
+ const home = env.HOME?.trim() || homedir8();
17357
+ const expectedLibDir = resolve17(home, ".local", "lib", "beeline");
16279
17358
  const expectedPrefix = `${expectedLibDir}/`;
16280
- return resolve12(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve12(invocationPath).startsWith(expectedPrefix);
17359
+ return resolve17(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve17(invocationPath).startsWith(expectedPrefix);
16281
17360
  }
16282
17361
  function assertCanonicalInstalledLauncher(env, invocationPath) {
16283
17362
  if (isCanonicalInstalledLauncher(env, invocationPath))
@@ -16285,8 +17364,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
16285
17364
  throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
16286
17365
  }
16287
17366
  function systemdUserUnitPath(env = process.env) {
16288
- const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve12(homedir7(), ".config");
16289
- return resolve12(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
17367
+ const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve17(homedir8(), ".config");
17368
+ return resolve17(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
16290
17369
  }
16291
17370
  var runSystemctl = async (args) => {
16292
17371
  const result = await execFileAsync4("systemctl", ["--user", ...args], {
@@ -16302,10 +17381,10 @@ async function installAgentService(publicKey, options = {}) {
16302
17381
  assertCanonicalInstalledLauncher(env, options.invocationPath);
16303
17382
  const path = systemdUserUnitPath(env);
16304
17383
  const content = agentServiceUnit();
16305
- const existing = await readFile2(path, "utf8").catch(() => "");
17384
+ const existing = await readFile7(path, "utf8").catch(() => "");
16306
17385
  if (existing !== content) {
16307
- await mkdir7(dirname5(path), { recursive: true, mode: 448 });
16308
- await writeFile4(path, content, { mode: 384 });
17386
+ await mkdir9(dirname7(path), { recursive: true, mode: 448 });
17387
+ await writeFile7(path, content, { mode: 384 });
16309
17388
  }
16310
17389
  const run2 = options.run ?? runSystemctl;
16311
17390
  await run2(["daemon-reload"]);
@@ -16357,6 +17436,9 @@ async function notify(fields) {
16357
17436
  return;
16358
17437
  await execFileAsync4("systemd-notify", fields, { timeout: SYSTEMD_COMMAND_TIMEOUT_MS });
16359
17438
  }
17439
+ async function extendSystemdStartTimeout(ms) {
17440
+ await notify([`EXTEND_TIMEOUT_USEC=${Math.max(0, Math.round(ms)) * 1e3}`]).catch(() => void 0);
17441
+ }
16360
17442
  var SystemdNotifier = class {
16361
17443
  async ready(status) {
16362
17444
  await notify(["--ready", `--status=${status}`]);
@@ -16443,7 +17525,7 @@ async function runStartCommand(args, interactiveUi) {
16443
17525
  continue;
16444
17526
  }
16445
17527
  const spinnerHandle = spinner();
16446
- spinnerHandle.start(`Starting ${dirname6(path)}\u2026`);
17528
+ spinnerHandle.start(`Starting ${dirname8(path)}\u2026`);
16447
17529
  try {
16448
17530
  await startRuntime(path, spinnerHandle);
16449
17531
  spinnerHandle.stop(import_picocolors.default.green("Started."));
@@ -16459,9 +17541,9 @@ async function runStartCommand(args, interactiveUi) {
16459
17541
 
16460
17542
  // apps/body/dist/connect-command.js
16461
17543
  import { spawn as spawn5 } from "node:child_process";
16462
- import { createHash as createHash3 } from "node:crypto";
16463
- import { chmod as chmod4, mkdir as mkdir10, readFile as readFile5, unlink as unlink2, writeFile as writeFile7 } from "node:fs/promises";
16464
- import { dirname as dirname9, resolve as resolve15 } from "node:path";
17544
+ import { createHash as createHash4 } from "node:crypto";
17545
+ import { chmod as chmod4, mkdir as mkdir11, readFile as readFile9, unlink as unlink2, writeFile as writeFile9 } from "node:fs/promises";
17546
+ import { dirname as dirname10, resolve as resolve19 } from "node:path";
16465
17547
  import { stdin as stdin3, stdout as stdout4 } from "node:process";
16466
17548
 
16467
17549
  // packages/api-contract/dist/agent-pairing-code.js
@@ -16771,63 +17853,6 @@ async function pairDevice(grant, options = {}) {
16771
17853
  return { runtime: activated.runtime, configPath: staged.configPath, pid };
16772
17854
  }
16773
17855
 
16774
- // apps/body/dist/provider-key-store.js
16775
- import { chmod as chmod2, mkdir as mkdir8, readFile as readFile3, writeFile as writeFile5 } from "node:fs/promises";
16776
- import { homedir as homedir8 } from "node:os";
16777
- import { dirname as dirname7, resolve as resolve13 } from "node:path";
16778
- var PROVIDER_KEY_ENV_VARS = {
16779
- openrouter: "OPENROUTER_API_KEY",
16780
- openai: "OPENAI_API_KEY",
16781
- anthropic: "ANTHROPIC_API_KEY",
16782
- google: "GOOGLE_API_KEY",
16783
- xai: "XAI_API_KEY"
16784
- };
16785
- var GOOGLE_ENV_ALIAS = "GEMINI_API_KEY";
16786
- function providerKeyStorePath(env = process.env) {
16787
- const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve13(homedir8(), ".config");
16788
- return resolve13(configRoot, "beeline", "providers.json");
16789
- }
16790
- async function readProviderKeyStore(env = process.env) {
16791
- const path = providerKeyStorePath(env);
16792
- const raw = await readFile3(path, "utf8").catch(() => void 0);
16793
- if (!raw)
16794
- return {};
16795
- try {
16796
- const parsed = JSON.parse(raw);
16797
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
16798
- return {};
16799
- const entries = Object.entries(parsed).filter((entry) => entry[0] in PROVIDER_KEY_ENV_VARS && typeof entry[1] === "string" && entry[1].length > 0);
16800
- return Object.fromEntries(entries);
16801
- } catch {
16802
- return {};
16803
- }
16804
- }
16805
- async function readSavedProviderKey(provider, env = process.env) {
16806
- return (await readProviderKeyStore(env))[provider];
16807
- }
16808
- async function saveProviderKey(provider, key, env = process.env) {
16809
- const path = providerKeyStorePath(env);
16810
- const store = { ...await readProviderKeyStore(env), [provider]: key };
16811
- await mkdir8(dirname7(path), { recursive: true, mode: 448 });
16812
- await writeFile5(path, `${JSON.stringify(store, null, 2)}
16813
- `, { mode: 384 });
16814
- await chmod2(path, 384);
16815
- }
16816
- function providerKeyFromEnvironment(provider, env = process.env) {
16817
- const primary = env[PROVIDER_KEY_ENV_VARS[provider]]?.trim();
16818
- if (primary)
16819
- return primary;
16820
- if (provider === "google")
16821
- return env[GOOGLE_ENV_ALIAS]?.trim() || void 0;
16822
- return void 0;
16823
- }
16824
- function maskProviderKey(key) {
16825
- const trimmed = key.trim();
16826
- if (trimmed.length <= 9)
16827
- return "\u2026";
16828
- return `${trimmed.slice(0, 6)}\u2026${trimmed.slice(-3)}`;
16829
- }
16830
-
16831
17856
  // apps/body/dist/connect-command.js
16832
17857
  init_self_update();
16833
17858
  init_self_update_manifest();
@@ -16874,14 +17899,32 @@ function brassEnabled(env, output) {
16874
17899
  return "256";
16875
17900
  return "plain";
16876
17901
  }
17902
+ var BRASS_TRUECOLOR = "\x1B[38;2;215;175;95m";
17903
+ var BRASS_256 = "\x1B[38;5;179m";
16877
17904
  function brass(value, env = process.env, output = stdout4) {
16878
17905
  const level = brassEnabled(env, output);
16879
17906
  if (level === "truecolor")
16880
- return `\x1B[38;2;194;147;60m${value}\x1B[39m`;
17907
+ return `${BRASS_TRUECOLOR}${value}\x1B[39m`;
16881
17908
  if (level === "256")
16882
- return `\x1B[38;5;178m${value}\x1B[39m`;
17909
+ return `${BRASS_256}${value}\x1B[39m`;
16883
17910
  return value;
16884
17911
  }
17912
+ function brassRails(text2, env = process.env, output = stdout4) {
17913
+ const level = brassEnabled(env, output);
17914
+ if (level === "plain")
17915
+ return text2;
17916
+ return text2.replace(/\u001b\[(?:36|96)m/g, level === "truecolor" ? BRASS_TRUECOLOR : BRASS_256);
17917
+ }
17918
+ function paintWizardBrass(output = stdout4) {
17919
+ const original = output.write;
17920
+ const patched = function write(chunk, ...rest) {
17921
+ return original.call(this, typeof chunk === "string" ? brassRails(chunk, process.env, output) : chunk, ...rest);
17922
+ };
17923
+ output.write = patched;
17924
+ return () => {
17925
+ output.write = original;
17926
+ };
17927
+ }
16885
17928
  var clackPrompts = {
16886
17929
  async select(input) {
16887
17930
  clackPromptOutput();
@@ -16906,12 +17949,12 @@ var clackPrompts = {
16906
17949
  }), "Connection cancelled.");
16907
17950
  }
16908
17951
  };
16909
- function connectModelPickerFromAxes(axes, fallbackModel, harness) {
17952
+ function connectModelPickerFromAxes(axes, fallbackModel, harness, rawAxes = axes) {
16910
17953
  const filtered = axes.find((axis) => axis.category === "model");
16911
17954
  if (filtered?.options.length) {
16912
17955
  return { currentValue: filtered.currentValue, options: filtered.options };
16913
17956
  }
16914
- const raw = axes.find((axis) => axis.category === "model" && axis.options.length);
17957
+ const raw = rawAxes.find((axis) => axis.category === "model" && axis.options.length);
16915
17958
  if (raw) {
16916
17959
  return { currentValue: raw.currentValue, options: raw.options };
16917
17960
  }
@@ -16929,7 +17972,7 @@ async function loadConnectModelCatalog(input) {
16929
17972
  ...input.apiKey ? { apiKey: input.apiKey } : {},
16930
17973
  model: defaultConnectModel(input.harness, input.provider)
16931
17974
  }));
16932
- return connectModelPickerFromAxes(catalog.catalog, defaultConnectModel(input.harness, input.provider), input.harness);
17975
+ return connectModelPickerFromAxes(catalog.catalog, defaultConnectModel(input.harness, input.provider), input.harness, catalog.raw);
16933
17976
  }
16934
17977
  async function collectConnectWizard(prompts = clackPrompts, loadModels = loadConnectModelCatalog, keyStore = fileConnectKeyStore, env = process.env, verifyKey = (input) => verifyProviderKey(input)) {
16935
17978
  const harness = await prompts.select({
@@ -17006,25 +18049,11 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
17006
18049
  placeholder: "Type to filter available models\u2026",
17007
18050
  maxItems: 12
17008
18051
  });
17009
- const name = await prompts.text({
17010
- message: brass("Agent name"),
17011
- validate: (value) => {
17012
- if (!value.trim())
17013
- return "Agent name is required";
17014
- return isReasonableAgentName(value) ? void 0 : `Use letters, spaces, hyphens, or apostrophes (${AGENT_NAME_MAX_LENGTH} characters max)`;
17015
- }
17016
- });
17017
- const soul = await prompts.text({
17018
- message: brass("Input soul"),
17019
- validate: (value) => value.trim() ? void 0 : "Soul is required"
17020
- });
17021
18052
  return {
17022
- name: name.trim().replace(/\s+/g, " "),
17023
18053
  harness,
17024
18054
  ...provider ? { provider } : {},
17025
18055
  ...apiKey ? { apiKey: apiKey.trim() } : {},
17026
- model: model.trim(),
17027
- soul: soul.trim()
18056
+ model: model.trim()
17028
18057
  };
17029
18058
  }
17030
18059
  async function jsonRequest(url, body, fetchImpl) {
@@ -17044,17 +18073,25 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
17044
18073
  const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
17045
18074
  if (!normalizedPairingCode)
17046
18075
  throw new Error("invalid pairing code");
17047
- const avatarSeed = createHash3("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
18076
+ const avatarSeed = createHash4("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
17048
18077
  return jsonRequest(`${baseUrl}/auth/agent/connect`, {
17049
18078
  pairing_code: normalizedPairingCode,
17050
18079
  harness: selection.harness,
17051
18080
  ...selection.provider ? { provider: selection.provider } : {},
17052
18081
  model: selection.model,
17053
- soul: selection.soul,
17054
- avatar_seed: avatarSeed,
17055
- agent_name: selection.name
18082
+ avatar_seed: avatarSeed
17056
18083
  }, fetchImpl);
17057
18084
  }
18085
+ async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
18086
+ const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
18087
+ if (!normalizedPairingCode)
18088
+ throw new Error("invalid pairing code");
18089
+ const renamed = await jsonRequest(`${baseUrl}/auth/agent/connect/name`, { pairing_code: normalizedPairingCode, agent_name: name.trim().replace(/\s+/g, " ") }, fetchImpl);
18090
+ return renamed.agent_name;
18091
+ }
18092
+ function seededIdentityLine(grant) {
18093
+ return grant.agent_face ? `${grant.agent_name} the ${grant.agent_face}` : grant.agent_name;
18094
+ }
17058
18095
  async function installCurrentRelease(fetchImpl) {
17059
18096
  const manifestUrl = resolveManifestUrl(process.env);
17060
18097
  const response = await fetchImpl(manifestUrl, { signal: AbortSignal.timeout(3e4) });
@@ -17069,7 +18106,7 @@ async function installCurrentRelease(fetchImpl) {
17069
18106
  });
17070
18107
  await activateRelease(layout, releaseId);
17071
18108
  return {
17072
- binary: resolve15(layout.binDir, "beeline"),
18109
+ binary: resolve19(layout.binDir, "beeline"),
17073
18110
  version: published.version ?? releaseId
17074
18111
  };
17075
18112
  }
@@ -17092,8 +18129,8 @@ function providerEnvironment(selection) {
17092
18129
  };
17093
18130
  }
17094
18131
  async function writePrivateJson(path, value) {
17095
- await mkdir10(dirname9(path), { recursive: true, mode: 448 });
17096
- await writeFile7(path, `${JSON.stringify(value, null, 2)}
18132
+ await mkdir11(dirname10(path), { recursive: true, mode: 448 });
18133
+ await writeFile9(path, `${JSON.stringify(value, null, 2)}
17097
18134
  `, { mode: 384 });
17098
18135
  await chmod4(path, 384);
17099
18136
  }
@@ -17101,10 +18138,10 @@ async function writeProviderEnv(selection, agentPubkey) {
17101
18138
  const values = providerEnvironment(selection);
17102
18139
  if (Object.keys(values).length === 0)
17103
18140
  return void 0;
17104
- const path = resolve15(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
17105
- await mkdir10(dirname9(path), { recursive: true, mode: 448 });
18141
+ const path = resolve19(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
18142
+ await mkdir11(dirname10(path), { recursive: true, mode: 448 });
17106
18143
  const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
17107
- await writeFile7(path, `${contents}
18144
+ await writeFile9(path, `${contents}
17108
18145
  `, { mode: 384 });
17109
18146
  await chmod4(path, 384);
17110
18147
  return path;
@@ -17147,18 +18184,26 @@ async function runConnectCommand(code, options = {}) {
17147
18184
  if (!stdin3.isTTY || !stdout4.isTTY) {
17148
18185
  throw new Error("`usebeeline connect` needs an interactive terminal");
17149
18186
  }
18187
+ const restoreRails = paintWizardBrass();
18188
+ try {
18189
+ await runConnectWizard(code, options.fetchImpl ?? fetch);
18190
+ } finally {
18191
+ restoreRails();
18192
+ }
18193
+ }
18194
+ async function runConnectWizard(code, fetchImpl) {
17150
18195
  intro(brass("Beeline connect"));
17151
- const fetchImpl = options.fetchImpl ?? fetch;
17152
18196
  const pairingCode = code?.trim() || await clackPrompts.text({
17153
18197
  message: brass("Pairing code from the app"),
17154
18198
  validate: (value) => normalizeAgentPairingCode(value) ? void 0 : "Enter the pairing code shown in the app"
17155
18199
  });
17156
18200
  const selection = await collectConnectWizard(clackPrompts, loadConnectModelCatalog, fileConnectKeyStore, process.env, (input) => verifyProviderKey({ ...input, fetchImpl }));
17157
18201
  const baseUrl = (process.env.BEELINE_AUTH_URL ?? "https://server.usebeeline.app").replace(/\/$/, "");
17158
- const grant = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
18202
+ const claimed = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
18203
+ const grant = { ...claimed, agent_name: await confirmSeededName(baseUrl, pairingCode, claimed, fetchImpl) };
17159
18204
  const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
17160
18205
  const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
17161
- const grantPath = resolve15(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
18206
+ const grantPath = resolve19(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
17162
18207
  await writePrivateJson(grantPath, {
17163
18208
  agentSecretKey: grant.agent_secret_key,
17164
18209
  bodySecretKey: grant.body_secret_key,
@@ -17175,10 +18220,38 @@ async function runConnectCommand(code, options = {}) {
17175
18220
  });
17176
18221
  await brassSpinner("Starting your agent\u2026", () => runInstalledFinish(installedRelease.binary, grantPath), () => `Started ${grant.agent_name}`);
17177
18222
  console.log("");
17178
- console.log(`${brass("Agent")} ${grant.agent_name}`);
18223
+ console.log(`${brass("Agent")} ${seededIdentityLine(grant)}`);
17179
18224
  console.log(`${brass("Workspace")} ${grant.workspace_name}`);
17180
18225
  outro(brass("Say hi in the app."));
17181
18226
  }
18227
+ async function confirmSeededName(baseUrl, pairingCode, grant, fetchImpl, prompts = clackPrompts) {
18228
+ log.info(brass(`Your agent is ${seededIdentityLine(grant)}.`));
18229
+ const choice = await prompts.select({
18230
+ message: brass("Name"),
18231
+ initialValue: "keep",
18232
+ options: [
18233
+ { value: "keep", label: `Keep ${grant.agent_name}`, hint: "default" },
18234
+ { value: "rename", label: "Rename this agent" }
18235
+ ]
18236
+ });
18237
+ if (choice === "keep")
18238
+ return grant.agent_name;
18239
+ const renamed = await prompts.text({
18240
+ message: brass("Agent name"),
18241
+ initialValue: grant.agent_name,
18242
+ validate: (value) => {
18243
+ if (!value.trim())
18244
+ return "Agent name is required";
18245
+ return isReasonableAgentName(value) ? void 0 : `Use letters, spaces, hyphens, or apostrophes (${AGENT_NAME_MAX_LENGTH} characters max)`;
18246
+ }
18247
+ });
18248
+ try {
18249
+ return await renameConnectedAgent(baseUrl, pairingCode, renamed, fetchImpl);
18250
+ } catch (error) {
18251
+ log.warn(brass(`Could not rename this agent (${error instanceof Error ? error.message : String(error)}); it stays ${grant.agent_name}. Rename it in the app.`));
18252
+ return grant.agent_name;
18253
+ }
18254
+ }
17182
18255
  function isDevicePairingGrant(value) {
17183
18256
  if (!value || typeof value !== "object")
17184
18257
  return false;
@@ -17209,11 +18282,22 @@ async function runConnectFinishCommand(path) {
17209
18282
  throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
17210
18283
  }
17211
18284
  try {
17212
- const grant = JSON.parse(await readFile5(resolve15(path), "utf8"));
18285
+ const grant = JSON.parse(await readFile9(resolve19(path), "utf8"));
17213
18286
  if (!isDevicePairingGrant(grant))
17214
18287
  throw new Error("device connection grant is invalid");
17215
- await completeDevicePairing(grant);
17216
- await unlink2(resolve15(path));
18288
+ const connected = await completeDevicePairing(grant);
18289
+ await unlink2(resolve19(path));
18290
+ const providerEnv = grant.llmEnvFile ? await readFile9(grant.llmEnvFile, "utf8").catch(() => "") : "";
18291
+ const model = openRouterModelId(grant.model, {
18292
+ OPENROUTER_API_KEY: /^OPENROUTER_API_KEY=\S/m.test(providerEnv) ? "set" : ""
18293
+ });
18294
+ if (model) {
18295
+ const decision2 = await resolveOpenRouterRouting({
18296
+ model,
18297
+ cacheDir: openRouterRoutingCacheDir(dirname10(connected.configPath))
18298
+ });
18299
+ console.log(decision2.line);
18300
+ }
17217
18301
  } catch (error) {
17218
18302
  throw new ConnectFailureError(connectPlainFailure(error));
17219
18303
  }
@@ -17227,20 +18311,20 @@ init_self_update_manifest();
17227
18311
  // apps/body/dist/managed-update.js
17228
18312
  init_self_update();
17229
18313
  import { spawn as spawn6 } from "node:child_process";
17230
- import { mkdir as mkdir12, rm as rm5, stat as stat2, writeFile as writeFile9 } from "node:fs/promises";
17231
- import { dirname as dirname11, resolve as resolve17 } from "node:path";
18314
+ import { mkdir as mkdir13, rm as rm5, stat as stat2, writeFile as writeFile11 } from "node:fs/promises";
18315
+ import { dirname as dirname12, resolve as resolve21 } from "node:path";
17232
18316
 
17233
18317
  // apps/body/dist/update-rollback-alert.js
17234
- import { mkdir as mkdir11, readFile as readFile6, rename as rename4, writeFile as writeFile8 } from "node:fs/promises";
17235
- import { dirname as dirname10, resolve as resolve16 } from "node:path";
18318
+ import { mkdir as mkdir12, readFile as readFile10, rename as rename4, writeFile as writeFile10 } from "node:fs/promises";
18319
+ import { dirname as dirname11, resolve as resolve20 } from "node:path";
17236
18320
  function updateRollbackAlertPath(runtimeDir) {
17237
- return resolve16(runtimeDir, "update-rollback-alert.json");
18321
+ return resolve20(runtimeDir, "update-rollback-alert.json");
17238
18322
  }
17239
18323
  async function writeAlert(runtimeDir, alert) {
17240
18324
  const path = updateRollbackAlertPath(runtimeDir);
17241
18325
  const staged = `${path}.${process.pid}.tmp`;
17242
- await mkdir11(dirname10(path), { recursive: true });
17243
- await writeFile8(staged, `${JSON.stringify(alert, null, 2)}
18326
+ await mkdir12(dirname11(path), { recursive: true });
18327
+ await writeFile10(staged, `${JSON.stringify(alert, null, 2)}
17244
18328
  `, { mode: 384 });
17245
18329
  await rename4(staged, path);
17246
18330
  }
@@ -17252,7 +18336,7 @@ async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()
17252
18336
  }
17253
18337
  async function readUpdateRollbackAlert(runtimeDir) {
17254
18338
  try {
17255
- const value = JSON.parse(await readFile6(updateRollbackAlertPath(runtimeDir), "utf8"));
18339
+ const value = JSON.parse(await readFile10(updateRollbackAlertPath(runtimeDir), "utf8"));
17256
18340
  if (value.version !== 1 || typeof value.releaseId !== "string")
17257
18341
  return void 0;
17258
18342
  return value;
@@ -17277,13 +18361,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
17277
18361
  var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
17278
18362
  async function withInstallLock(layout, work, options = {}) {
17279
18363
  const now2 = options.now ?? Date.now;
17280
- const lock = resolve17(layout.releasesRoot, ".state", "install.lock");
18364
+ const lock = resolve21(layout.releasesRoot, ".state", "install.lock");
17281
18365
  const deadline = now2() + (options.waitMs ?? 1e4);
17282
- await mkdir12(dirname11(lock), { recursive: true });
18366
+ await mkdir13(dirname12(lock), { recursive: true });
17283
18367
  for (; ; ) {
17284
18368
  try {
17285
- await mkdir12(lock);
17286
- await writeFile9(resolve17(lock, "owner"), `${process.pid}
18369
+ await mkdir13(lock);
18370
+ await writeFile11(resolve21(lock, "owner"), `${process.pid}
17287
18371
  ${now2()}
17288
18372
  `, "utf8");
17289
18373
  break;
@@ -17320,7 +18404,6 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
17320
18404
  #requested = false;
17321
18405
  #restartRequest;
17322
18406
  #stagedReleaseId;
17323
- #drainDeadlineLogged = false;
17324
18407
  constructor(options) {
17325
18408
  this.#layout = options.layout;
17326
18409
  this.#loadedRelease = options.loadedRelease;
@@ -17407,7 +18490,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
17407
18490
  if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
17408
18491
  const from = await readInstalledBundleIdentity({
17409
18492
  ...this.#layout,
17410
- libDir: resolve17(this.#layout.releasesRoot, this.#loadedRelease)
18493
+ libDir: resolve21(this.#layout.releasesRoot, this.#loadedRelease)
17411
18494
  }).catch(() => void 0) ?? {};
17412
18495
  const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
17413
18496
  const record2 = {
@@ -17444,11 +18527,13 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
17444
18527
  }
17445
18528
  /**
17446
18529
  * Resolve one handoff tick against the daemon's authoritative turn registry.
17447
- * A staged release stays inert while accepted work is running.
17448
- * `quiesceIfIdle` closes intake in the same synchronous transition that
17449
- * proves idle, so a new turn cannot race activation. Expiring the bounded
17450
- * drain window records delayed convergence; it never turns a routine update
17451
- * into an ACP cancellation or a failed Room receipt.
18530
+ * Busy means a turn is executing right now; serving Rooms and corners with
18531
+ * no turn in flight is idle. `quiesceIfIdle` closes intake in the same
18532
+ * synchronous transition that proves idle, so a new turn cannot race
18533
+ * activation. A staged release stays inert while a turn runs — until the
18534
+ * absolute drain deadline, when the restart is forced (`forced: true`) and
18535
+ * the caller cancels the running turn; the convergence contract outranks a
18536
+ * stuck turn. `ManagedUpdateDrain` enforces that deadline with a timer.
17452
18537
  */
17453
18538
  async restartRequest(quiesceIfIdle) {
17454
18539
  const activeDrift = await this.check();
@@ -17457,12 +18542,11 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
17457
18542
  const request = this.#restartRequest;
17458
18543
  if (!request)
17459
18544
  throw new Error("update drift was detected without an in-memory restart request");
18545
+ let forced = false;
17460
18546
  if (!quiesceIfIdle()) {
17461
- if (this.#now() >= request.drainDeadlineAt && !this.#drainDeadlineLogged) {
17462
- console.log(`[thin-core] update drain window elapsed with active work; keeping the staged release ${request.desiredRelease} inert instead of interrupting the Room turn`);
17463
- this.#drainDeadlineLogged = true;
17464
- }
17465
- return { kind: "waiting", request };
18547
+ if (this.#now() < request.drainDeadlineAt)
18548
+ return { kind: "waiting", request };
18549
+ forced = true;
17466
18550
  }
17467
18551
  if (this.#stagedReleaseId) {
17468
18552
  const stagedReleaseId = this.#stagedReleaseId;
@@ -17482,7 +18566,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
17482
18566
  this.#restartRequest = void 0;
17483
18567
  await this.#journalDrift(stagedReleaseId);
17484
18568
  }
17485
- return { kind: "restart", request: this.#restartRequest ?? request };
18569
+ return { kind: "restart", request: this.#restartRequest ?? request, forced };
17486
18570
  }
17487
18571
  };
17488
18572
  async function coordinateManagedUpdateHandoff(update, quiesceIfIdle, restart, waiting = async () => void 0) {
@@ -17493,9 +18577,88 @@ async function coordinateManagedUpdateHandoff(update, quiesceIfIdle, restart, wa
17493
18577
  await waiting(next.request);
17494
18578
  return "waiting-for-idle";
17495
18579
  }
17496
- await restart(next.request);
18580
+ await restart(next.request, next.forced ? "forced" : "drained");
17497
18581
  return "restarting";
17498
18582
  }
18583
+ var UPDATE_DRAIN_WAIT_LOG_INTERVAL_MS = 6e4;
18584
+ var ManagedUpdateDrain = class {
18585
+ #options;
18586
+ #now;
18587
+ #log;
18588
+ #setTimer;
18589
+ #clearTimer;
18590
+ #deadlineTimer;
18591
+ #waitLogTimer;
18592
+ #resolving;
18593
+ #restarting = false;
18594
+ constructor(options) {
18595
+ this.#options = options;
18596
+ this.#now = options.now ?? Date.now;
18597
+ this.#log = options.log ?? ((line) => console.log(line));
18598
+ this.#setTimer = options.setTimer ?? ((callback, ms) => setTimeout(callback, ms));
18599
+ this.#clearTimer = options.clearTimer ?? ((handle) => clearTimeout(handle));
18600
+ }
18601
+ /** Called from every completed core progress tick. */
18602
+ tick() {
18603
+ return this.#resolve();
18604
+ }
18605
+ #resolve() {
18606
+ if (this.#restarting)
18607
+ return Promise.resolve("restarting");
18608
+ if (this.#resolving)
18609
+ return this.#resolving;
18610
+ this.#resolving = this.#step().finally(() => {
18611
+ this.#resolving = void 0;
18612
+ });
18613
+ return this.#resolving;
18614
+ }
18615
+ async #step() {
18616
+ const { update, quiesceIfIdle, activeTurnCount } = this.#options;
18617
+ let armed;
18618
+ const progress = await coordinateManagedUpdateHandoff(update, quiesceIfIdle, async (request, mode) => {
18619
+ this.#disarm();
18620
+ if (mode === "forced") {
18621
+ this.#log(`[thin-core] update restart forced: drain deadline reached with ${activeTurnCount()} active turn(s); cancelling them and restarting onto ${request.desiredRelease}`);
18622
+ }
18623
+ await this.#options.restart(request, mode);
18624
+ this.#restarting = true;
18625
+ }, async (request) => {
18626
+ armed = request;
18627
+ await this.#options.waiting?.(request);
18628
+ });
18629
+ if (armed && !this.#deadlineTimer)
18630
+ this.#arm(armed);
18631
+ return progress;
18632
+ }
18633
+ #arm(request) {
18634
+ this.#logWaiting(request);
18635
+ this.#scheduleWaitLog(request);
18636
+ this.#deadlineTimer = this.#setTimer(() => void this.#resolve().catch((error) => {
18637
+ this.#log(`[thin-core] update restart at the drain deadline failed; retrying on the next tick: ${error instanceof Error ? error.message : String(error)}`);
18638
+ }), Math.max(0, request.drainDeadlineAt - this.#now()));
18639
+ }
18640
+ #scheduleWaitLog(request) {
18641
+ this.#waitLogTimer = this.#setTimer(() => {
18642
+ this.#waitLogTimer = void 0;
18643
+ if (this.#restarting)
18644
+ return;
18645
+ this.#logWaiting(request);
18646
+ this.#scheduleWaitLog(request);
18647
+ }, UPDATE_DRAIN_WAIT_LOG_INTERVAL_MS);
18648
+ }
18649
+ #logWaiting(request) {
18650
+ const minutesLeft = Math.max(0, Math.ceil((request.drainDeadlineAt - this.#now()) / 6e4));
18651
+ this.#log(`[thin-core] update restart waiting: ${this.#options.activeTurnCount()} active turn(s); deadline in ${minutesLeft}m`);
18652
+ }
18653
+ #disarm() {
18654
+ if (this.#deadlineTimer !== void 0)
18655
+ this.#clearTimer(this.#deadlineTimer);
18656
+ if (this.#waitLogTimer !== void 0)
18657
+ this.#clearTimer(this.#waitLogTimer);
18658
+ this.#deadlineTimer = void 0;
18659
+ this.#waitLogTimer = void 0;
18660
+ }
18661
+ };
17499
18662
  function numberEnv(env, name, fallback) {
17500
18663
  const value = Number(env[name]);
17501
18664
  return Number.isFinite(value) && value >= 0 ? value : fallback;
@@ -17614,7 +18777,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
17614
18777
  });
17615
18778
  if (!accepted)
17616
18779
  return false;
17617
- await writeFile9(resolve17(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
18780
+ await writeFile11(resolve21(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
17618
18781
  readyAt: (options.now ?? Date.now)(),
17619
18782
  loadedRelease,
17620
18783
  functionalProof: options.functionalProof
@@ -17819,16 +18982,16 @@ async function runUpdateCommand(args) {
17819
18982
  init_self_update();
17820
18983
 
17821
18984
  // apps/body/dist/daemon-failure.js
17822
- import { mkdir as mkdir13, readFile as readFile7, rename as rename5, rm as rm6, writeFile as writeFile10 } from "node:fs/promises";
17823
- import { dirname as dirname12, resolve as resolve18 } from "node:path";
18985
+ import { mkdir as mkdir14, readFile as readFile11, rename as rename5, rm as rm6, writeFile as writeFile12 } from "node:fs/promises";
18986
+ import { dirname as dirname13, resolve as resolve22 } from "node:path";
17824
18987
  var DAEMON_FAILURE_LIMIT = 3;
17825
18988
  var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
17826
18989
  function daemonFailurePath(runtimeDir) {
17827
- return resolve18(runtimeDir, "daemon-distress.json");
18990
+ return resolve22(runtimeDir, "daemon-distress.json");
17828
18991
  }
17829
18992
  async function readFailureRecord(runtimeDir) {
17830
18993
  try {
17831
- const value = JSON.parse(await readFile7(daemonFailurePath(runtimeDir), "utf8"));
18994
+ const value = JSON.parse(await readFile11(daemonFailurePath(runtimeDir), "utf8"));
17832
18995
  if (value.version !== 1 || !Array.isArray(value.failures) || value.failures.some((failure) => typeof failure !== "number") || typeof value.lastError !== "string") {
17833
18996
  return void 0;
17834
18997
  }
@@ -17840,8 +19003,8 @@ async function readFailureRecord(runtimeDir) {
17840
19003
  async function writeFailureRecord(runtimeDir, record2) {
17841
19004
  const path = daemonFailurePath(runtimeDir);
17842
19005
  const staged = `${path}.${process.pid}.tmp`;
17843
- await mkdir13(dirname12(path), { recursive: true, mode: 448 });
17844
- await writeFile10(staged, `${JSON.stringify(record2, null, 2)}
19006
+ await mkdir14(dirname13(path), { recursive: true, mode: 448 });
19007
+ await writeFile12(staged, `${JSON.stringify(record2, null, 2)}
17845
19008
  `, { mode: 384 });
17846
19009
  await rename5(staged, path);
17847
19010
  }
@@ -17863,21 +19026,45 @@ async function clearDaemonStartFailures(runtimeDir) {
17863
19026
  }
17864
19027
 
17865
19028
  // apps/body/dist/update-functional-probe.js
17866
- import { mkdir as mkdir14, rm as rm7 } from "node:fs/promises";
19029
+ import { mkdir as mkdir15, rm as rm7 } from "node:fs/promises";
17867
19030
  import { homedir as homedir10 } from "node:os";
17868
- import { resolve as resolve19 } from "node:path";
19031
+ import { resolve as resolve23 } from "node:path";
17869
19032
  var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
17870
19033
  var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
17871
19034
  var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
17872
19035
  var UpdateFunctionalProbeError = class extends Error {
17873
19036
  reason;
17874
19037
  code = "BEELINE_UPDATE_FUNCTIONAL_PROBE_FAILED";
19038
+ /** Present when the turn failed on a provider refusal with an HTTP status. */
19039
+ providerRefusal;
17875
19040
  constructor(reason, detail, options) {
17876
19041
  super(`functional update probe failed (${reason}): ${detail}`, options);
17877
19042
  this.reason = reason;
17878
19043
  this.name = "UpdateFunctionalProbeError";
19044
+ this.providerRefusal = options?.providerRefusal;
17879
19045
  }
17880
19046
  };
19047
+ async function probeOutcome(run2) {
19048
+ try {
19049
+ await run2();
19050
+ return { kind: "served" };
19051
+ } catch (error) {
19052
+ if (error instanceof UpdateFunctionalProbeError && error.providerRefusal) {
19053
+ return { kind: "refused", ...error.providerRefusal };
19054
+ }
19055
+ return { kind: "unavailable", reason: error instanceof Error ? error.message : String(error) };
19056
+ }
19057
+ }
19058
+ function describeCurrentReleaseOutcome(outcome) {
19059
+ switch (outcome.kind) {
19060
+ case "served":
19061
+ return "the current release answered";
19062
+ case "refused":
19063
+ return `the current release got a different refusal (${outcome.reason})`;
19064
+ case "unavailable":
19065
+ return `the current release could not be compared (${outcome.reason})`;
19066
+ }
19067
+ }
17881
19068
  async function runUpdateFunctionalProbe(input) {
17882
19069
  const command = input.config.agentCommand ?? input.config.agentBinary;
17883
19070
  const harness = input.config.agentKind ?? command;
@@ -17887,11 +19074,11 @@ async function runUpdateFunctionalProbe(input) {
17887
19074
  if (input.sandboxRequired && !input.config.bwrapPath) {
17888
19075
  throw new UpdateFunctionalProbeError("sandbox-unavailable", "the configured bubblewrap boundary did not pass its startup self-test");
17889
19076
  }
17890
- const root = resolve19(input.runtimeDir, "update-functional-probe");
17891
- const cwd = resolve19(root, "checkout");
17892
- const homeRoot = resolve19(root, "agent-home");
19077
+ const root = input.probeRoot ?? resolve23(input.runtimeDir, "update-functional-probe");
19078
+ const cwd = resolve23(root, "checkout");
19079
+ const homeRoot = resolve23(root, "agent-home");
17893
19080
  await rm7(root, { recursive: true, force: true });
17894
- await mkdir14(cwd, { recursive: true, mode: 448 });
19081
+ await mkdir15(cwd, { recursive: true, mode: 448 });
17895
19082
  let client;
17896
19083
  try {
17897
19084
  const agentEnv = {
@@ -17901,7 +19088,8 @@ async function runUpdateFunctionalProbe(input) {
17901
19088
  operatorHome: input.config.operatorHome ?? homedir10(),
17902
19089
  sharedSkills: input.config.sharedSkills ?? [],
17903
19090
  skillReleaseId: input.releaseId,
17904
- failClosed: true
19091
+ failClosed: true,
19092
+ ...openRouterRoutingInput({ ...input.config, openRouterRoutingCacheDir: openRouterRoutingCacheDir(input.runtimeDir) }, input.config.modelSelection)
17905
19093
  })
17906
19094
  };
17907
19095
  const selectedAgent = {
@@ -17913,11 +19101,12 @@ async function runUpdateFunctionalProbe(input) {
17913
19101
  command,
17914
19102
  args: agentArgsWithModelSelection(selectedAgent, input.config.modelSelection)
17915
19103
  };
19104
+ let modelAnswer = {};
17916
19105
  if (input.config.bwrapPath) {
17917
19106
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
17918
19107
  const operatorHome = input.config.operatorHome ?? homedir10();
17919
19108
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
17920
- await Promise.all(homeStateDirs.map((dir) => mkdir14(dir, { recursive: true })));
19109
+ await Promise.all(homeStateDirs.map((dir) => mkdir15(dir, { recursive: true })));
17921
19110
  spawnCommand = wrapAgentCommand({
17922
19111
  bwrapPath: input.config.bwrapPath,
17923
19112
  spec: {
@@ -17956,10 +19145,39 @@ async function runUpdateFunctionalProbe(input) {
17956
19145
  }
17957
19146
  try {
17958
19147
  const served = await client.sessionPrompt(opened.sessionId, "Reply READY.", input.turnTimeoutMs ?? UPDATE_PROBE_TURN_TIMEOUT_MS);
17959
- if (!served.agentText.trim()) {
17960
- throw new UpdateFunctionalProbeError("turn-failed", "the harness completed a session/prompt without an agent answer");
19148
+ if (served.agentText.trim()) {
19149
+ modelAnswer = { modelAnswer: "served" };
19150
+ } else {
19151
+ const explained = await explainEmptyAgentTurn({
19152
+ agentLabel: command,
19153
+ agentEnv,
19154
+ sessionId: opened.sessionId,
19155
+ result: served
19156
+ });
19157
+ const modelSide = isAccountOrProviderRefusal(explained.record) || explained.record?.kind === "empty";
19158
+ if (!modelSide) {
19159
+ const refusal = explained.record?.kind === "error" && explained.record.status !== void 0 ? { status: explained.record.status, reason: explained.record.reason } : void 0;
19160
+ const detail = `the harness completed a session/prompt without an agent answer: ${explained.reason}`;
19161
+ if (!refusal || !input.compareWithCurrentRelease) {
19162
+ throw new UpdateFunctionalProbeError("turn-failed", detail, {
19163
+ ...refusal ? { providerRefusal: refusal } : {}
19164
+ });
19165
+ }
19166
+ const current = await input.compareWithCurrentRelease(refusal);
19167
+ if (current.kind !== "refused" || current.status !== refusal.status) {
19168
+ throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { providerRefusal: refusal });
19169
+ }
19170
+ const reason = `${explained.reason} (the current release gets the same ${refusal.status})`;
19171
+ console.warn(`[body] update probe: the provider refused this release and the current release alike (${refusal.reason}); that refusal is not this bundle's doing, so the probe passes as inconclusive`);
19172
+ modelAnswer = { modelAnswer: "unavailable", modelAnswerReason: reason };
19173
+ } else {
19174
+ console.warn(`[body] update probe: the bundle reached the model boundary but the model answered nothing (${explained.reason}); that is the model's own answer on any release, so the probe passes without one`);
19175
+ modelAnswer = { modelAnswer: "unavailable", modelAnswerReason: explained.reason };
19176
+ }
17961
19177
  }
17962
19178
  } catch (error) {
19179
+ if (error instanceof UpdateFunctionalProbeError)
19180
+ throw error;
17963
19181
  throw new UpdateFunctionalProbeError("turn-failed", error instanceof Error ? error.message : String(error), { cause: error });
17964
19182
  }
17965
19183
  } catch (error) {
@@ -17972,7 +19190,8 @@ async function runUpdateFunctionalProbe(input) {
17972
19190
  sandboxed: Boolean(input.config.bwrapPath),
17973
19191
  sessionStarted: true,
17974
19192
  turnCompleted: true,
17975
- nativeTools: []
19193
+ nativeTools: [],
19194
+ ...modelAnswer
17976
19195
  };
17977
19196
  } finally {
17978
19197
  await client?.stop().catch(() => void 0);
@@ -17980,9 +19199,140 @@ async function runUpdateFunctionalProbe(input) {
17980
19199
  }
17981
19200
  }
17982
19201
 
19202
+ // apps/body/dist/current-release-probe.js
19203
+ import { spawn as spawn7 } from "node:child_process";
19204
+ import { dirname as dirname14, join as join7 } from "node:path";
19205
+ init_self_update();
19206
+ var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 8e4;
19207
+ var UPDATE_PROBE_COMMAND = "update-probe";
19208
+ function parseReport(line) {
19209
+ let parsed;
19210
+ try {
19211
+ parsed = JSON.parse(line);
19212
+ } catch {
19213
+ return void 0;
19214
+ }
19215
+ if (!parsed || typeof parsed !== "object")
19216
+ return void 0;
19217
+ const report = parsed;
19218
+ if (report.probe === "served")
19219
+ return { probe: "served" };
19220
+ if (report.probe === "refused" && typeof report.status === "number" && typeof report.reason === "string") {
19221
+ return { probe: "refused", status: report.status, reason: report.reason };
19222
+ }
19223
+ if (report.probe === "failed" && typeof report.reason === "string") {
19224
+ return { probe: "failed", reason: report.reason };
19225
+ }
19226
+ return void 0;
19227
+ }
19228
+ function outcomeFromReport(report) {
19229
+ switch (report.probe) {
19230
+ case "served":
19231
+ return { kind: "served" };
19232
+ case "refused":
19233
+ return { kind: "refused", status: report.status, reason: report.reason };
19234
+ case "failed":
19235
+ return { kind: "unavailable", reason: report.reason };
19236
+ }
19237
+ }
19238
+ async function probeReleaseInSubprocess(input) {
19239
+ const bundleDir = join7(input.layout.releasesRoot, input.releaseId);
19240
+ const entrypoint = await resolveBundleEntrypoint(bundleDir);
19241
+ if (!entrypoint) {
19242
+ return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
19243
+ }
19244
+ const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
19245
+ return new Promise((resolve26) => {
19246
+ const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
19247
+ let stdout6 = "";
19248
+ let stderr = "";
19249
+ let settled = false;
19250
+ const finish = (outcome) => {
19251
+ if (settled)
19252
+ return;
19253
+ settled = true;
19254
+ clearTimeout(timer);
19255
+ resolve26(outcome);
19256
+ };
19257
+ const timer = setTimeout(() => {
19258
+ child.kill("SIGKILL");
19259
+ finish({
19260
+ kind: "unavailable",
19261
+ reason: `release ${input.releaseId} did not finish its probe within ${timeoutMs}ms`
19262
+ });
19263
+ }, timeoutMs);
19264
+ child.stdout.on("data", (chunk) => {
19265
+ stdout6 += chunk.toString();
19266
+ });
19267
+ child.stderr.on("data", (chunk) => {
19268
+ stderr += chunk.toString();
19269
+ });
19270
+ child.on("error", (error) => {
19271
+ finish({ kind: "unavailable", reason: `release ${input.releaseId} could not be spawned: ${error.message}` });
19272
+ });
19273
+ child.on("close", (code, signal) => {
19274
+ const lines = stdout6.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
19275
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
19276
+ const report = parseReport(lines[index]);
19277
+ if (report) {
19278
+ finish(outcomeFromReport(report));
19279
+ return;
19280
+ }
19281
+ }
19282
+ const tail = stderr.trim().split(/\r?\n/).slice(-3).join(" | ").slice(0, 300);
19283
+ finish({
19284
+ kind: "unavailable",
19285
+ reason: `release ${input.releaseId} printed no probe report (exit ${signal ?? code})` + (tail ? `: ${tail}` : "")
19286
+ });
19287
+ });
19288
+ });
19289
+ }
19290
+ async function runUpdateProbeCommand(args, options = {}) {
19291
+ const env = options.env ?? process.env;
19292
+ const write = options.write ?? ((line) => process.stdout.write(`${line}
19293
+ `));
19294
+ const configFlag = args.indexOf("--config");
19295
+ const configArg = configFlag >= 0 ? args[configFlag + 1] : void 0;
19296
+ if (!configArg)
19297
+ throw new Error(`${UPDATE_PROBE_COMMAND} requires --config <runtime.json>`);
19298
+ const configPath = await resolveRuntimeConfigPath(configArg);
19299
+ const runtime = await readRuntimeRecord(configPath);
19300
+ const agent = runtimeAgentCommand(runtime);
19301
+ const config = loadBodyConfig({
19302
+ workspaceRoot: join7(dirname14(configPath), "workspace"),
19303
+ llmEnvFile: runtime.llmEnvFile,
19304
+ env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
19305
+ agent
19306
+ });
19307
+ if (runtime.sharedSkills)
19308
+ config.sharedSkills = [...runtime.sharedSkills];
19309
+ if (runtime.modelSelection)
19310
+ config.modelSelection = runtime.modelSelection;
19311
+ config.runtimeConfigPath = configPath;
19312
+ const sandbox = detectBwrapSandbox({ ...runtime.sandbox ? { policy: runtime.sandbox } : {}, env });
19313
+ if (sandbox.path)
19314
+ config.bwrapPath = sandbox.path;
19315
+ if (runtime.sandboxMaskPaths?.length) {
19316
+ config.sandboxMaskPaths = [...config.sandboxMaskPaths ?? [], ...runtime.sandboxMaskPaths];
19317
+ }
19318
+ const layout = beelineInstallLayout(env);
19319
+ const releaseId = (layout && await activeReleaseId(layout).catch(() => void 0)) ?? "unknown";
19320
+ const runtimeDir = dirname14(configPath);
19321
+ const outcome = await probeOutcome(() => (options.probe ?? runUpdateFunctionalProbe)({
19322
+ config,
19323
+ runtimeDir,
19324
+ releaseId,
19325
+ sandboxRequired: runtime.sandbox !== "off",
19326
+ // The successor's probe still holds `<runtimeDir>/update-functional-probe`.
19327
+ probeRoot: join7(runtimeDir, "current-release-probe")
19328
+ }));
19329
+ const report = outcome.kind === "served" ? { probe: "served" } : outcome.kind === "refused" ? { probe: "refused", status: outcome.status, reason: outcome.reason } : { probe: "failed", reason: outcome.reason };
19330
+ write(JSON.stringify(report));
19331
+ }
19332
+
17983
19333
  // apps/body/dist/release-status.js
17984
- import { readFile as readFile8, readdir as readdir3, rename as rename6, writeFile as writeFile11 } from "node:fs/promises";
17985
- import { resolve as resolve20 } from "node:path";
19334
+ import { readFile as readFile12, readdir as readdir4, rename as rename6, writeFile as writeFile13 } from "node:fs/promises";
19335
+ import { resolve as resolve24 } from "node:path";
17986
19336
  var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
17987
19337
  var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
17988
19338
  var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
@@ -17999,9 +19349,9 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
17999
19349
  pid: options.pid ?? process.pid,
18000
19350
  readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
18001
19351
  };
18002
- const target = resolve20(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
19352
+ const target = resolve24(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
18003
19353
  const temporary = `${target}.${status.pid}.tmp`;
18004
- await writeFile11(temporary, `${JSON.stringify(status, null, 2)}
19354
+ await writeFile13(temporary, `${JSON.stringify(status, null, 2)}
18005
19355
  `, { mode: 384 });
18006
19356
  await rename6(temporary, target);
18007
19357
  return status;
@@ -18042,7 +19392,7 @@ var DaemonExitError = class extends Error {
18042
19392
  };
18043
19393
  async function runStoredDaemon(pathOrPointer) {
18044
19394
  const configPath = await resolveRuntimeConfigPath(pathOrPointer);
18045
- daemonFailureRuntimeDir = dirname13(configPath);
19395
+ daemonFailureRuntimeDir = dirname15(configPath);
18046
19396
  const accessMigration = await migrateRuntimeRecordAccessPolicy(configPath);
18047
19397
  let runtime = accessMigration.runtime;
18048
19398
  if (!runtime.transport) {
@@ -18054,7 +19404,7 @@ async function runStoredDaemon(pathOrPointer) {
18054
19404
  runtime = activated.runtime;
18055
19405
  const daemonApi = activated.client;
18056
19406
  const agent = runtimeAgentCommand(runtime);
18057
- await writeFile12(resolve21(dirname13(configPath), "daemon.pid"), `${process.pid}
19407
+ await writeFile14(resolve25(dirname15(configPath), "daemon.pid"), `${process.pid}
18058
19408
  `, { mode: 384 });
18059
19409
  const env = {
18060
19410
  ...process.env,
@@ -18062,7 +19412,7 @@ async function runStoredDaemon(pathOrPointer) {
18062
19412
  BUZZ_DEV_MCP_BIN: runtime.mcpBinary
18063
19413
  };
18064
19414
  const config = loadBodyConfig({
18065
- workspaceRoot: resolve21(dirname13(configPath), "workspace"),
19415
+ workspaceRoot: resolve25(dirname15(configPath), "workspace"),
18066
19416
  llmEnvFile: runtime.llmEnvFile,
18067
19417
  env,
18068
19418
  agent
@@ -18097,7 +19447,7 @@ async function runStoredDaemon(pathOrPointer) {
18097
19447
  const stop = () => controller.abort();
18098
19448
  process.once("SIGINT", stop);
18099
19449
  process.once("SIGTERM", stop);
18100
- const runtimeDir = dirname13(configPath);
19450
+ const runtimeDir = dirname15(configPath);
18101
19451
  const layout = beelineInstallLayout(process.env);
18102
19452
  const notifier = new SystemdNotifier();
18103
19453
  let rollbackAlertDrain;
@@ -18143,11 +19493,28 @@ async function runStoredDaemon(pathOrPointer) {
18143
19493
  let stoppingStatus = "daemon stopped";
18144
19494
  try {
18145
19495
  const core = new ThinDaemonCore(runtime, configPath, config, { daemonApi });
19496
+ const updateDrain = update ? new ManagedUpdateDrain({
19497
+ update,
19498
+ quiesceIfIdle: () => core.quiesceForUpdateIfIdle(),
19499
+ activeTurnCount: () => core.activeTurnCount(),
19500
+ restart: async ({ desiredRelease, drainDeadlineAt }, mode) => {
19501
+ if (mode === "forced")
19502
+ await core.prepareForForcedUpdateRestart();
19503
+ core.setDrainDeadlineAt(drainDeadlineAt);
19504
+ stoppingStatus = `update pending, converging; loaded_release=${loadedRelease ?? "unknown"}; desired_release=${desiredRelease}; ${mode === "forced" ? "active work cancelled at the drain deadline" : "active work drained"}; intake quiesced; exit_deadline=${new Date(drainDeadlineAt).toISOString()}`;
19505
+ await notifier.stopping(stoppingStatus);
19506
+ controller.abort();
19507
+ },
19508
+ waiting: async ({ desiredRelease, drainDeadlineAt }) => {
19509
+ await notifier.progress(`loaded_release=${loadedRelease ?? "unknown"}; update ready; active agent work is still running; handoff deferred; desired_release=${desiredRelease}; exit_deadline=${new Date(drainDeadlineAt).toISOString()}`);
19510
+ }
19511
+ }) : void 0;
18146
19512
  const result = await core.run({
18147
19513
  signal: controller.signal,
18148
19514
  onEstablished: async () => {
18149
19515
  let functionalProof;
18150
19516
  if (layout && pendingSuccessor) {
19517
+ const currentReleaseId = (await readUpdateAttempt(layout))?.previousReleaseId;
18151
19518
  const gate = await gateManagedSuccessor({
18152
19519
  layout,
18153
19520
  runtimeDir,
@@ -18157,7 +19524,18 @@ async function runStoredDaemon(pathOrPointer) {
18157
19524
  config,
18158
19525
  runtimeDir,
18159
19526
  releaseId: loadedRelease ?? "unknown",
18160
- sandboxRequired: runtime.sandbox !== "off"
19527
+ sandboxRequired: runtime.sandbox !== "off",
19528
+ ...currentReleaseId ? {
19529
+ compareWithCurrentRelease: async (refusal) => {
19530
+ console.warn(`[thin-core] successor probe refused by the provider (${refusal.reason}); probing the current release ${currentReleaseId} for the same refusal`);
19531
+ await extendSystemdStartTimeout(CURRENT_RELEASE_PROBE_TIMEOUT_MS + 15e3);
19532
+ return probeReleaseInSubprocess({
19533
+ layout,
19534
+ releaseId: currentReleaseId,
19535
+ runtimeConfigPath: configPath
19536
+ });
19537
+ }
19538
+ } : {}
18161
19539
  })
18162
19540
  });
18163
19541
  if (gate.kind === "failed") {
@@ -18166,28 +19544,26 @@ async function runStoredDaemon(pathOrPointer) {
18166
19544
  }
18167
19545
  functionalProof = gate.proof;
18168
19546
  pendingSuccessor = false;
18169
- console.log(`[thin-core] successor functional probe passed on exact release ${loadedRelease}: ${functionalProof?.harness ?? "unknown"} session/new + turn`);
19547
+ console.log(`[thin-core] successor functional probe passed on exact release ${loadedRelease}: ${functionalProof?.harness ?? "unknown"} session/new + turn` + (functionalProof?.modelAnswer === "unavailable" ? ` (model answer unavailable: ${functionalProof.modelAnswerReason})` : ""));
18170
19548
  }
18171
19549
  await clearDaemonStartFailures(runtimeDir);
18172
19550
  await writeDaemonReleaseStatus(runtimeDir, runtime.agent.publicKey, loadedReleaseIdentity);
18173
19551
  await notifier.ready(`ready; loaded_release=${loadedRelease ?? "development"}`);
18174
19552
  ready = true;
19553
+ void syncAgentModelCatalog({
19554
+ api: daemonApi,
19555
+ agent,
19556
+ agentEnv: config.agentEnv,
19557
+ agentId: runtime.agent.publicKey,
19558
+ workspaceId: runtime.communityId,
19559
+ runtimeDir,
19560
+ ...runtime.modelSelection ? { runtimeSelection: runtime.modelSelection } : {}
19561
+ });
18175
19562
  },
18176
19563
  onProgress: async (status) => {
18177
19564
  void drainRollbackAlert(core.activeRoomIds()[0] ?? runtime.rooms[0]?.channelId);
18178
19565
  await notifier.progress(`loaded_release=${loadedRelease ?? "development"}; ${status}`);
18179
- if (!update)
18180
- return;
18181
- await coordinateManagedUpdateHandoff(update, () => core.quiesceForUpdateIfIdle(), async ({ desiredRelease, drainDeadlineAt }) => {
18182
- if (Date.now() >= drainDeadlineAt)
18183
- await core.prepareForForcedUpdateRestart();
18184
- core.setDrainDeadlineAt(drainDeadlineAt);
18185
- stoppingStatus = `update pending, converging; loaded_release=${loadedRelease ?? "unknown"}; desired_release=${desiredRelease}; active work drained; intake quiesced; exit_deadline=${new Date(drainDeadlineAt).toISOString()}`;
18186
- await notifier.stopping(stoppingStatus);
18187
- controller.abort();
18188
- }, async ({ desiredRelease, drainDeadlineAt }) => {
18189
- await notifier.progress(`loaded_release=${loadedRelease ?? "unknown"}; update ready; active agent work is still running; handoff deferred; desired_release=${desiredRelease}; exit_deadline=${new Date(drainDeadlineAt).toISOString()}`);
18190
- });
19566
+ await updateDrain?.tick();
18191
19567
  }
18192
19568
  });
18193
19569
  if (result === "agent-removed") {
@@ -18209,8 +19585,8 @@ async function runStoredDaemon(pathOrPointer) {
18209
19585
  throw error;
18210
19586
  } finally {
18211
19587
  await notifier.stopping(stoppingStatus).catch(() => void 0);
18212
- const pidPath = resolve21(dirname13(configPath), "daemon.pid");
18213
- const recorded = Number((await readFile9(pidPath, "utf8").catch(() => "")).trim());
19588
+ const pidPath = resolve25(dirname15(configPath), "daemon.pid");
19589
+ const recorded = Number((await readFile13(pidPath, "utf8").catch(() => "")).trim());
18214
19590
  if (recorded === process.pid) {
18215
19591
  await unlink3(pidPath).catch(() => void 0);
18216
19592
  }
@@ -18266,20 +19642,24 @@ async function main() {
18266
19642
  const agentPubkey = agentFlag >= 0 ? args[agentFlag + 1] : void 0;
18267
19643
  if (!configPath && agentPubkey) {
18268
19644
  const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
18269
- configPath = configs.find((candidate) => dirname13(candidate).endsWith(agentPubkey));
19645
+ configPath = configs.find((candidate) => dirname15(candidate).endsWith(agentPubkey));
18270
19646
  }
18271
19647
  if (!configPath && agentPubkey) {
18272
19648
  throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing systemd restart loop`, UNKNOWN_AGENT_EXIT_STATUS);
18273
19649
  }
18274
19650
  if (!configPath)
18275
19651
  throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
18276
- await runStoredDaemon(resolve21(configPath));
19652
+ await runStoredDaemon(resolve25(configPath));
18277
19653
  return;
18278
19654
  }
18279
19655
  if (command === "update") {
18280
19656
  await runUpdateCommand(args);
18281
19657
  return;
18282
19658
  }
19659
+ if (command === UPDATE_PROBE_COMMAND) {
19660
+ await runUpdateProbeCommand(args);
19661
+ return;
19662
+ }
18283
19663
  if (command === "start") {
18284
19664
  await runStartCommand(args, interactiveUi);
18285
19665
  return;
@@ -18290,7 +19670,7 @@ async function main() {
18290
19670
  if (!agentPubkey)
18291
19671
  throw new Error("stop requires --agent <pubkey>");
18292
19672
  const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
18293
- const configPath = configs.find((candidate) => dirname13(candidate).endsWith(agentPubkey));
19673
+ const configPath = configs.find((candidate) => dirname15(candidate).endsWith(agentPubkey));
18294
19674
  if (!configPath)
18295
19675
  throw new Error(`no stored runtime found for agent ${agentPubkey}`);
18296
19676
  const runtime = await readRuntimeRecord(configPath);