usebeeline 0.0.132 → 0.0.134

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 +906 -1407
  2. package/package.json +1 -1
@@ -8713,13 +8713,13 @@ var init_esm = __esm({
8713
8713
  let count = last - first;
8714
8714
  while (count > 0) {
8715
8715
  let it = first;
8716
- let step4 = Math.floor(count / 2);
8717
- it += step4;
8716
+ let step3 = Math.floor(count / 2);
8717
+ it += step3;
8718
8718
  if (cmp(arr[it])) {
8719
8719
  first = ++it;
8720
- count -= step4 + 1;
8720
+ count -= step3 + 1;
8721
8721
  } else {
8722
- count = step4;
8722
+ count = step3;
8723
8723
  }
8724
8724
  }
8725
8725
  return first;
@@ -9349,10 +9349,210 @@ var init_runtime = __esm({
9349
9349
  }
9350
9350
  });
9351
9351
 
9352
+ // apps/body/dist/squire-broker-link.js
9353
+ import { randomUUID } from "node:crypto";
9354
+ import { createConnection } from "node:net";
9355
+ function frameLines(chunk, buffered, receive) {
9356
+ let input = Buffer.concat([buffered, chunk]);
9357
+ for (; ; ) {
9358
+ const end = input.indexOf(10);
9359
+ if (end < 0)
9360
+ return input;
9361
+ receive(input.subarray(0, end).toString("utf8"));
9362
+ input = input.subarray(end + 1);
9363
+ }
9364
+ }
9365
+ async function runSquireBrokerLink(options) {
9366
+ const { agentId, socketPath, giveUpMs = SQUIRE_RELAY_GIVE_UP_MS, input = process.stdin, output = process.stdout, logError = (message) => process.stderr.write(`${message}
9367
+ `), connect = (path) => createConnection(path), onShutdownSignal = (handler) => {
9368
+ process.once("SIGHUP", handler);
9369
+ process.once("SIGTERM", handler);
9370
+ process.once("SIGINT", handler);
9371
+ } } = options;
9372
+ let socket;
9373
+ let retryTimer;
9374
+ let disconnectedSince;
9375
+ let inBuffer = Buffer.alloc(0);
9376
+ let outBuffer = Buffer.alloc(0);
9377
+ let initializeLine;
9378
+ let initializedLine;
9379
+ let replayId;
9380
+ let delayMs = SQUIRE_RELAY_INITIAL_DELAY_MS;
9381
+ let stopped = false;
9382
+ let gaveUp = false;
9383
+ let connectedOnce = false;
9384
+ let ready = false;
9385
+ const pending = /* @__PURE__ */ new Map();
9386
+ const queued = [];
9387
+ let resolveDone;
9388
+ const done = new Promise((resolve40) => {
9389
+ resolveDone = resolve40;
9390
+ });
9391
+ const failResponse = (id) => `${JSON.stringify({
9392
+ jsonrpc: "2.0",
9393
+ id,
9394
+ error: { code: -32e3, message: "Trusty Squire broker connection lost" }
9395
+ })}
9396
+ `;
9397
+ const flush = () => {
9398
+ while (queued.length) {
9399
+ const line = queued.shift();
9400
+ const frame = JSON.parse(line);
9401
+ if (frame.id !== void 0 && frame.method)
9402
+ pending.set(JSON.stringify(frame.id), frame.id);
9403
+ socket?.write(`${line}
9404
+ `);
9405
+ }
9406
+ };
9407
+ function stop(ok2) {
9408
+ if (stopped)
9409
+ return;
9410
+ stopped = true;
9411
+ if (retryTimer)
9412
+ clearTimeout(retryTimer);
9413
+ socket?.destroy();
9414
+ resolveDone(ok2);
9415
+ }
9416
+ const giveUp = () => {
9417
+ if (gaveUp)
9418
+ return;
9419
+ gaveUp = true;
9420
+ logError(`${SQUIRE_BROKER_UNAVAILABLE}: ${TRUSTY_SQUIRE_BROKER_UNIT_NAME} is not reachable at ${socketPath}`);
9421
+ for (const id of pending.values())
9422
+ output.write(failResponse(id));
9423
+ pending.clear();
9424
+ for (const line of queued.splice(0)) {
9425
+ const frame = JSON.parse(line);
9426
+ if (frame.id !== void 0 && frame.method)
9427
+ output.write(failResponse(frame.id));
9428
+ }
9429
+ stop(false);
9430
+ };
9431
+ const reconnect = () => {
9432
+ if (stopped || retryTimer || gaveUp)
9433
+ return;
9434
+ disconnectedSince ??= Date.now();
9435
+ if (Date.now() - disconnectedSince >= giveUpMs) {
9436
+ giveUp();
9437
+ return;
9438
+ }
9439
+ retryTimer = setTimeout(() => {
9440
+ retryTimer = void 0;
9441
+ doConnect();
9442
+ }, delayMs);
9443
+ delayMs = Math.min(delayMs * 2, SQUIRE_RELAY_MAX_DELAY_MS);
9444
+ };
9445
+ const attach = (peer) => {
9446
+ if (stopped) {
9447
+ peer.destroy();
9448
+ return;
9449
+ }
9450
+ socket = peer;
9451
+ outBuffer = Buffer.alloc(0);
9452
+ peer.once("connect", () => {
9453
+ delayMs = SQUIRE_RELAY_INITIAL_DELAY_MS;
9454
+ disconnectedSince = void 0;
9455
+ peer.write(`${agentId}
9456
+ `);
9457
+ if (connectedOnce && initializeLine) {
9458
+ replayId = `beeline-squire-relay-${randomUUID()}`;
9459
+ const frame = JSON.parse(initializeLine);
9460
+ peer.write(`${JSON.stringify({ ...frame, id: replayId })}
9461
+ `);
9462
+ } else {
9463
+ ready = true;
9464
+ flush();
9465
+ }
9466
+ connectedOnce = true;
9467
+ });
9468
+ peer.on("data", (chunk) => {
9469
+ outBuffer = frameLines(chunk, outBuffer, (line) => {
9470
+ const frame = JSON.parse(line);
9471
+ if (frame.id === replayId) {
9472
+ replayId = void 0;
9473
+ if (frame.error) {
9474
+ peer.destroy(new Error("broker rejected relay initialization"));
9475
+ return;
9476
+ }
9477
+ if (initializedLine)
9478
+ peer.write(`${initializedLine}
9479
+ `);
9480
+ ready = true;
9481
+ flush();
9482
+ return;
9483
+ }
9484
+ if (frame.id !== void 0 && !frame.method)
9485
+ pending.delete(JSON.stringify(frame.id));
9486
+ output.write(`${line}
9487
+ `);
9488
+ });
9489
+ });
9490
+ peer.on("error", (error) => {
9491
+ if (!stopped)
9492
+ logError(`squire relay: ${error instanceof Error ? error.message : String(error)}`);
9493
+ });
9494
+ peer.once("close", () => {
9495
+ if (socket !== peer || stopped)
9496
+ return;
9497
+ socket = void 0;
9498
+ ready = false;
9499
+ replayId = void 0;
9500
+ for (const id of pending.values())
9501
+ output.write(failResponse(id));
9502
+ pending.clear();
9503
+ reconnect();
9504
+ });
9505
+ };
9506
+ const doConnect = () => {
9507
+ if (stopped)
9508
+ return;
9509
+ try {
9510
+ attach(connect(socketPath));
9511
+ } catch {
9512
+ reconnect();
9513
+ }
9514
+ };
9515
+ input.on("data", (chunk) => {
9516
+ inBuffer = frameLines(chunk, inBuffer, (line) => {
9517
+ const frame = JSON.parse(line);
9518
+ if (gaveUp) {
9519
+ if (frame.id !== void 0 && frame.method)
9520
+ output.write(failResponse(frame.id));
9521
+ return;
9522
+ }
9523
+ if (frame.method === "initialize")
9524
+ initializeLine = line;
9525
+ if (frame.method === "notifications/initialized")
9526
+ initializedLine = line;
9527
+ queued.push(line);
9528
+ if (ready)
9529
+ flush();
9530
+ });
9531
+ });
9532
+ const close = () => stop(!gaveUp);
9533
+ input.once("end", close);
9534
+ input.once("close", close);
9535
+ onShutdownSignal(close);
9536
+ doConnect();
9537
+ const ok = await done;
9538
+ return { ok };
9539
+ }
9540
+ var SQUIRE_RELAY_INITIAL_DELAY_MS, SQUIRE_RELAY_MAX_DELAY_MS, SQUIRE_RELAY_GIVE_UP_MS;
9541
+ var init_squire_broker_link = __esm({
9542
+ "apps/body/dist/squire-broker-link.js"() {
9543
+ "use strict";
9544
+ init_squire_host();
9545
+ SQUIRE_RELAY_INITIAL_DELAY_MS = 100;
9546
+ SQUIRE_RELAY_MAX_DELAY_MS = 1e3;
9547
+ SQUIRE_RELAY_GIVE_UP_MS = 1e4;
9548
+ }
9549
+ });
9550
+
9352
9551
  // apps/body/dist/squire-host.js
9353
9552
  import { spawn as spawn3 } from "node:child_process";
9354
- import { existsSync as existsSync2, lstatSync, mkdirSync } from "node:fs";
9553
+ import { accessSync, constants as fsConstants, existsSync as existsSync2, mkdirSync } from "node:fs";
9355
9554
  import { createRequire as createRequire2 } from "node:module";
9555
+ import { createConnection as createConnection2 } from "node:net";
9356
9556
  import { homedir as homedir2 } from "node:os";
9357
9557
  import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
9358
9558
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -9362,7 +9562,8 @@ function squireHostPaths(home) {
9362
9562
  dir,
9363
9563
  profileDir: join2(dir, "chrome-profile"),
9364
9564
  configHome: join2(resolve2(home), ".config"),
9365
- brokerSocket: join2(dir, "broker.sock")
9565
+ brokerSocket: join2(dir, "broker.sock"),
9566
+ mcpSocket: join2(dir, "mcp.sock")
9366
9567
  };
9367
9568
  }
9368
9569
  function squireHostRewriteEnv(home) {
@@ -9379,13 +9580,27 @@ function ensureSquireHostDir(home) {
9379
9580
  mkdirSync(paths.profileDir, { recursive: true, mode: 448 });
9380
9581
  return paths;
9381
9582
  }
9382
- function squireBrokerSocketReady(socketPath) {
9583
+ function squireHostDirWritable(socketPath) {
9383
9584
  try {
9384
- return lstatSync(socketPath).isSocket();
9585
+ accessSync(dirname2(socketPath), fsConstants.W_OK);
9586
+ return true;
9385
9587
  } catch {
9386
9588
  return false;
9387
9589
  }
9388
9590
  }
9591
+ async function squireBrokerSocketReady(socketPath) {
9592
+ return await new Promise((resolveReady) => {
9593
+ const probe = createConnection2(socketPath);
9594
+ probe.once("connect", () => {
9595
+ probe.destroy();
9596
+ resolveReady(true);
9597
+ });
9598
+ probe.once("error", () => {
9599
+ probe.destroy();
9600
+ resolveReady(false);
9601
+ });
9602
+ });
9603
+ }
9389
9604
  function squireFacadeLaunch(home, scope) {
9390
9605
  if (!scope.agentId || !scope.roomId)
9391
9606
  throw new Error("Squire agent and Room IDs are required");
@@ -9461,20 +9676,26 @@ function runSquireBroker(env = process.env) {
9461
9676
  const paths = ensureSquireHostDir(home);
9462
9677
  spawnSquireServer({ ...env, ...squireHostRewriteEnv(home), TRUSTY_SQUIRE_BROKER_SOCKET: paths.brokerSocket }, true, SQUIRE_BROKER_ARGS);
9463
9678
  }
9464
- function runSquireFacade(env = process.env) {
9679
+ async function runSquireFacade(env = process.env) {
9465
9680
  const socket = env.TRUSTY_SQUIRE_BROKER_SOCKET ?? squireHostPaths(env.HOME?.trim() || homedir2()).brokerSocket;
9466
- if (!squireBrokerSocketReady(socket)) {
9467
- process.stderr.write(`${SQUIRE_BROKER_UNAVAILABLE}
9681
+ if (!squireHostDirWritable(socket) || !await squireBrokerSocketReady(socket)) {
9682
+ process.stderr.write(`${SQUIRE_BROKER_UNAVAILABLE}: ${TRUSTY_SQUIRE_BROKER_UNIT_NAME} is not reachable at ${socket}
9468
9683
  `);
9469
9684
  process.exitCode = 1;
9470
9685
  return;
9471
9686
  }
9472
- spawnSquireServer({ ...env, TRUSTY_SQUIRE_BROKER_SOCKET: socket }, false, SQUIRE_SERVER_ARGS);
9687
+ const mcpSocket = join2(dirname2(socket), "mcp.sock");
9688
+ const { ok } = await runSquireBrokerLink({
9689
+ agentId: env.TRUSTY_SQUIRE_AGENT_IDENTITY?.trim() || "unknown",
9690
+ socketPath: mcpSocket
9691
+ });
9692
+ process.exit(ok ? 0 : 1);
9473
9693
  }
9474
9694
  var SQUIRE_BROKER_UNAVAILABLE, TRUSTY_SQUIRE_BROKER_UNIT_NAME, SQUIRE_FACADE_FLAG, SQUIRE_BROKER_FLAG, SQUIRE_SERVER_ARGS, SQUIRE_BROKER_ARGS;
9475
9695
  var init_squire_host = __esm({
9476
9696
  "apps/body/dist/squire-host.js"() {
9477
9697
  "use strict";
9698
+ init_squire_broker_link();
9478
9699
  SQUIRE_BROKER_UNAVAILABLE = "broker unavailable";
9479
9700
  TRUSTY_SQUIRE_BROKER_UNIT_NAME = "trusty-squire-broker.service";
9480
9701
  SQUIRE_FACADE_FLAG = "--squire-facade";
@@ -9513,7 +9734,7 @@ RestartPreventExitStatus=${DAEMON_DISTRESS_EXIT_STATUS} ${DELIBERATE_REMOVAL_EXI
9513
9734
  SuccessExitStatus=${UNKNOWN_AGENT_EXIT_STATUS}
9514
9735
  WatchdogSec=180s
9515
9736
  TimeoutStartSec=90s
9516
- TimeoutStopSec=10min
9737
+ TimeoutStopSec=90s
9517
9738
  KillMode=control-group
9518
9739
  UMask=0077
9519
9740
  # A desktop-launched user manager may inherit Ubuntu's unprivileged_userns
@@ -9736,7 +9957,7 @@ var init_systemd = __esm({
9736
9957
  UNKNOWN_AGENT_EXIT_STATUS = 79;
9737
9958
  SYSTEMD_UNIT_NAME = "beeline-agent@.service";
9738
9959
  SYSTEMD_COMMAND_TIMEOUT_MS = 15e3;
9739
- SYSTEMD_RESTART_WAIT_MS = 10 * 6e4 + 3e4;
9960
+ SYSTEMD_RESTART_WAIT_MS = 9e4 + 3e4;
9740
9961
  AGENT_SERVICE = /^beeline-agent@([0-9a-f]{64})\.service$/i;
9741
9962
  runSystemctl = async (args) => {
9742
9963
  const result = await execFileAsync2("systemctl", ["--user", ...args], {
@@ -10180,7 +10401,7 @@ __export(self_update_exports, {
10180
10401
  writeUpdateState: () => writeUpdateState
10181
10402
  });
10182
10403
  import { createHash } from "node:crypto";
10183
- import { constants as fsConstants } from "node:fs";
10404
+ import { constants as fsConstants2 } from "node:fs";
10184
10405
  import { access, chmod as chmod2, lstat, mkdir as mkdir4, open, readFile as readFile5, rename as rename3, rm as rm2, symlink, writeFile as writeFile4 } from "node:fs/promises";
10185
10406
  import { spawn as spawn4 } from "node:child_process";
10186
10407
  import { homedir as homedir5 } from "node:os";
@@ -10378,7 +10599,7 @@ function entrypointCandidates(bundleDir) {
10378
10599
  async function resolveBundleEntrypoint(bundleDir) {
10379
10600
  for (const candidate of entrypointCandidates(bundleDir)) {
10380
10601
  try {
10381
- await access(candidate, fsConstants.F_OK);
10602
+ await access(candidate, fsConstants2.F_OK);
10382
10603
  return candidate;
10383
10604
  } catch {
10384
10605
  }
@@ -10443,7 +10664,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
10443
10664
  throw new Error(`extracting bundle failed: ${extract2.stderr}`);
10444
10665
  for (const relative4 of requiredBundlePaths()) {
10445
10666
  try {
10446
- await access(join3(releaseDir, relative4), fsConstants.F_OK);
10667
+ await access(join3(releaseDir, relative4), fsConstants2.F_OK);
10447
10668
  } catch {
10448
10669
  throw new Error(`staged bundle is missing ${relative4}`);
10449
10670
  }
@@ -10488,7 +10709,7 @@ async function replaceFile(path, contents, mode) {
10488
10709
  }
10489
10710
  async function activateRelease(layout, releaseId) {
10490
10711
  const releaseDir = join3(layout.releasesRoot, releaseId);
10491
- await access(join3(releaseDir, BUNDLE_ENTRYPOINT), fsConstants.F_OK);
10712
+ await access(join3(releaseDir, BUNDLE_ENTRYPOINT), fsConstants2.F_OK);
10492
10713
  await mkdir4(layout.releasesRoot, { recursive: true });
10493
10714
  await mkdir4(layout.binDir, { recursive: true });
10494
10715
  let previousReleaseId = await activeReleaseId(layout);
@@ -10498,7 +10719,7 @@ async function activateRelease(layout, releaseId) {
10498
10719
  const legacyId = sanitizeReleaseId(legacyIdentity?.commit ?? legacyIdentity?.version ?? `legacy-${Date.now()}`);
10499
10720
  const legacyDir = join3(layout.releasesRoot, legacyId);
10500
10721
  try {
10501
- await access(legacyDir, fsConstants.F_OK);
10722
+ await access(legacyDir, fsConstants2.F_OK);
10502
10723
  previousReleaseId = `${legacyId}-${Date.now()}`;
10503
10724
  await rename3(layout.libDir, join3(layout.releasesRoot, previousReleaseId));
10504
10725
  await normalizeLegacyBundleShape(join3(layout.releasesRoot, previousReleaseId));
@@ -10521,7 +10742,7 @@ async function normalizeLegacyBundleShape(bundleDir) {
10521
10742
  let anyFlat = false;
10522
10743
  for (const name of LEGACY_FLAT_BUNDLE_FILES) {
10523
10744
  try {
10524
- await access(join3(bundleDir, name), fsConstants.F_OK);
10745
+ await access(join3(bundleDir, name), fsConstants2.F_OK);
10525
10746
  anyFlat = true;
10526
10747
  break;
10527
10748
  } catch {
@@ -10532,7 +10753,7 @@ async function normalizeLegacyBundleShape(bundleDir) {
10532
10753
  await mkdir4(innerLib, { recursive: true });
10533
10754
  for (const name of LEGACY_FLAT_BUNDLE_FILES) {
10534
10755
  try {
10535
- await access(join3(innerLib, name), fsConstants.F_OK);
10756
+ await access(join3(innerLib, name), fsConstants2.F_OK);
10536
10757
  continue;
10537
10758
  } catch {
10538
10759
  }
@@ -10547,7 +10768,7 @@ async function writeBinForwarders(layout, activeBundleRoot) {
10547
10768
  for (const [name, tool] of entries) {
10548
10769
  const target = join3(activeBundleRoot, "bin", tool);
10549
10770
  try {
10550
- await access(target, fsConstants.X_OK);
10771
+ await access(target, fsConstants2.X_OK);
10551
10772
  } catch {
10552
10773
  continue;
10553
10774
  }
@@ -11028,7 +11249,7 @@ import { createRequire as createRequire3 } from "node:module";
11028
11249
  import { createInterface as createInterface3 } from "node:readline";
11029
11250
  import { basename, dirname as dirname7, resolve as resolvePath } from "node:path";
11030
11251
  import { fileURLToPath as fileURLToPath3 } from "node:url";
11031
- import { randomUUID } from "node:crypto";
11252
+ import { randomUUID as randomUUID2 } from "node:crypto";
11032
11253
  function harnessIdentityLabel(agent) {
11033
11254
  if (agent.kind === "cursor")
11034
11255
  return CURSOR_ACP_BRIDGE_LABEL;
@@ -11092,7 +11313,7 @@ async function writeIsolatedCursorFile(path, content) {
11092
11313
  if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
11093
11314
  throw new Error(`isolated cursor parent is not a real directory: ${parent}`);
11094
11315
  }
11095
- const temporary = resolvePath(parent, `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`);
11316
+ const temporary = resolvePath(parent, `.${basename(path)}.${process.pid}.${randomUUID2()}.tmp`);
11096
11317
  try {
11097
11318
  await writeFile5(temporary, content, { mode: 384, flag: "wx" });
11098
11319
  await chmod3(temporary, 384);
@@ -11384,7 +11605,7 @@ var init_cursor_acp_bridge = __esm({
11384
11605
  });
11385
11606
  const catalog = await this.loadModels();
11386
11607
  const session = {
11387
- id: randomUUID(),
11608
+ id: randomUUID2(),
11388
11609
  cwd,
11389
11610
  ...systemPrompt ? { systemPrompt } : {},
11390
11611
  model: catalog.currentValue
@@ -11507,7 +11728,7 @@ var init_cursor_acp_bridge = __esm({
11507
11728
  });
11508
11729
  if (pending.length)
11509
11730
  consumeLine(pending.join(""));
11510
- const failure2 = describeCursorTurnFailure({
11731
+ const failure = describeCursorTurnFailure({
11511
11732
  isError: resultEvent ? cursorResultIsError(resultEvent) : false,
11512
11733
  resultText: resultEvent ? resultEventText(resultEvent) : void 0,
11513
11734
  exitCode: spawnError ? 1 : code,
@@ -11515,8 +11736,8 @@ var init_cursor_acp_bridge = __esm({
11515
11736
  stderr,
11516
11737
  spawnError
11517
11738
  });
11518
- if (failure2)
11519
- throw new Error(failure2);
11739
+ if (failure)
11740
+ throw new Error(failure);
11520
11741
  if (!sawAssistant) {
11521
11742
  const fallback = resultEvent && !cursorResultIsError(resultEvent) ? resultEventText(resultEvent) : "";
11522
11743
  if (fallback)
@@ -11558,7 +11779,7 @@ var init_cursor_acp_bridge = __esm({
11558
11779
 
11559
11780
  // apps/body/dist/agent-command.js
11560
11781
  import { execFile as execFile4, spawn as spawn7 } from "node:child_process";
11561
- import { accessSync, constants, existsSync as existsSync4, readdirSync } from "node:fs";
11782
+ import { accessSync as accessSync2, constants, existsSync as existsSync4, readdirSync } from "node:fs";
11562
11783
  import { readFile as readFile7 } from "node:fs/promises";
11563
11784
  import { homedir as homedir6 } from "node:os";
11564
11785
  import { delimiter, isAbsolute, join as join4, resolve as resolve7 } from "node:path";
@@ -11697,7 +11918,7 @@ function executableOnPath(name, env = process.env) {
11697
11918
  for (const directory of augmentedSearchDirectories(env)) {
11698
11919
  const candidate = resolve7(directory, name);
11699
11920
  try {
11700
- accessSync(candidate, constants.X_OK);
11921
+ accessSync2(candidate, constants.X_OK);
11701
11922
  return candidate;
11702
11923
  } catch {
11703
11924
  }
@@ -11709,7 +11930,7 @@ function requireExecutable(command, env, cwd, missingMessage) {
11709
11930
  const candidate = pathLike ? resolve7(cwd, command) : executableOnPath(command, env);
11710
11931
  if (candidate) {
11711
11932
  try {
11712
- accessSync(candidate, constants.X_OK);
11933
+ accessSync2(candidate, constants.X_OK);
11713
11934
  return candidate;
11714
11935
  } catch {
11715
11936
  }
@@ -14158,7 +14379,7 @@ var require_websocket = __commonJS({
14158
14379
  var http = __require("http");
14159
14380
  var net2 = __require("net");
14160
14381
  var tls = __require("tls");
14161
- var { randomBytes: randomBytes8, createHash: createHash14 } = __require("crypto");
14382
+ var { randomBytes: randomBytes8, createHash: createHash13 } = __require("crypto");
14162
14383
  var { Duplex, Readable } = __require("stream");
14163
14384
  var { URL: URL2 } = __require("url");
14164
14385
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -14826,7 +15047,7 @@ var require_websocket = __commonJS({
14826
15047
  abortHandshake(websocket, socket, "Invalid Upgrade header");
14827
15048
  return;
14828
15049
  }
14829
- const digest = createHash14("sha1").update(key + GUID).digest("base64");
15050
+ const digest = createHash13("sha1").update(key + GUID).digest("base64");
14830
15051
  if (res.headers["sec-websocket-accept"] !== digest) {
14831
15052
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
14832
15053
  return;
@@ -15195,7 +15416,7 @@ var require_websocket_server = __commonJS({
15195
15416
  var EventEmitter2 = __require("events");
15196
15417
  var http = __require("http");
15197
15418
  var { Duplex } = __require("stream");
15198
- var { createHash: createHash14 } = __require("crypto");
15419
+ var { createHash: createHash13 } = __require("crypto");
15199
15420
  var extension2 = require_extension();
15200
15421
  var PerMessageDeflate2 = require_permessage_deflate();
15201
15422
  var subprotocol2 = require_subprotocol();
@@ -15502,7 +15723,7 @@ var require_websocket_server = __commonJS({
15502
15723
  );
15503
15724
  }
15504
15725
  if (this._state > RUNNING) return abortHandshake(socket, 503);
15505
- const digest = createHash14("sha1").update(key + GUID).digest("base64");
15726
+ const digest = createHash13("sha1").update(key + GUID).digest("base64");
15506
15727
  const headers = [
15507
15728
  "HTTP/1.1 101 Switching Protocols",
15508
15729
  "Upgrade: websocket",
@@ -22925,8 +23146,6 @@ import { readFile } from "node:fs/promises";
22925
23146
  import { createInterface } from "node:readline";
22926
23147
 
22927
23148
  // packages/api-contract/dist/app-connections.js
22928
- var APP_TRANSPORTS = ["registry-mcp", "squire-api", "squire-browser"];
22929
- var APP_ROUTES = ["workbench", ...APP_TRANSPORTS];
22930
23149
  var APP_KEY_MAX_LENGTH = 63;
22931
23150
  var APP_INPUT_MAX_LENGTH = 200;
22932
23151
  var SECOND_LEVEL_SUFFIXES = /* @__PURE__ */ new Set(["co", "com", "net", "org", "gov", "edu", "ac"]);
@@ -23003,108 +23222,11 @@ function squireCallAppKeys(args) {
23003
23222
  return [...keys].sort();
23004
23223
  }
23005
23224
 
23006
- // packages/api-contract/dist/connector-adapter.js
23007
- var CONNECTOR_ADAPTER_DENIED = "connector not found (access denied)";
23008
- function ownerOnly(offered, action, requester) {
23009
- if (!offered.includes(action) || requester !== "owner") {
23010
- return { allowed: false, reason: CONNECTOR_ADAPTER_DENIED };
23011
- }
23012
- return { allowed: true };
23013
- }
23014
- var SQUIRE_ACTIONS = [
23015
- "connect",
23016
- "reconnect",
23017
- "disconnect",
23018
- "revoke-grants"
23019
- ];
23020
- var SQUIRE_CONNECTOR_ADAPTER = {
23021
- kind: "trusty-squire",
23022
- actions: SQUIRE_ACTIONS,
23023
- authorize: (action, requester) => ownerOnly(SQUIRE_ACTIONS, action, requester),
23024
- workbenchActions: (status) => {
23025
- switch (status) {
23026
- case "installing":
23027
- return ["disconnect"];
23028
- case "connected":
23029
- return ["reconnect", "disconnect", "revoke-grants"];
23030
- case "error":
23031
- return ["connect", "reconnect", "disconnect"];
23032
- default:
23033
- return ["connect"];
23034
- }
23035
- },
23036
- assignmentKinds: (status) => {
23037
- if (status === "installing")
23038
- return ["install"];
23039
- if (status === "disconnected")
23040
- return ["uninstall"];
23041
- return [];
23042
- }
23043
- };
23044
- var YOUTUBE_ACTIONS = [
23045
- "connect",
23046
- "reconnect",
23047
- "disconnect"
23048
- ];
23049
- var YOUTUBE_CONNECTOR_ADAPTER = {
23050
- kind: "google-youtube",
23051
- actions: YOUTUBE_ACTIONS,
23052
- authorize: (action, requester) => ownerOnly(YOUTUBE_ACTIONS, action, requester),
23053
- workbenchActions: (status) => {
23054
- switch (status) {
23055
- case "installing":
23056
- return ["disconnect"];
23057
- case "connected":
23058
- return ["reconnect", "disconnect"];
23059
- case "error":
23060
- return ["connect", "reconnect", "disconnect"];
23061
- default:
23062
- return ["connect"];
23063
- }
23064
- },
23065
- assignmentKinds: (status) => {
23066
- if (status === "installing")
23067
- return ["install"];
23068
- if (status === "disconnected")
23069
- return ["uninstall"];
23070
- if (status === "connected")
23071
- return ["refresh-google-grant"];
23072
- return [];
23073
- }
23074
- };
23075
- var ADAPTERS = {
23076
- "trusty-squire": SQUIRE_CONNECTOR_ADAPTER,
23077
- "google-youtube": YOUTUBE_CONNECTOR_ADAPTER
23078
- };
23079
- function connectorAdapter(kind) {
23080
- return ADAPTERS[kind];
23081
- }
23082
-
23083
23225
  // packages/api-contract/dist/workbench.js
23084
23226
  var CONNECTABLE_CONNECTOR_KINDS = [
23085
23227
  "trusty-squire",
23086
- "tailscale",
23087
- "google-gmail",
23088
- "google-calendar",
23089
- "google-drive",
23090
- "google-youtube"
23228
+ "tailscale"
23091
23229
  ];
23092
- var GOOGLE_TOOL_SCOPES = {
23093
- "google-gmail": [
23094
- "https://www.googleapis.com/auth/gmail.send",
23095
- "https://www.googleapis.com/auth/gmail.readonly",
23096
- "https://www.googleapis.com/auth/gmail.compose"
23097
- ],
23098
- "google-calendar": [
23099
- "https://www.googleapis.com/auth/calendar.events",
23100
- "https://www.googleapis.com/auth/calendar.readonly"
23101
- ],
23102
- "google-drive": ["https://www.googleapis.com/auth/drive.readonly"],
23103
- "google-youtube": [
23104
- "https://www.googleapis.com/auth/youtube.readonly",
23105
- "https://www.googleapis.com/auth/yt-analytics.readonly"
23106
- ]
23107
- };
23108
23230
 
23109
23231
  // apps/body/dist/resource-mcp-facade.js
23110
23232
  var RESOURCE_FACADE_FLAG = "--resource-mcp-facade";
@@ -23603,7 +23725,7 @@ function configureNetworkFamilyDefaults(network = net) {
23603
23725
  configureNetworkFamilyDefaults();
23604
23726
 
23605
23727
  // apps/body/dist/cli.js
23606
- import { dirname as dirname27, resolve as resolve39 } from "node:path";
23728
+ import { dirname as dirname26, resolve as resolve39 } from "node:path";
23607
23729
  import { stdin as stdin4, stdout as stdout5 } from "node:process";
23608
23730
 
23609
23731
  // node_modules/@clack/core/dist/index.mjs
@@ -25014,7 +25136,7 @@ var import_picocolors3 = __toESM(require_picocolors(), 1);
25014
25136
 
25015
25137
  // apps/body/dist/config.js
25016
25138
  init_agent_command();
25017
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
25139
+ import { accessSync as accessSync3, constants as constants2, existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
25018
25140
  import { basename as basename2, dirname as dirname8, resolve as resolve8 } from "node:path";
25019
25141
  function firstExisting2(paths) {
25020
25142
  for (const p of paths) {
@@ -25036,7 +25158,7 @@ function commandInRunningBundle(command) {
25036
25158
  ];
25037
25159
  for (const candidate of candidates) {
25038
25160
  try {
25039
- accessSync2(candidate, constants2.X_OK);
25161
+ accessSync3(candidate, constants2.X_OK);
25040
25162
  return candidate;
25041
25163
  } catch {
25042
25164
  }
@@ -25061,7 +25183,7 @@ function resolveReadonlyMcpCommand(env = process.env) {
25061
25183
  const configuredBinary = env.BEELINE_READONLY_MCP_BIN;
25062
25184
  if (configuredBinary) {
25063
25185
  try {
25064
- accessSync2(configuredBinary, constants2.X_OK);
25186
+ accessSync3(configuredBinary, constants2.X_OK);
25065
25187
  return { command: resolve8(configuredBinary), args: [] };
25066
25188
  } catch {
25067
25189
  throw new Error(`read-only tools unavailable: BEELINE_READONLY_MCP_BIN is not executable: ${configuredBinary}`);
@@ -25099,7 +25221,7 @@ function resolveCodegraphCommand(env = process.env) {
25099
25221
  const configured = env.BEELINE_CODEGRAPH_BIN ?? env.BUZZ_CODEGRAPH_BIN;
25100
25222
  if (configured) {
25101
25223
  try {
25102
- accessSync2(configured, constants2.X_OK);
25224
+ accessSync3(configured, constants2.X_OK);
25103
25225
  return resolve8(configured);
25104
25226
  } catch {
25105
25227
  return void 0;
@@ -25153,6 +25275,7 @@ var AGENT_ENV_PASSTHROUGH_NAMES = [
25153
25275
  "NODE_EXTRA_CA_CERTS",
25154
25276
  "NODE_OPTIONS",
25155
25277
  "OPENCODE_API_KEY",
25278
+ "GOOGLE_API_KEY",
25156
25279
  "http_proxy",
25157
25280
  "https_proxy",
25158
25281
  "no_proxy",
@@ -25194,7 +25317,6 @@ var AGENT_ENV_PASSTHROUGH_PREFIXES = [
25194
25317
  "OPENROUTER_",
25195
25318
  "AZURE_",
25196
25319
  "AWS_",
25197
- "GOOGLE_",
25198
25320
  "GEMINI_",
25199
25321
  "VERTEX_",
25200
25322
  "BEDROCK_",
@@ -25337,7 +25459,7 @@ init_cursor_acp_bridge();
25337
25459
  init_squire_host();
25338
25460
 
25339
25461
  // apps/body/dist/squire-task-relay.js
25340
- import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
25462
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
25341
25463
  import { createServer } from "node:http";
25342
25464
  import { readFile as readFile8 } from "node:fs/promises";
25343
25465
  import { createInterface as createInterface4 } from "node:readline";
@@ -26017,6 +26139,43 @@ function sessionIds(value, depth = 0) {
26017
26139
  function redactedSessionId(id) {
26018
26140
  return id ? createHash2("sha256").update(id).digest("hex").slice(0, 16) : null;
26019
26141
  }
26142
+ function staleLeaseResult(value) {
26143
+ if (!value || typeof value !== "object")
26144
+ return false;
26145
+ const result = value;
26146
+ if (result.isError !== true || !Array.isArray(result.content))
26147
+ return false;
26148
+ const text2 = result.content.find((entry) => entry && typeof entry === "object" && entry.type === "text")?.text;
26149
+ if (!text2)
26150
+ return false;
26151
+ try {
26152
+ const body = JSON.parse(text2);
26153
+ return body.error?.code === "stale_lease";
26154
+ } catch {
26155
+ return false;
26156
+ }
26157
+ }
26158
+ function resultStatus(value, depth = 0) {
26159
+ if (depth > 8 || !value)
26160
+ return void 0;
26161
+ if (typeof value === "string") {
26162
+ if (value.length > 1e5 || !value.trimStart().startsWith("{"))
26163
+ return void 0;
26164
+ try {
26165
+ return resultStatus(JSON.parse(value), depth + 1);
26166
+ } catch {
26167
+ return void 0;
26168
+ }
26169
+ }
26170
+ if (Array.isArray(value))
26171
+ return value.map((item2) => resultStatus(item2, depth + 1)).find(Boolean);
26172
+ if (typeof value !== "object")
26173
+ return void 0;
26174
+ const item = value;
26175
+ if (typeof item.status === "string")
26176
+ return item.status;
26177
+ return Object.values(item).map((entry) => resultStatus(entry, depth + 1)).find(Boolean);
26178
+ }
26020
26179
  var SquireTaskRelay = class {
26021
26180
  agentId;
26022
26181
  roomId;
@@ -26025,10 +26184,11 @@ var SquireTaskRelay = class {
26025
26184
  makeClient;
26026
26185
  server;
26027
26186
  url;
26028
- token = randomUUID2();
26187
+ token = randomUUID3();
26029
26188
  active;
26030
26189
  task;
26031
26190
  leaseTimer;
26191
+ approvalRequestId;
26032
26192
  closed = false;
26033
26193
  callTail = Promise.resolve();
26034
26194
  constructor(agentId, roomId, contextFile, authorize, home = homedir9(), makeClient = (callbacks) => new StdioSquireMcpClient({ scope: { agentId, roomId }, home, processGroup: true, ...callbacks })) {
@@ -26078,46 +26238,59 @@ var SquireTaskRelay = class {
26078
26238
  if (this.leaseTimer)
26079
26239
  clearTimeout(this.leaseTimer);
26080
26240
  this.leaseTimer = void 0;
26081
- if (this.task && this.task.taskId !== command.rootCommandId)
26082
- this.retire("task-ended");
26083
26241
  this.active = {
26084
26242
  roomId: command.roomId,
26085
26243
  requestId: command.turnRequestId,
26086
26244
  taskId: command.rootCommandId,
26087
26245
  generationId
26088
26246
  };
26089
- if (this.task)
26247
+ if (this.task) {
26248
+ this.task.taskId = command.rootCommandId;
26090
26249
  this.task.lastRequestId = command.turnRequestId;
26250
+ }
26091
26251
  }
26092
- deactivate(requestId, continuation = null) {
26252
+ deactivate(requestId, approvalRequestId) {
26093
26253
  if (this.active?.requestId !== requestId)
26094
26254
  return;
26095
- const taskId = this.active.taskId;
26096
26255
  this.active = void 0;
26097
- if (!this.task || this.task.taskId !== taskId)
26256
+ this.approvalRequestId = approvalRequestId;
26257
+ if (approvalRequestId)
26098
26258
  return;
26099
- if (continuation !== "grant-decision") {
26100
- this.retire("task-complete");
26259
+ this.scheduleIdle();
26260
+ }
26261
+ scheduleIdle() {
26262
+ if (this.leaseTimer)
26263
+ clearTimeout(this.leaseTimer);
26264
+ this.leaseTimer = void 0;
26265
+ if (!this.task || this.approvalRequestId || this.task.pendingApprovals.size)
26101
26266
  return;
26102
- }
26267
+ const task = this.task;
26103
26268
  this.leaseTimer = setTimeout(() => {
26104
26269
  this.leaseTimer = void 0;
26105
- if (!this.active && this.task?.taskId === taskId)
26106
- this.retire("task-lease-expired");
26270
+ if (!this.active && !this.approvalRequestId && !task.pendingApprovals.size && this.task === task)
26271
+ this.retire("conversation-idle");
26107
26272
  }, SQUIRE_TASK_IDLE_LEASE_MS);
26108
26273
  this.leaseTimer.unref?.();
26109
26274
  }
26110
26275
  cancel(requestId) {
26111
- if (this.active?.requestId !== requestId)
26276
+ if (this.active?.requestId !== requestId && this.approvalRequestId !== requestId && ![...this.task?.pendingApprovals.values() ?? []].some((approval) => approval.requestId === requestId))
26112
26277
  return;
26113
- this.active = void 0;
26114
- this.retire("cancelled");
26278
+ if (this.active?.requestId === requestId)
26279
+ this.active = void 0;
26280
+ if (this.approvalRequestId === requestId)
26281
+ this.approvalRequestId = void 0;
26282
+ for (const [id, approval] of this.task?.pendingApprovals ?? [])
26283
+ if (approval.requestId === requestId)
26284
+ this.task?.pendingApprovals.delete(id);
26285
+ if (!this.active && !this.approvalRequestId)
26286
+ this.scheduleIdle();
26115
26287
  }
26116
26288
  close() {
26117
26289
  if (this.closed)
26118
26290
  return;
26119
26291
  this.closed = true;
26120
26292
  this.active = void 0;
26293
+ this.approvalRequestId = void 0;
26121
26294
  this.retire("helper-exit");
26122
26295
  this.server?.close();
26123
26296
  }
@@ -26126,6 +26299,7 @@ var SquireTaskRelay = class {
26126
26299
  console.info("[squire-task]", JSON.stringify({
26127
26300
  event,
26128
26301
  agentId: this.agentId,
26302
+ conversationId: this.roomId,
26129
26303
  taskId: task.taskId,
26130
26304
  requestId: this.active?.requestId ?? task.lastRequestId,
26131
26305
  squireSessionId: sessionId ?? null,
@@ -26141,8 +26315,9 @@ var SquireTaskRelay = class {
26141
26315
  const task = {
26142
26316
  taskId,
26143
26317
  lastRequestId: this.active?.requestId ?? "",
26144
- connectionId: randomUUID2(),
26318
+ connectionId: randomUUID3(),
26145
26319
  sessions: /* @__PURE__ */ new Set(),
26320
+ pendingApprovals: /* @__PURE__ */ new Map(),
26146
26321
  dead: false
26147
26322
  };
26148
26323
  task.client = this.makeClient({
@@ -26155,6 +26330,7 @@ var SquireTaskRelay = class {
26155
26330
  sessionId: redactedSessionId(task.sessions.values().next().value)
26156
26331
  });
26157
26332
  task.sessions.clear();
26333
+ task.pendingApprovals.clear();
26158
26334
  }
26159
26335
  });
26160
26336
  this.task = task;
@@ -26172,6 +26348,7 @@ var SquireTaskRelay = class {
26172
26348
  });
26173
26349
  this.task.client.close();
26174
26350
  this.task.sessions.clear();
26351
+ this.task.pendingApprovals.clear();
26175
26352
  this.task = void 0;
26176
26353
  }
26177
26354
  handle(input) {
@@ -26208,9 +26385,13 @@ var SquireTaskRelay = class {
26208
26385
  this.log("call-end", task, { method: input.method, source: "cached" });
26209
26386
  return task.tools;
26210
26387
  }
26388
+ if (input.method === "tools/call" && task.dead && toolName2 !== "operate_start") {
26389
+ this.log("call-refused", task, { reason: "connection-died" });
26390
+ throw new Error("Squire MCP connection died and its browser session is gone; call operate_start");
26391
+ }
26211
26392
  if (input.method === "tools/call" && (!safeToolName || requestedIds.some((id) => !task.sessions.has(id)))) {
26212
26393
  this.log("call-refused", task, { reason: "session-not-owned" });
26213
- throw new Error("Squire browser session is no longer owned by this task; call operate_start");
26394
+ throw new Error("Squire browser session is no longer owned by this conversation; call operate_start");
26214
26395
  }
26215
26396
  if (input.method === "tools/call" && !await this.authorize({
26216
26397
  ...active,
@@ -26234,8 +26415,47 @@ var SquireTaskRelay = class {
26234
26415
  throw new Error("Squire task ended while the call was running");
26235
26416
  if (input.method === "tools/list")
26236
26417
  task.tools = result;
26237
- for (const id of sessionIds(result))
26238
- task.sessions.add(id);
26418
+ if (staleLeaseResult(result)) {
26419
+ for (const id of requestedIds)
26420
+ task.sessions.delete(id);
26421
+ this.releasePendingApprovals(task, requestedIds);
26422
+ this.log("call-error", task, {
26423
+ method: input.method,
26424
+ tool: safeToolName ?? null,
26425
+ reason: "stale-lease",
26426
+ sessionId: redactedSessionId(requestedIds[0])
26427
+ });
26428
+ return { isError: true, content: [{ type: "text", text: JSON.stringify({
26429
+ error: { code: "stale_lease", message: "Squire browser session is gone; call operate_start for a fresh session" }
26430
+ }) }] };
26431
+ }
26432
+ if (safeToolName === "operate_finish" && !(result && typeof result === "object" && result.isError === true)) {
26433
+ for (const id of requestedIds)
26434
+ task.sessions.delete(id);
26435
+ this.releasePendingApprovals(task, requestedIds);
26436
+ } else {
26437
+ for (const id of sessionIds(result))
26438
+ task.sessions.add(id);
26439
+ }
26440
+ const approval = input.method === "tools/call" && squireApprovalFromMcp({ id: 1, method: input.method, params: input.params }, { id: 1, result });
26441
+ if (approval) {
26442
+ const ids = requestedIds.length ? requestedIds : [...task.sessions];
26443
+ const approvalKey = createHash2("sha256").update(approval.approvalId ?? approval.approvalUrl).digest("hex");
26444
+ const status = resultStatus(result);
26445
+ const pending = status === "approval_pending" || status === "pending_approval";
26446
+ if (pending && ids.length) {
26447
+ task.pendingApprovals.set(approvalKey, {
26448
+ requestId: active.requestId,
26449
+ sessionIds: new Set(ids)
26450
+ });
26451
+ this.log("approval-pending", task, {
26452
+ tool: safeToolName ?? null,
26453
+ sessionId: redactedSessionId(ids[0])
26454
+ });
26455
+ } else if (!pending) {
26456
+ task.pendingApprovals.delete(approvalKey);
26457
+ }
26458
+ }
26239
26459
  this.log("call-end", task, {
26240
26460
  method: input.method,
26241
26461
  tool: safeToolName ?? null,
@@ -26246,6 +26466,7 @@ var SquireTaskRelay = class {
26246
26466
  if (error instanceof Error && /timed out/.test(error.message)) {
26247
26467
  task.dead = true;
26248
26468
  task.sessions.clear();
26469
+ task.pendingApprovals.clear();
26249
26470
  task.client.close();
26250
26471
  }
26251
26472
  this.log("call-error", task, {
@@ -26253,9 +26474,19 @@ var SquireTaskRelay = class {
26253
26474
  tool: safeToolName ?? null,
26254
26475
  sessionId: redactedSessionId(requestedIds[0] ?? task.sessions.values().next().value)
26255
26476
  });
26477
+ if (task.dead)
26478
+ throw new Error("Squire MCP connection died and its browser session is gone; call operate_start");
26256
26479
  throw error;
26257
26480
  }
26258
26481
  }
26482
+ releasePendingApprovals(task, sessionIdsToRelease) {
26483
+ for (const [id, approval] of task.pendingApprovals) {
26484
+ for (const sessionId of sessionIdsToRelease)
26485
+ approval.sessionIds.delete(sessionId);
26486
+ if (!approval.sessionIds.size)
26487
+ task.pendingApprovals.delete(id);
26488
+ }
26489
+ }
26259
26490
  };
26260
26491
  function runSquireTaskProxy(env = process.env) {
26261
26492
  const url = env.BEELINE_SQUIRE_RELAY_URL;
@@ -26310,7 +26541,7 @@ function isAllowedAgentModelConfigCategory(category, id) {
26310
26541
  }
26311
26542
 
26312
26543
  // apps/body/dist/model-config.js
26313
- import { lstatSync as lstatSync2, readFileSync as readFileSync3 } from "node:fs";
26544
+ import { lstatSync, readFileSync as readFileSync3 } from "node:fs";
26314
26545
  import { basename as basename3, resolve as resolve9 } from "node:path";
26315
26546
  var GROK_SESSION_MODEL_AXIS_ID = "beeline:grok-session-model";
26316
26547
  var GROK_LAUNCH_EFFORT_AXIS_ID = "beeline:grok-launch-reasoning-effort";
@@ -26486,7 +26717,7 @@ function credentialedPiCustomProviders(env) {
26486
26717
  return held;
26487
26718
  const path = resolve9(agentDir, "models.json");
26488
26719
  try {
26489
- const stats = lstatSync2(path);
26720
+ const stats = lstatSync(path);
26490
26721
  if (!stats.isFile() || stats.isSymbolicLink() || stats.nlink !== 1 || stats.size > 1048576) {
26491
26722
  return held;
26492
26723
  }
@@ -27923,519 +28154,12 @@ async function syncAgentModelCatalog(input) {
27923
28154
  }
27924
28155
  }
27925
28156
 
27926
- // apps/body/dist/connector-google.js
27927
- import { mkdirSync as mkdirSync2, writeFileSync } from "node:fs";
27928
- import { dirname as dirname9, join as join5 } from "node:path";
27929
-
27930
- // apps/body/dist/google-workspace-client.js
27931
- function credentialsTokenSource(credentials) {
27932
- return {
27933
- accessToken: () => Promise.resolve(credentials.accessToken),
27934
- accountEmail: credentials.accountEmail ? () => credentials.accountEmail : void 0
27935
- };
27936
- }
27937
- var googleOAuthTokenTransport = {
27938
- async request(method, url, body) {
27939
- const fields = body && typeof body === "object" ? body : {};
27940
- const response = await fetch(url, {
27941
- method,
27942
- headers: { "content-type": "application/x-www-form-urlencoded" },
27943
- body: new URLSearchParams(fields).toString()
27944
- });
27945
- let json = null;
27946
- const text2 = await response.text();
27947
- if (text2) {
27948
- try {
27949
- json = JSON.parse(text2);
27950
- } catch {
27951
- json = { raw: text2 };
27952
- }
27953
- }
27954
- return { status: response.status, json };
27955
- }
27956
- };
27957
- async function refreshGoogleAccessToken(credentials, clientId, clientSecret, transport = googleOAuthTokenTransport) {
27958
- if (!credentials.refreshToken) {
27959
- throw new GoogleApiError(401, "Google grant has no refresh token; reconnect Google Workspace");
27960
- }
27961
- const response = await transport.request("POST", "https://oauth2.googleapis.com/token", {
27962
- client_id: clientId,
27963
- client_secret: clientSecret,
27964
- refresh_token: credentials.refreshToken,
27965
- grant_type: "refresh_token"
27966
- });
27967
- if (response.status >= 300) {
27968
- throw new GoogleApiError(response.status, "Google refused to refresh the access token");
27969
- }
27970
- const payload = response.json;
27971
- if (!payload.access_token) {
27972
- throw new GoogleApiError(401, "Google refresh returned no access token");
27973
- }
27974
- return {
27975
- ...credentials,
27976
- accessToken: payload.access_token,
27977
- expiresAt: typeof payload.expires_in === "number" ? Date.now() + payload.expires_in * 1e3 : void 0
27978
- };
27979
- }
27980
- function refreshableTokenSource(credentials, clientId, clientSecret, transport = googleOAuthTokenTransport) {
27981
- let current = credentials;
27982
- return {
27983
- async accessToken() {
27984
- const stale = current.expiresAt !== void 0 && current.expiresAt <= Date.now() + 3e4;
27985
- if (stale && clientId && clientSecret && current.refreshToken) {
27986
- current = await refreshGoogleAccessToken(current, clientId, clientSecret, transport);
27987
- }
27988
- return current.accessToken;
27989
- },
27990
- accountEmail: current.accountEmail ? () => current.accountEmail : void 0
27991
- };
27992
- }
27993
- var defaultGoogleApiTransport = {
27994
- async request(method, url, body, headers) {
27995
- const response = await fetch(url, {
27996
- method,
27997
- headers: {
27998
- "content-type": "application/json",
27999
- ...headers
28000
- },
28001
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
28002
- });
28003
- let json = null;
28004
- const text2 = await response.text();
28005
- if (text2) {
28006
- try {
28007
- json = JSON.parse(text2);
28008
- } catch {
28009
- json = { raw: text2 };
28010
- }
28011
- }
28012
- return { status: response.status, json };
28013
- }
28014
- };
28015
- var GoogleApiError = class extends Error {
28016
- status;
28017
- detail;
28018
- constructor(status, detail) {
28019
- super(`Google API ${status}: ${detail}`);
28020
- this.status = status;
28021
- this.detail = detail;
28022
- }
28023
- };
28024
- var MAX_RESULTS = 25;
28025
- function assertOk(status, json) {
28026
- if (status >= 200 && status < 300)
28027
- return;
28028
- const detail = json && typeof json === "object" && "error" in json ? JSON.stringify(json.error) : `HTTP ${status}`;
28029
- throw new GoogleApiError(status, detail);
28030
- }
28031
- var YOUTUBE_ANALYTICS_OWNER_LIMIT = "YouTube Analytics requires the Google account that owns the channel, not a manager.";
28032
- function defaultAnalyticsDateRange(days = 28, now2 = /* @__PURE__ */ new Date()) {
28033
- const end = new Date(Date.UTC(now2.getUTCFullYear(), now2.getUTCMonth(), now2.getUTCDate()));
28034
- const start = new Date(end);
28035
- start.setUTCDate(start.getUTCDate() - days);
28036
- return { startDate: start.toISOString().slice(0, 10), endDate: end.toISOString().slice(0, 10) };
28037
- }
28038
- function rfc822(input) {
28039
- return `To: ${input.to}\r
28040
- Subject: ${input.subject}\r
28041
- Content-Type: text/plain; charset="UTF-8"\r
28042
- \r
28043
- ${input.body}`;
28044
- }
28045
- function googleWorkspaceClient(tokenSource, transport = defaultGoogleApiTransport) {
28046
- const authorized = {
28047
- async request(method, url, body) {
28048
- const token = await tokenSource.accessToken();
28049
- const response = await transport.request(method, url, body, {
28050
- authorization: `Bearer ${token}`
28051
- });
28052
- if (response.status === 401) {
28053
- throw new GoogleApiError(401, "access token rejected; reconnect the Google tool");
28054
- }
28055
- return response;
28056
- }
28057
- };
28058
- const gmailFetch = async (path) => {
28059
- const { status, json } = await authorized.request("GET", `https://gmail.googleapis.com/gmail/v1/users/me${path}`);
28060
- assertOk(status, json);
28061
- return json;
28062
- };
28063
- return {
28064
- gmail: {
28065
- async listMessages(query) {
28066
- const params = new URLSearchParams({ maxResults: String(MAX_RESULTS) });
28067
- if (query)
28068
- params.set("q", query);
28069
- const { status, json } = await authorized.request("GET", `https://gmail.googleapis.com/gmail/v1/users/me/messages?${params}`);
28070
- assertOk(status, json);
28071
- const messages = json.messages ?? [];
28072
- return messages.map((entry) => ({ id: entry.id, snippet: entry.snippet }));
28073
- },
28074
- async getMessage(id) {
28075
- const message = await gmailFetch(`/messages/${encodeURIComponent(id)}?format=metadata`);
28076
- const snippet = typeof message.snippet === "string" ? message.snippet : void 0;
28077
- const payload = message.payload;
28078
- const subject = payload?.headers?.find((header) => header.name === "Subject")?.value;
28079
- const bodyText = payload?.body?.data !== void 0 ? Buffer.from(payload.body.data, "base64url").toString("utf8") : void 0;
28080
- return { id, snippet: subject ?? snippet, body: bodyText };
28081
- },
28082
- async createDraft(input) {
28083
- const { status, json } = await authorized.request("POST", "https://gmail.googleapis.com/gmail/v1/users/me/drafts", { message: { raw: Buffer.from(rfc822(input), "utf8").toString("base64url") } });
28084
- assertOk(status, json);
28085
- return { id: String(json.id) };
28086
- },
28087
- async sendMessage(input) {
28088
- const raw = Buffer.from(rfc822(input), "utf8").toString("base64url");
28089
- const { status, json } = await authorized.request("POST", "https://gmail.googleapis.com/gmail/v1/users/me/messages/send", { raw });
28090
- assertOk(status, json);
28091
- return { id: String(json.id) };
28092
- }
28093
- },
28094
- calendar: {
28095
- async listEvents(input) {
28096
- const params = new URLSearchParams({
28097
- maxResults: String(input?.maxResults ?? MAX_RESULTS),
28098
- singleEvents: "true",
28099
- orderBy: "startTime",
28100
- timeMin: (/* @__PURE__ */ new Date()).toISOString()
28101
- });
28102
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/calendar/v3/calendars/primary/events?${params}`);
28103
- assertOk(status, json);
28104
- const events = json.items ?? [];
28105
- return events.map((event) => ({
28106
- id: String(event.id),
28107
- summary: typeof event.summary === "string" ? event.summary : void 0,
28108
- start: event.start?.dateTime,
28109
- end: event.end?.dateTime
28110
- }));
28111
- },
28112
- async createEvent(input) {
28113
- const { status, json } = await authorized.request("POST", `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(input.calendarId ?? "primary")}/events`, {
28114
- summary: input.summary,
28115
- ...input.description ? { description: input.description } : {},
28116
- start: { dateTime: input.start },
28117
- end: { dateTime: input.end }
28118
- });
28119
- assertOk(status, json);
28120
- const event = json;
28121
- return { id: event.id, ...event.htmlLink ? { htmlLink: event.htmlLink } : {} };
28122
- }
28123
- },
28124
- drive: {
28125
- async listFiles() {
28126
- const params = new URLSearchParams({
28127
- q: "trashed = false",
28128
- pageSize: String(MAX_RESULTS),
28129
- fields: "files(id,name,mimeType)"
28130
- });
28131
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files?${params}`);
28132
- assertOk(status, json);
28133
- return (json.files ?? []).map((file) => ({
28134
- id: String(file.id),
28135
- name: typeof file.name === "string" ? file.name : void 0,
28136
- mimeType: typeof file.mimeType === "string" ? file.mimeType : void 0
28137
- }));
28138
- },
28139
- async searchFiles(query) {
28140
- const params = new URLSearchParams({
28141
- q: `name contains '${query.replace(/'/g, "\\'")}' and trashed = false`,
28142
- pageSize: String(MAX_RESULTS),
28143
- fields: "files(id,name,mimeType)"
28144
- });
28145
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files?${params}`);
28146
- assertOk(status, json);
28147
- return (json.files ?? []).map((file) => ({
28148
- id: String(file.id),
28149
- name: typeof file.name === "string" ? file.name : void 0,
28150
- mimeType: typeof file.mimeType === "string" ? file.mimeType : void 0
28151
- }));
28152
- },
28153
- async readFile(fileId) {
28154
- const meta = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}?fields=id,name`);
28155
- assertOk(meta.status, meta.json);
28156
- const content = await authorized.request("GET", `https://www.googleapis.com/drive/v3/files/${encodeURIComponent(fileId)}?alt=media`);
28157
- assertOk(content.status, content.json);
28158
- const body = content.json;
28159
- return {
28160
- id: fileId,
28161
- name: meta.json.name,
28162
- content: body.raw ?? JSON.stringify(content.json)
28163
- };
28164
- }
28165
- },
28166
- youtube: {
28167
- async getChannel(mine = true) {
28168
- const params = new URLSearchParams({
28169
- part: "snippet,statistics",
28170
- maxResults: "1",
28171
- ...mine ? { mine: "true" } : {}
28172
- });
28173
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/channels?${params}`);
28174
- assertOk(status, json);
28175
- const item = (json.items ?? [])[0];
28176
- if (!item)
28177
- throw new GoogleApiError(404, "no YouTube channel on this Google account");
28178
- const snippet = item.snippet ?? {};
28179
- const statistics = item.statistics ?? {};
28180
- return {
28181
- id: String(item.id),
28182
- ...typeof snippet.title === "string" ? { title: snippet.title } : {},
28183
- ...typeof snippet.customUrl === "string" ? { handle: snippet.customUrl } : {},
28184
- ...typeof statistics.subscriberCount === "string" ? { subscriberCount: statistics.subscriberCount } : {}
28185
- };
28186
- },
28187
- async listVideos() {
28188
- const params = new URLSearchParams({
28189
- part: "snippet",
28190
- forMine: "true",
28191
- type: "video",
28192
- maxResults: String(MAX_RESULTS)
28193
- });
28194
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/search?${params}`);
28195
- assertOk(status, json);
28196
- return (json.items ?? []).map((item) => ({
28197
- videoId: String(item.id?.videoId ?? item.id),
28198
- title: item.snippet?.title
28199
- }));
28200
- },
28201
- async getVideo(videoId) {
28202
- const params = new URLSearchParams({
28203
- part: "snippet,statistics",
28204
- id: videoId
28205
- });
28206
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/videos?${params}`);
28207
- assertOk(status, json);
28208
- const item = (json.items ?? [])[0];
28209
- if (!item)
28210
- throw new GoogleApiError(404, `video ${videoId} was not found`);
28211
- const snippet = item.snippet ?? {};
28212
- const statistics = item.statistics ?? {};
28213
- return {
28214
- id: String(item.id),
28215
- ...typeof snippet.title === "string" ? { title: snippet.title } : {},
28216
- ...typeof snippet.description === "string" ? { description: snippet.description } : {},
28217
- ...typeof statistics.viewCount === "string" ? { viewCount: statistics.viewCount } : {}
28218
- };
28219
- },
28220
- async listPlaylists(mine = true) {
28221
- const params = new URLSearchParams({
28222
- part: "snippet",
28223
- maxResults: String(MAX_RESULTS),
28224
- ...mine ? { mine: "true" } : {}
28225
- });
28226
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/playlists?${params}`);
28227
- assertOk(status, json);
28228
- return (json.items ?? []).map((item) => ({
28229
- id: String(item.id),
28230
- title: item.snippet?.title
28231
- }));
28232
- },
28233
- async listPlaylistItems(playlistId) {
28234
- const params = new URLSearchParams({
28235
- part: "snippet",
28236
- maxResults: String(MAX_RESULTS),
28237
- playlistId
28238
- });
28239
- const { status, json } = await authorized.request("GET", `https://www.googleapis.com/youtube/v3/playlistItems?${params}`);
28240
- assertOk(status, json);
28241
- return (json.items ?? []).map((item) => ({
28242
- videoId: String(item.snippet?.resourceId?.videoId ?? item.id),
28243
- title: item.snippet?.title
28244
- }));
28245
- },
28246
- async getTranscript(videoId) {
28247
- const params = new URLSearchParams({ lang: "en", v: videoId });
28248
- const { status, json } = await authorized.request("GET", `https://video.google.com/timedtext?${params}`);
28249
- if (status < 200 || status >= 300) {
28250
- throw new GoogleApiError(status, `no caption track could be fetched for ${videoId} (timedtext ${status})`);
28251
- }
28252
- const raw = json.raw ?? "";
28253
- const transcript = raw.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
28254
- if (!transcript) {
28255
- throw new GoogleApiError(404, `video ${videoId} has no fetchable captions`);
28256
- }
28257
- return { videoId, transcript };
28258
- },
28259
- async analyticsQuery(input) {
28260
- const range = input.startDate && input.endDate ? { startDate: input.startDate, endDate: input.endDate } : defaultAnalyticsDateRange();
28261
- const params = new URLSearchParams({
28262
- ids: "channel==MINE",
28263
- startDate: range.startDate,
28264
- endDate: range.endDate,
28265
- metrics: input.metrics
28266
- });
28267
- if (input.dimensions)
28268
- params.set("dimensions", input.dimensions);
28269
- if (input.filters)
28270
- params.set("filters", input.filters);
28271
- if (input.sort)
28272
- params.set("sort", input.sort);
28273
- if (input.maxResults)
28274
- params.set("maxResults", String(input.maxResults));
28275
- const { status, json } = await authorized.request("GET", `https://youtubeanalytics.googleapis.com/v2/reports?${params}`);
28276
- if (status === 403) {
28277
- throw new GoogleApiError(403, YOUTUBE_ANALYTICS_OWNER_LIMIT);
28278
- }
28279
- assertOk(status, json);
28280
- const report = json;
28281
- const columns = (report.columnHeaders ?? []).map((header) => header.name);
28282
- const results = (report.rows ?? []).map((row) => {
28283
- const record6 = {};
28284
- columns.forEach((column, index) => {
28285
- record6[column] = row[index];
28286
- });
28287
- return record6;
28288
- });
28289
- return {
28290
- startDate: range.startDate,
28291
- endDate: range.endDate,
28292
- columns,
28293
- results,
28294
- totalRows: results.length
28295
- };
28296
- }
28297
- },
28298
- async verify() {
28299
- try {
28300
- const { status, json } = await authorized.request("GET", "https://www.googleapis.com/oauth2/v3/userinfo");
28301
- if (status === 401)
28302
- return { ok: false, reason: "Google rejected the access token" };
28303
- assertOk(status, json);
28304
- const email = json.email;
28305
- return { ok: true, ...email ? { account: email } : {} };
28306
- } catch (error) {
28307
- return {
28308
- ok: false,
28309
- reason: error instanceof Error ? error.message : String(error)
28310
- };
28311
- }
28312
- }
28313
- };
28314
- }
28315
-
28316
- // apps/body/dist/connector-google.js
28317
- function isGoogleToolConnectorType(type) {
28318
- return Object.hasOwn(GOOGLE_TOOL_SCOPES, type);
28319
- }
28320
- function manualGoogleCredentialsSearchPaths(home) {
28321
- return [join5(home, "google-credentials.json")];
28322
- }
28323
- function persistManualGoogleCredentials(home, credentials) {
28324
- const path = manualGoogleCredentialsSearchPaths(home)[0];
28325
- mkdirSync2(dirname9(path), { recursive: true, mode: 448 });
28326
- writeFileSync(path, `${JSON.stringify({
28327
- accessToken: credentials.accessToken,
28328
- ...credentials.expiresAt ? { expiresAt: credentials.expiresAt } : {},
28329
- ...credentials.accountEmail ? { accountEmail: credentials.accountEmail } : {},
28330
- ...credentials.scopes ? { scopes: credentials.scopes } : {}
28331
- })}
28332
- `, { encoding: "utf8", mode: 384 });
28333
- return path;
28334
- }
28335
- var step2 = (label, status, extra) => ({
28336
- label,
28337
- status,
28338
- ...extra
28339
- });
28340
- function outputTail(text2, maxChars = 800) {
28341
- const trimmed = text2.trim();
28342
- return trimmed.length <= maxChars ? trimmed : `\u2026${trimmed.slice(-maxChars)}`;
28343
- }
28344
- async function installGoogleTool(options) {
28345
- const steps2 = [step2("helper reached", "done")];
28346
- const emit = () => options.onProgress?.([...steps2]);
28347
- const push = (next) => {
28348
- steps2.push(next);
28349
- emit();
28350
- };
28351
- const fail = (label, reason, output) => {
28352
- push(step2(label, "failed", { reason, ...output ? { output } : {} }));
28353
- return { status: "error", steps: steps2, errorMessage: reason };
28354
- };
28355
- emit();
28356
- if (!isGoogleToolConnectorType(options.connectorType)) {
28357
- return fail("connector type", `${options.connectorType} is not a Google tool connector`);
28358
- }
28359
- push(step2("Google credentials resolved", "running", { output: "resolving\u2026" }));
28360
- const resolved = options.resolvedCredentials ? await options.resolvedCredentials : options.resolveCredentials ? await options.resolveCredentials() : { source: "pending", reason: "waiting for Google sign-in" };
28361
- if (!("credentials" in resolved)) {
28362
- const reason = resolved.reason;
28363
- steps2[1] = step2("Google credentials resolved", resolved.source === "pending" ? "running" : "failed", { ...resolved.source === "error" ? { reason } : {}, output: outputTail(reason) });
28364
- emit();
28365
- return resolved.source === "pending" ? { status: "installing", steps: steps2 } : { status: "error", steps: steps2, errorMessage: reason };
28366
- }
28367
- steps2[1] = step2("Google credentials resolved", "done", {
28368
- output: "Google sign-in completed through Beeline"
28369
- });
28370
- emit();
28371
- const missing = GOOGLE_TOOL_SCOPES[options.connectorType].filter((scope) => !resolved.credentials.scopes?.includes(scope));
28372
- if (missing.length)
28373
- return fail("tools enabled", `Google did not grant ${options.connectorType} permission`);
28374
- const client = options.client ?? googleWorkspaceClient(refreshableTokenSource(resolved.credentials, options.env?.BEELINE_GOOGLE_CLIENT_ID, options.env?.BEELINE_GOOGLE_CLIENT_SECRET));
28375
- push(step2("authorized with Google", "running", { output: "verifying the grant with Google\u2026" }));
28376
- const verify = await client.verify();
28377
- if (!verify.ok) {
28378
- return fail("authorized with Google", verify.reason, outputTail(verify.reason));
28379
- }
28380
- steps2[2] = step2("authorized with Google", "done", {
28381
- ...verify.account ? { output: `signed in as ${verify.account}` } : {}
28382
- });
28383
- emit();
28384
- push(step2("tools enabled", "running", { output: "verifying this Google tool\u2026" }));
28385
- try {
28386
- switch (options.connectorType) {
28387
- case "google-gmail":
28388
- await client.gmail.listMessages();
28389
- break;
28390
- case "google-calendar":
28391
- await client.calendar.listEvents({ maxResults: 1 });
28392
- break;
28393
- case "google-drive":
28394
- await client.drive.searchFiles("");
28395
- break;
28396
- case "google-youtube":
28397
- await client.youtube.listVideos();
28398
- break;
28399
- }
28400
- } catch (error) {
28401
- const reason = error instanceof Error ? error.message : String(error);
28402
- steps2[3] = step2("tools enabled", "failed", { reason, output: outputTail(reason) });
28403
- emit();
28404
- return { status: "error", steps: steps2, errorMessage: reason };
28405
- }
28406
- steps2[3] = step2("tools enabled", "done", {
28407
- output: `${GOOGLE_TOOL_SCOPES[options.connectorType].length} Google scopes granted; tool verified`
28408
- });
28409
- emit();
28410
- if (options.connectorType === "google-youtube")
28411
- persistManualGoogleCredentials(options.home, resolved.credentials);
28412
- return {
28413
- status: "connected",
28414
- steps: steps2,
28415
- ...verify.account ? { signedInAs: verify.account } : {}
28416
- };
28417
- }
28418
-
28419
- // apps/body/dist/connector-adapters.js
28420
- import { unlinkSync } from "node:fs";
28421
- function isAdaptedYoutube(type) {
28422
- return type !== void 0 && connectorAdapter(type)?.kind === "google-youtube";
28423
- }
28424
- function clearYoutubeGrant(home, log2) {
28425
- try {
28426
- unlinkSync(manualGoogleCredentialsSearchPaths(home)[0]);
28427
- } catch (error) {
28428
- if (error.code !== "ENOENT")
28429
- log2(`could not clear YouTube grant: ${error instanceof Error ? error.message : String(error)}`);
28430
- }
28431
- }
28432
-
28433
28157
  // apps/body/dist/connector-tailscale.js
28434
28158
  import { execFile as execFile6 } from "node:child_process";
28435
- import { randomUUID as randomUUID3 } from "node:crypto";
28159
+ import { randomUUID as randomUUID4 } from "node:crypto";
28436
28160
  import { rm as rm4 } from "node:fs/promises";
28437
28161
  import { tmpdir as tmpdir2, userInfo } from "node:os";
28438
- import { join as join6 } from "node:path";
28162
+ import { join as join5 } from "node:path";
28439
28163
  var COMMAND_TIMEOUT_MS = 2 * 6e4;
28440
28164
  var OUTPUT_LIMIT = 32 * 1024;
28441
28165
  var LOGIN_URL = /https:\/\/login\.tailscale\.com\/[A-Za-z0-9_/-]+/u;
@@ -28470,7 +28194,7 @@ function accountName(status) {
28470
28194
  const user = userId === void 0 ? void 0 : status.User?.[String(userId)];
28471
28195
  return user?.LoginName ?? user?.DisplayName ?? status.CurrentTailnet?.Name;
28472
28196
  }
28473
- function step3(label, status, details = {}) {
28197
+ function step2(label, status, details = {}) {
28474
28198
  return { label, status, ...details };
28475
28199
  }
28476
28200
  async function readStatus(run2) {
@@ -28508,7 +28232,7 @@ async function ensureInstalled(run2, onProgress, platform) {
28508
28232
  if (version.code === 0) {
28509
28233
  return {
28510
28234
  ok: true,
28511
- steps: [step3("Tailscale installed", "done", { output: version.stdout.trim() })]
28235
+ steps: [step2("Tailscale installed", "done", { output: version.stdout.trim() })]
28512
28236
  };
28513
28237
  }
28514
28238
  if (platform !== "linux") {
@@ -28517,17 +28241,17 @@ async function ensureInstalled(run2, onProgress, platform) {
28517
28241
  ok: false,
28518
28242
  result: {
28519
28243
  status: "error",
28520
- steps: [step3("Tailscale installed", "failed", { reason })],
28244
+ steps: [step2("Tailscale installed", "failed", { reason })],
28521
28245
  errorMessage: reason
28522
28246
  }
28523
28247
  };
28524
28248
  }
28525
- const script = join6(tmpdir2(), `beeline-tailscale-install-${process.pid}-${randomUUID3()}.sh`);
28249
+ const script = join5(tmpdir2(), `beeline-tailscale-install-${process.pid}-${randomUUID4()}.sh`);
28526
28250
  const steps2 = [
28527
- step3("Tailscale installed", "running", {
28251
+ step2("Tailscale installed", "running", {
28528
28252
  command: "curl -fsSL https://tailscale.com/install.sh"
28529
28253
  }),
28530
- step3("Tailnet signed in", "pending")
28254
+ step2("Tailnet signed in", "pending")
28531
28255
  ];
28532
28256
  onProgress(steps2);
28533
28257
  try {
@@ -28538,7 +28262,7 @@ async function ensureInstalled(run2, onProgress, platform) {
28538
28262
  ok: false,
28539
28263
  result: {
28540
28264
  status: "error",
28541
- steps: [step3("Tailscale installed", "failed", { reason })],
28265
+ steps: [step2("Tailscale installed", "failed", { reason })],
28542
28266
  errorMessage: reason
28543
28267
  }
28544
28268
  };
@@ -28550,14 +28274,14 @@ async function ensureInstalled(run2, onProgress, platform) {
28550
28274
  ok: false,
28551
28275
  result: {
28552
28276
  status: "error",
28553
- steps: [step3("Tailscale installed", "failed", { reason })],
28277
+ steps: [step2("Tailscale installed", "failed", { reason })],
28554
28278
  errorMessage: reason
28555
28279
  }
28556
28280
  };
28557
28281
  }
28558
28282
  return {
28559
28283
  ok: true,
28560
- steps: [step3("Tailscale installed", "done", { output: install.stdout.trim() })]
28284
+ steps: [step2("Tailscale installed", "done", { output: install.stdout.trim() })]
28561
28285
  };
28562
28286
  } finally {
28563
28287
  await rm4(script, { force: true }).catch(() => {
@@ -28576,14 +28300,14 @@ async function installTailscale(options = {}) {
28576
28300
  if (current?.BackendState === "Running") {
28577
28301
  return {
28578
28302
  status: "connected",
28579
- steps: [...installed.steps, step3("Tailnet signed in", "done")],
28303
+ steps: [...installed.steps, step2("Tailnet signed in", "done")],
28580
28304
  ...accountName(current) ? { signedInAs: accountName(current) } : {}
28581
28305
  };
28582
28306
  }
28583
28307
  if (options.signIn) {
28584
28308
  const steps3 = [
28585
28309
  ...installed.steps,
28586
- step3("Tailnet signed in", "running", { command: "tailscale up" })
28310
+ step2("Tailnet signed in", "running", { command: "tailscale up" })
28587
28311
  ];
28588
28312
  return { status: "installing", steps: steps3, signIn: options.signIn };
28589
28313
  }
@@ -28591,13 +28315,13 @@ async function installTailscale(options = {}) {
28591
28315
  if (pendingUrl) {
28592
28316
  return {
28593
28317
  status: "installing",
28594
- steps: [...installed.steps, step3("Tailnet signed in", "running", { command: "tailscale up" })],
28318
+ steps: [...installed.steps, step2("Tailnet signed in", "running", { command: "tailscale up" })],
28595
28319
  signIn: { method: "oauth", url: pendingUrl, browserLocation: { kind: "none" } }
28596
28320
  };
28597
28321
  }
28598
28322
  const steps2 = [
28599
28323
  ...installed.steps,
28600
- step3("Tailnet signed in", "running", { command: "tailscale up" })
28324
+ step2("Tailnet signed in", "running", { command: "tailscale up" })
28601
28325
  ];
28602
28326
  onProgress(steps2);
28603
28327
  let accountUsername;
@@ -28616,7 +28340,7 @@ async function installTailscale(options = {}) {
28616
28340
  if (after?.BackendState === "Running") {
28617
28341
  return {
28618
28342
  status: "connected",
28619
- steps: [...installed.steps, step3("Tailnet signed in", "done")],
28343
+ steps: [...installed.steps, step2("Tailnet signed in", "done")],
28620
28344
  ...accountName(after) ? { signedInAs: accountName(after) } : {}
28621
28345
  };
28622
28346
  }
@@ -28633,7 +28357,7 @@ ${up.stderr}`;
28633
28357
  const reason = (up.stderr || up.stdout || "Tailscale could not start on this helper").trim();
28634
28358
  return {
28635
28359
  status: "error",
28636
- steps: [...installed.steps, step3("Tailnet signed in", "failed", { reason })],
28360
+ steps: [...installed.steps, step2("Tailnet signed in", "failed", { reason })],
28637
28361
  errorMessage: reason
28638
28362
  };
28639
28363
  }
@@ -28642,10 +28366,10 @@ ${up.stderr}`;
28642
28366
  import { createHash as createHash4, randomBytes as randomBytes6 } from "node:crypto";
28643
28367
  import { lookup } from "node:dns/promises";
28644
28368
  import { createRequire as createRequire4 } from "node:module";
28645
- import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
28646
- import { createConnection, createServer as createServer2, isIPv4, isIPv6 } from "node:net";
28369
+ import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync, writeFileSync } from "node:fs";
28370
+ import { createConnection as createConnection3, createServer as createServer2, isIPv4, isIPv6 } from "node:net";
28647
28371
  import { homedir as homedir10 } from "node:os";
28648
- import { dirname as dirname10, join as join7 } from "node:path";
28372
+ import { dirname as dirname9, join as join6 } from "node:path";
28649
28373
  import { createInterface as createInterface5 } from "node:readline";
28650
28374
  import { fileURLToPath as fileURLToPath4 } from "node:url";
28651
28375
 
@@ -28780,12 +28504,12 @@ async function assertNotOwnMachine(url, remoteIsOwnMachine, resolveHost) {
28780
28504
  return url;
28781
28505
  }
28782
28506
  function registryMcpStateRoot(home = homedir10()) {
28783
- return join7(home, ".beeline", "registry-mcp");
28507
+ return join6(home, ".beeline", "registry-mcp");
28784
28508
  }
28785
28509
  function registryMcpStatePath(connectorId, home = homedir10()) {
28786
28510
  if (!/^[0-9a-f-]{20,}$/i.test(connectorId))
28787
28511
  throw new Error("Registry connector id is invalid");
28788
- return join7(registryMcpStateRoot(home), `${connectorId}.json`);
28512
+ return join6(registryMcpStateRoot(home), `${connectorId}.json`);
28789
28513
  }
28790
28514
  function readState(path) {
28791
28515
  try {
@@ -28796,8 +28520,8 @@ function readState(path) {
28796
28520
  }
28797
28521
  }
28798
28522
  function writeState(path, state) {
28799
- mkdirSync3(dirname10(path), { recursive: true, mode: 448 });
28800
- writeFileSync2(path, `${JSON.stringify(state)}
28523
+ mkdirSync2(dirname9(path), { recursive: true, mode: 448 });
28524
+ writeFileSync(path, `${JSON.stringify(state)}
28801
28525
  `, { mode: 384 });
28802
28526
  }
28803
28527
  function challengeParameter(header, key) {
@@ -28821,13 +28545,13 @@ var CONNECTOR_STEPS = [
28821
28545
  { key: "connect", label: "Connect provider account" }
28822
28546
  ];
28823
28547
  function steps(active, failed) {
28824
- const activeIndex = CONNECTOR_STEPS.findIndex((step4) => step4.key === active);
28825
- return CONNECTOR_STEPS.map((step4, index) => {
28548
+ const activeIndex = CONNECTOR_STEPS.findIndex((step3) => step3.key === active);
28549
+ return CONNECTOR_STEPS.map((step3, index) => {
28826
28550
  if (activeIndex < 0 || index < activeIndex)
28827
- return { label: step4.label, status: "done" };
28551
+ return { label: step3.label, status: "done" };
28828
28552
  if (index > activeIndex)
28829
- return { label: step4.label, status: "pending" };
28830
- return failed ? { label: step4.label, status: "failed", reason: failed } : { label: step4.label, status: "running" };
28553
+ return { label: step3.label, status: "pending" };
28554
+ return failed ? { label: step3.label, status: "failed", reason: failed } : { label: step3.label, status: "running" };
28831
28555
  });
28832
28556
  }
28833
28557
  var CEREMONY_EXPIRED = "the Trusty Squire sign-in page expired before it was used \xB7 tap Retry to open a new one";
@@ -29108,7 +28832,7 @@ function registryMcpHostDeclarations(routes, turnContextPath, brokerSocket = pro
29108
28832
  }));
29109
28833
  }
29110
28834
  function registryMcpHostBindPaths(routes, brokerSocket = process.env.BEELINE_REGISTRY_MCP_BROKER_SOCKET) {
29111
- return routes?.length && brokerSocket ? [dirname10(brokerSocket)] : [];
28835
+ return routes?.length && brokerSocket ? [dirname9(brokerSocket)] : [];
29112
28836
  }
29113
28837
  async function refresh(state, transport) {
29114
28838
  if (!state.refreshToken || !state.tokenEndpoint || !state.clientId)
@@ -29171,7 +28895,7 @@ function jsonRpcToolName(line) {
29171
28895
  }
29172
28896
  }
29173
28897
  function brokerSocketPath(home = homedir10()) {
29174
- return join7(home, ".beeline", "registry-mcp-broker", `${process.pid}.sock`);
28898
+ return join6(home, ".beeline", "registry-mcp-broker", `${process.pid}.sock`);
29175
28899
  }
29176
28900
  var RegistryMcpHostBroker = class {
29177
28901
  home;
@@ -29247,8 +28971,8 @@ var RegistryMcpHostBroker = class {
29247
28971
  async start() {
29248
28972
  if (this.server)
29249
28973
  return;
29250
- mkdirSync3(registryMcpStateRoot(this.home), { recursive: true, mode: 448 });
29251
- mkdirSync3(dirname10(this.socketPath), { recursive: true, mode: 448 });
28974
+ mkdirSync2(registryMcpStateRoot(this.home), { recursive: true, mode: 448 });
28975
+ mkdirSync2(dirname9(this.socketPath), { recursive: true, mode: 448 });
29252
28976
  rmSync(this.socketPath, { force: true });
29253
28977
  this.server = createServer2({ allowHalfOpen: true }, (socket) => {
29254
28978
  let buffer = "";
@@ -29295,7 +29019,7 @@ var RegistryMcpHostBroker = class {
29295
29019
  };
29296
29020
  async function brokerRequest(socketPath, request) {
29297
29021
  return new Promise((resolve40, reject) => {
29298
- const socket = createConnection(socketPath);
29022
+ const socket = createConnection3(socketPath);
29299
29023
  let output = "";
29300
29024
  socket.setEncoding("utf8");
29301
29025
  socket.setTimeout(125e3, () => socket.destroy(new Error("Registry MCP broker timed out")));
@@ -29375,11 +29099,9 @@ var ConnectorAssignmentLoop = class {
29375
29099
  api;
29376
29100
  log;
29377
29101
  install;
29378
- installGoogle;
29379
29102
  installTailscale;
29380
29103
  watchTailscaleSignIn;
29381
29104
  tailscaleWatch;
29382
- googleHomeDir;
29383
29105
  registryHomeDir;
29384
29106
  installRegistry;
29385
29107
  /** When each registry sign-in attempt's SERVER clock ends, so one can time
@@ -29402,15 +29124,8 @@ var ConnectorAssignmentLoop = class {
29402
29124
  this.log = options.log ?? (() => {
29403
29125
  });
29404
29126
  this.install = options.install ?? installSquire;
29405
- this.installGoogle = options.installGoogle ?? ((connectorType, onProgress, sharedCredentials) => installGoogleTool({
29406
- connectorType,
29407
- home: this.googleHome(),
29408
- onProgress,
29409
- resolvedCredentials: sharedCredentials ? sharedCredentials() : Promise.resolve({ source: "pending", reason: "waiting for Google sign-in" })
29410
- }));
29411
29127
  this.installTailscale = options.installTailscale ?? installTailscale;
29412
29128
  this.watchTailscaleSignIn = options.watchTailscaleSignIn ?? watchTailscaleSignIn;
29413
- this.googleHomeDir = options.googleHome ?? process.env.BEELINE_AGENT_HOME ?? process.cwd();
29414
29129
  this.registryHomeDir = options.registryHome ?? process.env.HOME ?? process.cwd();
29415
29130
  this.installRegistry = options.installRegistry ?? installRegistryMcp;
29416
29131
  this.readVaultFn = options.readVault ?? readVault;
@@ -29463,61 +29178,15 @@ var ConnectorAssignmentLoop = class {
29463
29178
  this.log(`connector assignments unavailable: ${describe(error)}`);
29464
29179
  return;
29465
29180
  }
29466
- const youtubeRows = assignments.filter((assignment) => isAdaptedYoutube(assignment.connectorType));
29467
- if (youtubeRows.some((assignment) => assignment.kind === "uninstall") && youtubeRows.every((assignment) => assignment.kind === "uninstall")) {
29468
- clearYoutubeGrant(this.googleHome(), (message) => this.log(message));
29469
- }
29470
- let googleBatch;
29471
29181
  for (const assignment of assignments) {
29472
29182
  const key = `${assignment.kind}:${assignment.connectorId}`;
29473
29183
  if (assignment.kind === "uninstall")
29474
29184
  continue;
29475
- if (assignment.kind === "install" && isGoogleToolConnectorType(assignment.connectorType)) {
29476
- if (this.inFlight.has(key))
29477
- continue;
29478
- this.inFlight.add(key);
29479
- (googleBatch ??= []).push(assignment);
29480
- continue;
29481
- }
29482
29185
  if (this.inFlight.has(key))
29483
29186
  continue;
29484
29187
  this.inFlight.add(key);
29485
29188
  void this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe(error)}`)).finally(() => this.inFlight.delete(key));
29486
29189
  }
29487
- if (googleBatch) {
29488
- const keys = googleBatch.map((assignment) => `${assignment.kind}:${assignment.connectorId}`);
29489
- void this.runGoogleBatch(googleBatch).catch((error) => this.log(`google connector installs failed: ${describe(error)}`)).finally(() => {
29490
- for (const key of keys)
29491
- this.inFlight.delete(key);
29492
- });
29493
- }
29494
- }
29495
- /** Google tools share a machine grant, but each connector has its own OAuth
29496
- * readiness. Resolve it per connector while installs run sequentially. */
29497
- async runGoogleBatch(batch) {
29498
- for (const assignment of batch) {
29499
- await this.runGoogleInstall(assignment.connectorId, assignment.connectorType, () => this.resolveGoogleCredentials(assignment.connectorId), assignment.kind === "install" ? assignment.pairingGeneration : void 0);
29500
- }
29501
- }
29502
- /** A failed grant lookup becomes an error for this connector. */
29503
- resolveGoogleCredentials(connectorId) {
29504
- return (async () => {
29505
- try {
29506
- const grant = await this.api.execute("getGoogleOAuthGrant", {
29507
- agentId: this.agentId,
29508
- connectorId
29509
- });
29510
- if (grant.status === "ready" && grant.credentials)
29511
- return { source: "beeline", credentials: grant.credentials };
29512
- } catch (error) {
29513
- this.log(`Google grant lookup failed: ${describe(error)}`);
29514
- return {
29515
- source: "error",
29516
- reason: "Beeline could not read the Google grant; retry the connection"
29517
- };
29518
- }
29519
- return { source: "pending", reason: "waiting for Google sign-in" };
29520
- })();
29521
29190
  }
29522
29191
  squire() {
29523
29192
  this.mcp ??= defaultSquireMcpClient({ agentId: this.agentId, roomId: "connector" });
@@ -29526,7 +29195,19 @@ var ConnectorAssignmentLoop = class {
29526
29195
  async handle(assignment) {
29527
29196
  const pairingGeneration = assignment.kind === "install" || assignment.kind === "uninstall" ? assignment.pairingGeneration : void 0;
29528
29197
  if (assignment.kind === "install") {
29529
- if (assignment.connectorType === "registry-mcp") {
29198
+ if (assignment.connectorType?.startsWith("google-")) {
29199
+ await this.api.execute("postConnectorStatus", {
29200
+ agentId: this.agentId,
29201
+ connectorId: assignment.connectorId,
29202
+ steps: [{
29203
+ label: "Connect app",
29204
+ status: "failed",
29205
+ reason: "Reconnect through Connect an app"
29206
+ }],
29207
+ errorMessage: "Reconnect through Connect an app",
29208
+ ...pairingGeneration !== void 0 ? { pairingGeneration } : {}
29209
+ });
29210
+ } else if (assignment.connectorType === "registry-mcp") {
29530
29211
  await this.runRegistryMcpInstall(assignment);
29531
29212
  } else if (assignment.connectorType === "tailscale") {
29532
29213
  await this.runTailscaleInstall(assignment.connectorId, pairingGeneration);
@@ -29538,9 +29219,7 @@ var ConnectorAssignmentLoop = class {
29538
29219
  } else if (assignment.kind === "sync") {
29539
29220
  await this.runSync();
29540
29221
  } else if (assignment.kind === "refresh-google-grant") {
29541
- const grant = await this.resolveGoogleCredentials(assignment.connectorId);
29542
- if ("credentials" in grant)
29543
- persistManualGoogleCredentials(this.googleHome(), grant.credentials);
29222
+ this.log("retired Google grant assignment ignored; reconnect through Connect an app");
29544
29223
  } else if (assignment.kind === "revoke-grants")
29545
29224
  await this.runRevoke(assignment.connectorId, assignment.reference);
29546
29225
  }
@@ -29655,49 +29334,6 @@ var ConnectorAssignmentLoop = class {
29655
29334
  this.wake();
29656
29335
  });
29657
29336
  }
29658
- /** Google tool connectors keep their manual credentials next to the runtime. */
29659
- googleHome() {
29660
- return this.googleHomeDir;
29661
- }
29662
- /** Install one Google tool connector (Gmail/Calendar/Drive/YouTube),
29663
- * riding the drain's shared grant resolution. */
29664
- async runGoogleInstall(connectorId, connectorType, sharedCredentials, pairingGeneration) {
29665
- const generation = pairingGeneration !== void 0 ? { pairingGeneration } : {};
29666
- const report = async (steps2) => {
29667
- try {
29668
- await this.api.execute("postConnectorStatus", {
29669
- agentId: this.agentId,
29670
- connectorId,
29671
- steps: steps2,
29672
- ...generation
29673
- });
29674
- } catch (error) {
29675
- this.log(`step report failed: ${describe(error)}`);
29676
- }
29677
- };
29678
- const result = await this.installGoogle(connectorType, report, sharedCredentials);
29679
- if (result.status === "installing")
29680
- return;
29681
- if (result.status === "error") {
29682
- if (isAdaptedYoutube(connectorType)) {
29683
- clearYoutubeGrant(this.googleHome(), (message) => this.log(message));
29684
- }
29685
- await this.api.execute("postConnectorStatus", {
29686
- agentId: this.agentId,
29687
- connectorId,
29688
- steps: result.steps,
29689
- errorMessage: result.errorMessage,
29690
- ...generation
29691
- });
29692
- return;
29693
- }
29694
- await this.api.execute("installConnector", {
29695
- agentId: this.agentId,
29696
- connectorId,
29697
- ...result.signedInAs ? { signedInAs: result.signedInAs } : {},
29698
- ...generation
29699
- });
29700
- }
29701
29337
  /** Install Trusty Squire, reporting every step as it settles. */
29702
29338
  async runInstall(connectorId, pairingGeneration) {
29703
29339
  const generation = pairingGeneration !== void 0 ? { pairingGeneration } : {};
@@ -29795,7 +29431,7 @@ var ConnectorAssignmentLoop = class {
29795
29431
  const status = await this.connectorRow(connectorId);
29796
29432
  if (!status)
29797
29433
  return false;
29798
- return status.steps.length > 0 && status.steps.every((step4) => step4.status === "pending");
29434
+ return status.steps.length > 0 && status.steps.every((step3) => step3.status === "pending");
29799
29435
  }
29800
29436
  /** One vault report covers every live trusty-squire connector on this helper. */
29801
29437
  async runSync() {
@@ -30585,7 +30221,7 @@ var InstitutionalMemoryShadowWorker = class {
30585
30221
  leaseToken: job.leaseToken,
30586
30222
  error: errorText(error),
30587
30223
  retryable: true
30588
- }).catch((failure2) => this.log(`shadow failure report failed: ${errorText(failure2)}`));
30224
+ }).catch((failure) => this.log(`shadow failure report failed: ${errorText(failure)}`));
30589
30225
  }
30590
30226
  return false;
30591
30227
  } finally {
@@ -30600,7 +30236,7 @@ var InstitutionalMemoryShadowWorker = class {
30600
30236
 
30601
30237
  // apps/body/dist/daemon-api-client.js
30602
30238
  import { resolve as resolve13 } from "node:path";
30603
- import { randomUUID as randomUUID5 } from "node:crypto";
30239
+ import { randomUUID as randomUUID6 } from "node:crypto";
30604
30240
 
30605
30241
  // node_modules/ws/wrapper.mjs
30606
30242
  var import_stream = __toESM(require_stream(), 1);
@@ -30622,10 +30258,10 @@ function helperVersionHeader(value) {
30622
30258
  }
30623
30259
 
30624
30260
  // apps/body/dist/host-read-budget.js
30625
- import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
30261
+ import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
30626
30262
  import { mkdir as mkdir7, open as open3, readFile as readFile10, readdir as readdir3, stat as stat5, unlink as unlink4, writeFile as writeFile7 } from "node:fs/promises";
30627
30263
  import { tmpdir as tmpdir4 } from "node:os";
30628
- import { join as join8 } from "node:path";
30264
+ import { join as join7 } from "node:path";
30629
30265
  var READ_SLOTS = 6;
30630
30266
  var BACKGROUND_SLOTS = 4;
30631
30267
  var MAX_WAITERS = 256;
@@ -30656,15 +30292,15 @@ var HostReadBudget = class {
30656
30292
  const uid = process.getuid?.() ?? "unknown";
30657
30293
  const origin = new URL(baseUrl).origin;
30658
30294
  const key = createHash5("sha256").update(origin).digest("hex").slice(0, 16);
30659
- this.directory = join8(root, `beeline-read-budget-${uid}-${key}`);
30295
+ this.directory = join7(root, `beeline-read-budget-${uid}-${key}`);
30660
30296
  }
30661
30297
  metrics() {
30662
30298
  return { waiting: this.waiting, active: this.active, totalWaitMs: this.totalWaitMs };
30663
30299
  }
30664
30300
  async acquire(priority, deadlineAt) {
30665
30301
  await mkdir7(this.directory, { recursive: true, mode: 448 });
30666
- const ticket = `wait-${priority === "urgent" ? "0" : "1"}-${String(Date.now()).padStart(13, "0")}-${randomUUID4()}`;
30667
- const ticketPath = join8(this.directory, ticket);
30302
+ const ticket = `wait-${priority === "urgent" ? "0" : "1"}-${String(Date.now()).padStart(13, "0")}-${randomUUID5()}`;
30303
+ const ticketPath = join7(this.directory, ticket);
30668
30304
  const tickets = (await readdir3(this.directory)).filter((name) => name.startsWith("wait-"));
30669
30305
  if (tickets.length >= MAX_WAITERS)
30670
30306
  throw new ReadBudgetFullError();
@@ -30676,14 +30312,14 @@ var HostReadBudget = class {
30676
30312
  const queue = (await readdir3(this.directory)).filter((name) => name.startsWith("wait-")).sort();
30677
30313
  for (const name of queue.slice(0, READ_SLOTS)) {
30678
30314
  if (name !== ticket)
30679
- await this.reapStaleTicket(join8(this.directory, name));
30315
+ await this.reapStaleTicket(join7(this.directory, name));
30680
30316
  }
30681
30317
  const liveQueue = (await readdir3(this.directory)).filter((name) => name.startsWith("wait-")).sort();
30682
30318
  const rank = liveQueue.indexOf(ticket);
30683
30319
  const available = priority === "urgent" ? READ_SLOTS : BACKGROUND_SLOTS;
30684
30320
  if (rank >= 0 && rank < available) {
30685
30321
  for (let slot = 0; slot < available; slot += 1) {
30686
- const slotPath = join8(this.directory, `slot-${slot}`);
30322
+ const slotPath = join7(this.directory, `slot-${slot}`);
30687
30323
  try {
30688
30324
  const handle2 = await open3(slotPath, "wx", 384);
30689
30325
  try {
@@ -30754,7 +30390,7 @@ var HostReadBudget = class {
30754
30390
  await unlink4(path).catch(() => void 0);
30755
30391
  }
30756
30392
  async takeRateToken(deadlineAt) {
30757
- const lock = join8(this.directory, "rate.lock");
30393
+ const lock = join7(this.directory, "rate.lock");
30758
30394
  let handle2;
30759
30395
  try {
30760
30396
  handle2 = await open3(lock, "wx", 384);
@@ -30765,7 +30401,7 @@ var HostReadBudget = class {
30765
30401
  return false;
30766
30402
  }
30767
30403
  try {
30768
- const path = join8(this.directory, "next-admission");
30404
+ const path = join7(this.directory, "next-admission");
30769
30405
  const next = Number(await readFile10(path, "utf8").catch(() => "0")) || 0;
30770
30406
  const now2 = Date.now();
30771
30407
  if (next > now2 || now2 >= deadlineAt)
@@ -30842,7 +30478,7 @@ var DaemonApiClient = class {
30842
30478
  agentId;
30843
30479
  fetchImpl;
30844
30480
  webSocketFactory;
30845
- presenceLifecycleId = randomUUID5();
30481
+ presenceLifecycleId = randomUUID6();
30846
30482
  liveSocket;
30847
30483
  liveReconnect;
30848
30484
  liveReconnectDelayMs = 1e3;
@@ -31288,10 +30924,10 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
31288
30924
 
31289
30925
  // apps/body/dist/room-runtime.js
31290
30926
  import { execFile as execFile12 } from "node:child_process";
31291
- import { createHash as createHash11 } from "node:crypto";
31292
- import { existsSync as existsSync8, mkdirSync as mkdirSync4 } from "node:fs";
31293
- import { mkdir as mkdir20, readdir as readdir8, realpath as realpath2, rm as rm9 } from "node:fs/promises";
31294
- import { dirname as dirname19, relative as relative3, resolve as resolve29, sep as sep2 } from "node:path";
30927
+ import { createHash as createHash10 } from "node:crypto";
30928
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3 } from "node:fs";
30929
+ import { cp, mkdir as mkdir20, readdir as readdir8, realpath as realpath2, rm as rm9 } from "node:fs/promises";
30930
+ import { dirname as dirname18, relative as relative3, resolve as resolve29, sep as sep2 } from "node:path";
31295
30931
  import { promisify as promisify8 } from "node:util";
31296
30932
 
31297
30933
  // apps/body/dist/grant-runner.js
@@ -31299,7 +30935,7 @@ import { execFile as execFile8 } from "node:child_process";
31299
30935
  import { createHash as createHash6, randomBytes as randomBytes7 } from "node:crypto";
31300
30936
  import { readFile as readFile12 } from "node:fs/promises";
31301
30937
  import { createServer as createServer3 } from "node:http";
31302
- import { dirname as dirname12, resolve as resolve16 } from "node:path";
30938
+ import { dirname as dirname11, resolve as resolve16 } from "node:path";
31303
30939
 
31304
30940
  // packages/api-contract/dist/agent-grants.js
31305
30941
  var AGENT_GRANT_KINDS = [
@@ -31546,7 +31182,7 @@ function surfaceAllows(surface, capability) {
31546
31182
  init_agent_command();
31547
31183
  init_cursor_acp_bridge();
31548
31184
  import { execFile as execFile7, spawnSync } from "node:child_process";
31549
- import { lstatSync as lstatSync3, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
31185
+ import { lstatSync as lstatSync2, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
31550
31186
  import { homedir as homedir11 } from "node:os";
31551
31187
  import { isAbsolute as isAbsolute2, relative, resolve as resolve14 } from "node:path";
31552
31188
  var DEFAULT_SANDBOX_POLICY = "bwrap";
@@ -31607,7 +31243,7 @@ var KNOWN_CREDENTIAL_MASK_PATHS = [
31607
31243
  ];
31608
31244
  function credentialMaskPaths(extraPaths, home = homedir11(), stat8 = (path) => {
31609
31245
  try {
31610
- const info = lstatSync3(path);
31246
+ const info = lstatSync2(path);
31611
31247
  return { isDirectory: info.isDirectory() };
31612
31248
  } catch {
31613
31249
  return void 0;
@@ -31825,7 +31461,7 @@ function recordInstallFailure(stateDir, at) {
31825
31461
  if (!stateDir)
31826
31462
  return;
31827
31463
  try {
31828
- writeFileSync3(installFailureMarker(stateDir), `${at}
31464
+ writeFileSync2(installFailureMarker(stateDir), `${at}
31829
31465
  `, "utf8");
31830
31466
  } catch {
31831
31467
  }
@@ -31950,7 +31586,7 @@ async function ensureBwrapSandbox(options = {}) {
31950
31586
  // apps/body/dist/provider-key-store.js
31951
31587
  import { chmod as chmod4, mkdir as mkdir8, readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
31952
31588
  import { homedir as homedir12 } from "node:os";
31953
- import { dirname as dirname11, resolve as resolve15 } from "node:path";
31589
+ import { dirname as dirname10, resolve as resolve15 } from "node:path";
31954
31590
  var PROVIDER_KEY_ENV_VARS = {
31955
31591
  openrouter: "OPENROUTER_API_KEY",
31956
31592
  openai: "OPENAI_API_KEY",
@@ -31984,7 +31620,7 @@ async function readSavedProviderKey(provider, env = process.env) {
31984
31620
  async function saveProviderKey(provider, key, env = process.env) {
31985
31621
  const path = providerKeyStorePath(env);
31986
31622
  const store = { ...await readProviderKeyStore(env), [provider]: key };
31987
- await mkdir8(dirname11(path), { recursive: true, mode: 448 });
31623
+ await mkdir8(dirname10(path), { recursive: true, mode: 448 });
31988
31624
  await writeFile8(path, `${JSON.stringify(store, null, 2)}
31989
31625
  `, { mode: 384 });
31990
31626
  await chmod4(path, 384);
@@ -32022,7 +31658,7 @@ function operatorSecretResolver(env = process.env) {
32022
31658
  if (saved)
32023
31659
  return saved;
32024
31660
  }
32025
- const raw = await readFile12(resolve16(dirname12(providerKeyStorePath(env)), "secrets.json"), "utf8").catch(() => void 0);
31661
+ const raw = await readFile12(resolve16(dirname11(providerKeyStorePath(env)), "secrets.json"), "utf8").catch(() => void 0);
32026
31662
  if (!raw)
32027
31663
  return void 0;
32028
31664
  try {
@@ -32152,13 +31788,13 @@ var GrantCommandRunner = class {
32152
31788
  encoding: "utf8"
32153
31789
  }, (error, stdout6, stderr) => {
32154
31790
  const combined = [stdout6, stderr].filter(Boolean).join(stderr && stdout6 ? "\n" : "");
32155
- const failure2 = error;
32156
- const spawnFailure = Boolean(failure2 && typeof failure2.code === "string");
31791
+ const failure = error;
31792
+ const spawnFailure = Boolean(failure && typeof failure.code === "string");
32157
31793
  resolveRun({
32158
- exitCode: spawnFailure ? null : child.exitCode ?? (typeof failure2?.code === "number" ? failure2.code : 0),
32159
- ...failure2?.signal ? { signal: failure2.signal } : {},
32160
- timedOut: Boolean(failure2?.killed && failure2?.signal === "SIGKILL"),
32161
- output: spawnFailure ? `${combined}${combined ? "\n" : ""}${failure2.message}` : combined
31794
+ exitCode: spawnFailure ? null : child.exitCode ?? (typeof failure?.code === "number" ? failure.code : 0),
31795
+ ...failure?.signal ? { signal: failure.signal } : {},
31796
+ timedOut: Boolean(failure?.killed && failure?.signal === "SIGKILL"),
31797
+ output: spawnFailure ? `${combined}${combined ? "\n" : ""}${failure.message}` : combined
32162
31798
  });
32163
31799
  });
32164
31800
  });
@@ -32294,16 +31930,16 @@ var GrantRunnerServer = class {
32294
31930
  await new Promise((resolveClose) => server.close(() => resolveClose()));
32295
31931
  }
32296
31932
  async handle(request, response, token) {
32297
- const send2 = (status, body) => {
31933
+ const send = (status, body) => {
32298
31934
  response.writeHead(status, { "content-type": "application/json" });
32299
31935
  response.end(JSON.stringify(body));
32300
31936
  };
32301
31937
  if (request.headers.authorization !== `Bearer ${token}`) {
32302
- send2(401, { error: "grant runner token required" });
31938
+ send(401, { error: "grant runner token required" });
32303
31939
  return;
32304
31940
  }
32305
31941
  if (request.method !== "POST" || request.url !== "/run") {
32306
- send2(404, { error: "not found" });
31942
+ send(404, { error: "not found" });
32307
31943
  return;
32308
31944
  }
32309
31945
  const chunks = [];
@@ -32311,9 +31947,9 @@ var GrantRunnerServer = class {
32311
31947
  chunks.push(chunk);
32312
31948
  try {
32313
31949
  const body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
32314
- send2(200, await this.runner.run({ roomId: body.roomId, argv: body.argv }));
31950
+ send(200, await this.runner.run({ roomId: body.roomId, argv: body.argv }));
32315
31951
  } catch (error) {
32316
- send2(400, { error: error instanceof Error ? error.message : String(error) });
31952
+ send(400, { error: error instanceof Error ? error.message : String(error) });
32317
31953
  }
32318
31954
  }
32319
31955
  };
@@ -32324,11 +31960,6 @@ function toolName(call) {
32324
31960
  const match = raw.match(/(?:^|__|\b)(use_credential|fetch_credential|grant_app_access|revoke_app_access)\b/);
32325
31961
  return match?.[1] ?? "";
32326
31962
  }
32327
- function youtubeToolName(call) {
32328
- const raw = `${call.title ?? ""} ${call.kind ?? ""}`;
32329
- const match = raw.match(/(?:^|__|\.|\/)(youtube_[a-z0-9_]+)\b/);
32330
- return match?.[1] ?? "";
32331
- }
32332
31963
  var SQUIRE_EVENT_CLASS = {
32333
31964
  fetch_credential: "approval",
32334
31965
  // the credential was read in clear
@@ -32415,23 +32046,9 @@ var ConnectorUsageRecorder = class {
32415
32046
  }
32416
32047
  }
32417
32048
  };
32418
- function youtubeUsageFromToolCall(call) {
32419
- const tool = youtubeToolName(call);
32420
- if (!tool.startsWith("youtube_"))
32421
- return void 0;
32422
- const result = record4(call.content ?? call.rawOutput);
32423
- const resultPayload = record4(result.content ?? result);
32424
- return {
32425
- ref: "google-youtube",
32426
- service: "youtube",
32427
- operation: tool.slice(0, 300),
32428
- statusCode: typeof resultPayload.status === "number" ? resultPayload.status : /failed|error|denied/i.test(call.status ?? "") ? 0 : 200,
32429
- bytes: serializedSize(resultPayload)
32430
- };
32431
- }
32432
32049
  function captureConnectionUsage(recorder, turn, calls) {
32433
32050
  for (const call of calls) {
32434
- const usage2 = squireUsageFromToolCall(call) ?? youtubeUsageFromToolCall(call);
32051
+ const usage2 = squireUsageFromToolCall(call);
32435
32052
  if (usage2)
32436
32053
  recorder.record(turn, usage2);
32437
32054
  }
@@ -32610,20 +32227,20 @@ async function readHarnessTurnUsage(input) {
32610
32227
  }
32611
32228
 
32612
32229
  // apps/body/dist/server-command-intake.js
32613
- import { randomUUID as randomUUID6 } from "node:crypto";
32230
+ import { randomUUID as randomUUID7 } from "node:crypto";
32614
32231
  import { mkdir as mkdir9, writeFile as writeFile9 } from "node:fs/promises";
32615
32232
  import { tmpdir as tmpdir5 } from "node:os";
32616
- import { dirname as dirname13, join as join9 } from "node:path";
32233
+ import { dirname as dirname12, join as join8 } from "node:path";
32617
32234
  var CommandExecutionContext = class {
32618
- generationId = randomUUID6();
32235
+ generationId = randomUUID7();
32619
32236
  path;
32620
32237
  current;
32621
32238
  constructor(root) {
32622
- this.path = join9(root ?? tmpdir5(), `beeline-command-${this.generationId}.json`);
32239
+ this.path = join8(root ?? tmpdir5(), `beeline-command-${this.generationId}.json`);
32623
32240
  }
32624
32241
  async enter(command) {
32625
32242
  this.current = command;
32626
- await mkdir9(dirname13(this.path), { recursive: true });
32243
+ await mkdir9(dirname12(this.path), { recursive: true });
32627
32244
  await writeFile9(this.path, JSON.stringify({
32628
32245
  roomId: command.roomId,
32629
32246
  requestId: command.turnRequestId,
@@ -32788,10 +32405,10 @@ async function runServerCommandIntake(options) {
32788
32405
 
32789
32406
  // apps/body/dist/monolith-corner-turn.js
32790
32407
  import { execFile as execFile11 } from "node:child_process";
32791
- import { createHash as createHash10 } from "node:crypto";
32408
+ import { createHash as createHash9 } from "node:crypto";
32792
32409
  import { mkdir as mkdir18, readFile as readFile19, writeFile as writeFile14 } from "node:fs/promises";
32793
32410
  import { homedir as homedir14, hostname } from "node:os";
32794
- import { dirname as dirname17, join as join14, resolve as resolve28 } from "node:path";
32411
+ import { dirname as dirname16, join as join13, resolve as resolve28 } from "node:path";
32795
32412
  import { promisify as promisify7 } from "node:util";
32796
32413
 
32797
32414
  // apps/body/dist/agent-home.js
@@ -33593,10 +33210,10 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
33593
33210
  }
33594
33211
 
33595
33212
  // apps/body/dist/agent-home.js
33596
- import { createHash as createHash7, randomUUID as randomUUID7 } from "node:crypto";
33213
+ import { createHash as createHash7, randomUUID as randomUUID8 } from "node:crypto";
33597
33214
  import { chmod as chmod5, copyFile, lstat as lstat3, mkdir as mkdir11, readFile as readFile16, readlink, readdir as readdir5, realpath, rename as rename5, rm as rm6, symlink as symlink2, unlink as unlink5, writeFile as writeFile11 } from "node:fs/promises";
33598
33215
  import { homedir as homedir13 } from "node:os";
33599
- import { basename as basename4, dirname as dirname14, join as join11, relative as relative2, resolve as resolve21, sep } from "node:path";
33216
+ import { basename as basename4, dirname as dirname13, join as join10, relative as relative2, resolve as resolve21, sep } from "node:path";
33600
33217
 
33601
33218
  // apps/body/dist/draw-avatar-skill.js
33602
33219
  var DRAW_AVATAR_SKILL_NAME = "draw-avatar";
@@ -33768,11 +33385,9 @@ Follow your own owner first, then this Workspace's owner and admins, then member
33768
33385
 
33769
33386
  A **tool** is something you can use once a human adds it; a **key** is the credential that tool holds for that human. You spend a key through the mounted connector and never see the credential itself.
33770
33387
 
33771
- The tools this build knows, what each is for, and which the owner of this machine already has are one call away: beeline-agent workbench_status. That read is the Workbench of the machine and owner you actually run on, not the person who asked. Trusty Squire is vaulted credentials plus a browser that signs up and signs in for you; the Google tools (Gmail, Calendar, Drive, YouTube) work through the person's own Google sign-in \u2014 the same Workbench overlay, never a second Google window. YouTube Analytics answers only the channel owner account, not a manager. Tailscale installs its CLI on the selected helper and opens Tailscale's own browser sign-in; once connected, use the CLI for tailnet resources and tailscale file cp or tailscale file get for Taildrop. The wallet is created only from the Workbench page.
33388
+ The tools this build knows, what each is for, and which the owner of this machine already has are one call away: beeline-agent workbench_status. That read is the Workbench of the machine and owner you actually run on, not the person who asked. Connected apps are listed once per app with a stable ID. Their sign-in and credentials stay with the server. Trusty Squire is vaulted credentials plus a browser for the separate key and browser routes. Tailscale installs its CLI on the selected helper and opens Tailscale's own browser sign-in; once connected, use the CLI for tailnet resources and tailscale file cp or tailscale file get for Taildrop. The wallet is created only from the Workbench page. When you cannot reach a tool, say: I can't reach X on this machine because Y; to fix it, Z. Give one explanation, then take or offer Z.
33772
33389
 
33773
- When you cannot use a tool or reach something on this machine, say it in one sentence: I can't reach X on this machine because Y; to fix it, Z. Give one explanation, then take or offer Z.
33774
-
33775
- **Offer the tool at the moment you need it.** When the work in front of you needs a tool the person does not have, do not send them to a settings page and do not stop at naming it. Call workbench_status first - a tool they already have is used, not offered. Then call offer_connector with the connectorType and one short reason: a card appears in this Room, spoken by you, addressed to the person you are answering, with one action. Only that person or a Workspace admin can accept it; accepting adds the tool on your machine, and the sign-in or keys stay theirs. Your turn pauses on the card - say in prose what you are waiting for and end the turn; you are woken when it is added, and then you carry on.
33390
+ **Offer the tool at the moment you need it.** When the work in front of you needs a tool the person does not have, do not send them to a settings page and do not stop at naming it. Call workbench_status first - a tool they already have is used, not offered. Then call offer_connector with the connectorType and one short reason: a card appears in this Room, spoken by you, addressed to the person you are answering, with one action. Your turn pauses on the card - say in prose what you are waiting for and end the turn; you are woken when it is added, and then you carry on.
33776
33391
 
33777
33392
  **Research before you offer, and say so.** Never offer a tool you cannot describe. If someone asks you to install or add something you do not already know - by name, by purpose, or by what it will hold - say plainly that you are looking it up first, find out what it is and what it does with credentials, and state what you learned in your reply BEFORE the card appears. A person reading "Add X?" must already have read, in your own words, what X is. Refusing to act blind is part of being trusted with keys.
33778
33393
 
@@ -33782,13 +33397,9 @@ Keys belong to the human who provisioned them. Your owner's keys serve whoever a
33782
33397
 
33783
33398
  ## Connect an app
33784
33399
 
33785
- When a request needs an app or service you cannot reach with a mounted tool, there is ONE way in: beeline-agent \`connect_app\` with the app's name or website and one short reason. You do not choose the route and you do not search for servers yourself. The server resolves it in a fixed order and records the choice: an app already connected in this owner's Workbench is reused; otherwise the app's official hosted MCP server is connected; otherwise Trusty Squire signs up or signs in, vaults an API key, and you call the app's API through Squire; only when Squire establishes that the app has no API is it served through Squire's browser.
33400
+ When a request needs an app or service, call beeline-agent \`workbench_status\` first. For a connected app, use its ID with \`list_app_tools\`, then call \`execute_app_tool\` with the selected tool slug and arguments. The server executes against that person\u2019s account and decides permission on every call. An empty tool list or \`needs_connection\` means the account must be reconnected; \`needs_permission\` means wait for the connected person's decision. Do not switch paths after denial or provider unavailability. No app token, provider key, or sign-in URL belongs in chat or a model prompt.
33786
33401
 
33787
- 1. Call \`workbench_status\` first; an app listed there as connected is used, not connected again.
33788
- 2. Call \`connect_app\` and do exactly what its \`next\` says. Repeating the call is safe and is how you report a finished step.
33789
- 3. Trusty Squire handles every sign-in, sign-up and payment, on every route - including an MCP server's OAuth page (\`authorizationUrl\`: \`operate_start\`, \`operate_login\`, \`operate_observe\`, \`operate_finish\`). Any passkey or vouch step goes to the owner through Squire. Never paste a sign-in link or a key into chat. If Squire is not connected, offer it with \`offer_connector\` (trusty-squire) and call \`connect_app\` again once it is added.
33790
- 4. On the API route, store the key with Squire's \`store_credential\` under the service the result names, call \`connect_app\` again, then call the API with \`use_credential\`. Pass \`noApi: true\` only when you established that the app offers no API at all.
33791
- 5. Every use of the app, whichever route serves it, is authorized as \`app:<key>\` and recorded once. A refusal or a pending approval is final for that call: wait for the owner's decision, and never try another route to get around it.
33402
+ For an app that is not connected, call \`connect_app\` with its name, one short reason, and a request-specific \`continuation\`: one sentence stating what you will do right after sign-in. Do not include a link, credential, account identifier, or private data in that sentence. The server chooses the route and returns \`next\`. A managed OAuth app presents a sign-in card to its owner; end the turn and wait for the connection wake. If the provider reports managed OAuth unsupported, follow the server's Squire route and its instructions. A provider outage is unavailable, not permission to change routes. After the person connects, read Workbench again and use the app ID. Trusty Squire handles the separate API key and browser routes; never ask for a raw key in chat. Every use is authorized as \`app:<key>\` and recorded once.
33792
33403
 
33793
33404
  ## Showing a mock
33794
33405
 
@@ -34065,7 +33676,7 @@ var SQUIRE_GOVERNED_TOOLS = [
34065
33676
  var SQUIRE_GOVERNED_TOOL_SET = new Set(SQUIRE_GOVERNED_TOOLS);
34066
33677
 
34067
33678
  // apps/body/dist/host-mcp-route.js
34068
- import { join as join10, resolve as resolve19 } from "node:path";
33679
+ import { join as join9, resolve as resolve19 } from "node:path";
34069
33680
  var import_yaml = __toESM(require_dist(), 1);
34070
33681
  init_squire_host();
34071
33682
  function grantedMcpServerNames(grants) {
@@ -34120,7 +33731,7 @@ function grantedSquireHostRouteNames(granted, declarations = {}) {
34120
33731
  });
34121
33732
  }
34122
33733
  function hostRouteEnv(hostHome) {
34123
- return { XDG_CONFIG_HOME: join10(resolve19(hostHome), ".config") };
33734
+ return { XDG_CONFIG_HOME: join9(resolve19(hostHome), ".config") };
34124
33735
  }
34125
33736
  function rewriteHostMcpDeclaration(name, declaration, hostHome, resourceAuthFile, squireScope) {
34126
33737
  const next = { ...declaration };
@@ -34143,10 +33754,6 @@ function rewriteHostMcpDeclaration(name, declaration, hostHome, resourceAuthFile
34143
33754
  next.envs = { ...recordValue(declaration.envs), ...routeEnv };
34144
33755
  else
34145
33756
  next.env = { ...recordValue(declaration.env), ...routeEnv };
34146
- if (launch) {
34147
- delete next.env?.TRUSTY_SQUIRE_AGENT_IDENTITY;
34148
- delete next.envs?.TRUSTY_SQUIRE_AGENT_IDENTITY;
34149
- }
34150
33757
  if (resourceAuthFile) {
34151
33758
  const target = explicitResourceTarget ?? (isSquireDeclaration(name, declaration) ? "squire" : name);
34152
33759
  const env = {
@@ -34520,7 +34127,7 @@ async function resolveUptimeRouting(input) {
34520
34127
  if (cached?.input !== void 0 && now2() - cached.fetchedAt < OPENROUTER_ROUTING_CACHE_TTL_MS) {
34521
34128
  return decision(input.model, cached.providers, cached.bar, "cache", void 0, true, cached.input ?? void 0);
34522
34129
  }
34523
- let failure2;
34130
+ let failure;
34524
34131
  try {
34525
34132
  const doFetch = input.fetchImpl ?? fetch;
34526
34133
  const response = await doFetch(`${OPENROUTER_ENDPOINTS_BASE_URL}/${input.model}/endpoints`, {
@@ -34546,12 +34153,12 @@ async function resolveUptimeRouting(input) {
34546
34153
  }).catch(() => void 0);
34547
34154
  return decision(input.model, selected.providers, selected.bar, "live", void 0, true, modelInput);
34548
34155
  } catch (error) {
34549
- failure2 = error instanceof Error ? error.message : String(error);
34156
+ failure = error instanceof Error ? error.message : String(error);
34550
34157
  }
34551
34158
  if (cached) {
34552
- return decision(input.model, cached.providers, cached.bar, "stale-cache", `api unreachable: ${failure2}`, true, cached.input ?? void 0);
34159
+ return decision(input.model, cached.providers, cached.bar, "stale-cache", `api unreachable: ${failure}`, true, cached.input ?? void 0);
34553
34160
  }
34554
- return decision(input.model, OPENROUTER_FALLBACK_PROVIDERS, null, "fallback", `api unreachable: ${failure2}`);
34161
+ return decision(input.model, OPENROUTER_FALLBACK_PROVIDERS, null, "fallback", `api unreachable: ${failure}`);
34555
34162
  }
34556
34163
  var inFlightProbes = /* @__PURE__ */ new Map();
34557
34164
  function answeringProviders(probe, candidates) {
@@ -34927,7 +34534,7 @@ async function repairRoomAgentCredentialLinks(input) {
34927
34534
  if (!existsSync7(source))
34928
34535
  continue;
34929
34536
  const target = resolve21(root, credential.dir, credential.target);
34930
- await mkdir11(dirname14(target), { recursive: true, mode: 448 });
34537
+ await mkdir11(dirname13(target), { recursive: true, mode: 448 });
34931
34538
  const stats = await lstat3(target).catch((error) => {
34932
34539
  if (isMissingPathError(error))
34933
34540
  return void 0;
@@ -34935,11 +34542,11 @@ async function repairRoomAgentCredentialLinks(input) {
34935
34542
  });
34936
34543
  if (stats?.isSymbolicLink()) {
34937
34544
  const linked = await readlink(target);
34938
- if (resolve21(dirname14(target), linked) === source)
34545
+ if (resolve21(dirname13(target), linked) === source)
34939
34546
  continue;
34940
34547
  }
34941
34548
  if (stats) {
34942
- const quarantine = `${target}.beeline-quarantine-${Date.now()}-${randomUUID7()}`;
34549
+ const quarantine = `${target}.beeline-quarantine-${Date.now()}-${randomUUID8()}`;
34943
34550
  await rename5(target, quarantine);
34944
34551
  }
34945
34552
  await symlink2(source, target);
@@ -35392,12 +34999,12 @@ function readJsonObject(path) {
35392
34999
  }
35393
35000
  }
35394
35001
  async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, optionalShares) {
35395
- const parent = dirname14(target);
35396
- await assertRealContainedDirectory(parent, dirname14(parent));
35002
+ const parent = dirname13(target);
35003
+ await assertRealContainedDirectory(parent, dirname13(parent));
35397
35004
  const plan = await planManagedSkills(managedSkills, sharedSkills, optionalShares);
35398
35005
  if (await materializedSkillManifest(target) === plan.manifest)
35399
35006
  return;
35400
- const staged = resolve21(parent, `.skills.${process.pid}.${randomUUID7()}.tmp`);
35007
+ const staged = resolve21(parent, `.skills.${process.pid}.${randomUUID8()}.tmp`);
35401
35008
  await mkdir11(staged, { mode: 448 });
35402
35009
  try {
35403
35010
  for (const entry of plan.entries) {
@@ -35433,8 +35040,8 @@ async function planManagedSkills(managedSkills, sharedSkills, optionalShares) {
35433
35040
  try {
35434
35041
  const tree = [];
35435
35042
  await walkSafeSkillTree(shared.source, shared.source, {
35436
- directory: async (rel) => void tree.push(`d ${join11(shared.name, rel)}`),
35437
- file: async (rel, realPath) => void tree.push(`f ${join11(shared.name, rel)} ${sha2563(await readFile16(realPath))}`)
35043
+ directory: async (rel) => void tree.push(`d ${join10(shared.name, rel)}`),
35044
+ file: async (rel, realPath) => void tree.push(`f ${join10(shared.name, rel)} ${sha2563(await readFile16(realPath))}`)
35438
35045
  });
35439
35046
  entries.push({ kind: "shared", name: shared.name, source: shared.source });
35440
35047
  lines.push(...tree);
@@ -35454,7 +35061,7 @@ async function materializedSkillManifest(target) {
35454
35061
  const visit = async (directory, prefix) => {
35455
35062
  for (const entry of await readdir5(directory)) {
35456
35063
  const path = resolve21(directory, entry);
35457
- const rel = prefix ? join11(prefix, entry) : entry;
35064
+ const rel = prefix ? join10(prefix, entry) : entry;
35458
35065
  const entryStats = await lstat3(path);
35459
35066
  if (entryStats.isSymbolicLink())
35460
35067
  return false;
@@ -35622,7 +35229,7 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
35622
35229
  for (const entry of await readdir5(resolvedSource)) {
35623
35230
  if (entry === "." || entry === "..")
35624
35231
  throw new Error("invalid shared skill entry");
35625
- await walkSafeSkillTree(resolve21(source, entry), sourceRoot, visitor, rel ? join11(rel, entry) : entry);
35232
+ await walkSafeSkillTree(resolve21(source, entry), sourceRoot, visitor, rel ? join10(rel, entry) : entry);
35626
35233
  }
35627
35234
  return;
35628
35235
  }
@@ -35644,12 +35251,12 @@ async function copySafeSkillTree(source, target, sourceRoot) {
35644
35251
  });
35645
35252
  }
35646
35253
  async function writeIsolatedHarnessFile(path, content) {
35647
- const parent = dirname14(path);
35254
+ const parent = dirname13(path);
35648
35255
  const parentStats = await lstat3(parent);
35649
35256
  if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
35650
35257
  throw new Error(`isolated harness parent is not a real directory: ${parent}`);
35651
35258
  }
35652
- const temporary = resolve21(parent, `.${basename4(path)}.${process.pid}.${randomUUID7()}.tmp`);
35259
+ const temporary = resolve21(parent, `.${basename4(path)}.${process.pid}.${randomUUID8()}.tmp`);
35653
35260
  try {
35654
35261
  await writeFile11(temporary, content, { mode: 384, flag: "wx" });
35655
35262
  await chmod5(temporary, 384);
@@ -35717,7 +35324,7 @@ function agentCommandCatalogPublisher(input) {
35717
35324
 
35718
35325
  // apps/body/dist/attachment-delivery.js
35719
35326
  import { mkdir as mkdir12, writeFile as writeFile12 } from "node:fs/promises";
35720
- import { basename as basename5, extname, join as join12 } from "node:path";
35327
+ import { basename as basename5, extname, join as join11 } from "node:path";
35721
35328
  var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
35722
35329
  var EXPIRED_REASON = "expired: these attachment bytes are past their retention window";
35723
35330
  var FETCH_TIMEOUT_MS = 3e4;
@@ -35776,7 +35383,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
35776
35383
  return { attachment, reason: EXPIRED_REASON };
35777
35384
  if (!fetched.ok)
35778
35385
  throw new Error(`HTTP ${fetched.status}`);
35779
- const path = join12(dir, safeFileName(attachment, index, taken));
35386
+ const path = join11(dir, safeFileName(attachment, index, taken));
35780
35387
  await writeFile12(path, fetched.bytes);
35781
35388
  const bytes = fetched.bytes;
35782
35389
  const mimeType = attachment.mimeType ?? fetched.mimeType;
@@ -36711,288 +36318,7 @@ function isMcpShapedPermissionRequest(request, hostServers = CODE_OWNED_HOST_MCP
36711
36318
  return /^mcp__[^_].*__[^_]/.test(title) || /^mcp\.[^.]+\.[^.]/.test(title);
36712
36319
  }
36713
36320
 
36714
- // apps/body/dist/youtube-mcp.js
36715
- import { createInterface as createInterface6 } from "node:readline";
36716
- import { readFileSync as readFileSync8 } from "node:fs";
36717
- var YOUTUBE_MCP_SERVER_NAME = "youtube";
36718
- var YOUTUBE_MCP_SURFACE = "youtube";
36719
- var dateProps = {
36720
- startDate: { type: "string", description: "YYYY-MM-DD. Defaults to 28 days ago." },
36721
- endDate: { type: "string", description: "YYYY-MM-DD. Defaults to today (UTC)." }
36722
- };
36723
- var analyticsOwnerNote = ` ${YOUTUBE_ANALYTICS_OWNER_LIMIT}`;
36724
- var YOUTUBE_MCP_TOOLS = [
36725
- {
36726
- name: "youtube_get_channel",
36727
- description: "Get the signed-in channel (id, title, handle, subscribers).",
36728
- inputSchema: { type: "object", properties: {}, additionalProperties: false }
36729
- },
36730
- {
36731
- name: "youtube_list_videos",
36732
- description: "List videos on the signed-in channel.",
36733
- inputSchema: { type: "object", properties: {}, additionalProperties: false }
36734
- },
36735
- {
36736
- name: "youtube_get_video",
36737
- description: "Get one video\u2019s title, description, and view count.",
36738
- inputSchema: {
36739
- type: "object",
36740
- required: ["videoId"],
36741
- properties: { videoId: { type: "string", minLength: 1 } },
36742
- additionalProperties: false
36743
- }
36744
- },
36745
- {
36746
- name: "youtube_list_playlists",
36747
- description: "List playlists on the signed-in channel.",
36748
- inputSchema: { type: "object", properties: {}, additionalProperties: false }
36749
- },
36750
- {
36751
- name: "youtube_list_playlist_items",
36752
- description: "List videos in one playlist.",
36753
- inputSchema: {
36754
- type: "object",
36755
- required: ["playlistId"],
36756
- properties: { playlistId: { type: "string", minLength: 1 } },
36757
- additionalProperties: false
36758
- }
36759
- },
36760
- {
36761
- name: "youtube_get_transcript",
36762
- description: "Fetch captions for a video when a public timedtext track exists.",
36763
- inputSchema: {
36764
- type: "object",
36765
- required: ["videoId"],
36766
- properties: { videoId: { type: "string", minLength: 1 } },
36767
- additionalProperties: false
36768
- }
36769
- },
36770
- {
36771
- name: "youtube_analytics_overview",
36772
- description: `Channel views, watch time, subscribers, likes for a date range.${analyticsOwnerNote}`,
36773
- inputSchema: { type: "object", properties: dateProps, additionalProperties: false }
36774
- },
36775
- {
36776
- name: "youtube_analytics_top_videos",
36777
- description: `Top long-form videos by views (excludes Shorts).${analyticsOwnerNote}`,
36778
- inputSchema: {
36779
- type: "object",
36780
- properties: {
36781
- ...dateProps,
36782
- maxResults: { type: "integer", minimum: 1, maximum: 25 }
36783
- },
36784
- additionalProperties: false
36785
- }
36786
- },
36787
- {
36788
- name: "youtube_analytics_traffic_sources",
36789
- description: `How viewers found the channel (search, suggested, browse\u2026).${analyticsOwnerNote}`,
36790
- inputSchema: { type: "object", properties: dateProps, additionalProperties: false }
36791
- },
36792
- {
36793
- name: "youtube_analytics_demographics",
36794
- description: `Audience age-group and gender breakdown.${analyticsOwnerNote}`,
36795
- inputSchema: { type: "object", properties: dateProps, additionalProperties: false }
36796
- }
36797
- ];
36798
- function stringArg2(args, key) {
36799
- const value = args[key];
36800
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
36801
- }
36802
- function dateArgs(args) {
36803
- const startDate = stringArg2(args, "startDate");
36804
- const endDate = stringArg2(args, "endDate");
36805
- if (startDate && endDate)
36806
- return { startDate, endDate };
36807
- return defaultAnalyticsDateRange();
36808
- }
36809
- function youtubeClientFromToken(accessToken) {
36810
- return googleWorkspaceClient(credentialsTokenSource({ accessToken }));
36811
- }
36812
- async function callYoutubeTool(name, args, client) {
36813
- try {
36814
- return JSON.stringify(await invokeYoutubeTool(name, args, client));
36815
- } catch (error) {
36816
- if (error instanceof GoogleApiError && error.status === 403 && name.startsWith("youtube_analytics_")) {
36817
- throw new Error(YOUTUBE_ANALYTICS_OWNER_LIMIT);
36818
- }
36819
- throw error;
36820
- }
36821
- }
36822
- async function invokeYoutubeTool(name, args, client) {
36823
- switch (name) {
36824
- case "youtube_get_channel":
36825
- return client.youtube.getChannel(true);
36826
- case "youtube_list_videos":
36827
- return client.youtube.listVideos();
36828
- case "youtube_get_video": {
36829
- const videoId = stringArg2(args, "videoId");
36830
- if (!videoId)
36831
- throw new Error("videoId is required");
36832
- return client.youtube.getVideo(videoId);
36833
- }
36834
- case "youtube_list_playlists":
36835
- return client.youtube.listPlaylists(true);
36836
- case "youtube_list_playlist_items": {
36837
- const playlistId = stringArg2(args, "playlistId");
36838
- if (!playlistId)
36839
- throw new Error("playlistId is required");
36840
- return client.youtube.listPlaylistItems(playlistId);
36841
- }
36842
- case "youtube_get_transcript": {
36843
- const videoId = stringArg2(args, "videoId");
36844
- if (!videoId)
36845
- throw new Error("videoId is required");
36846
- return client.youtube.getTranscript(videoId);
36847
- }
36848
- case "youtube_analytics_overview":
36849
- return client.youtube.analyticsQuery({
36850
- metrics: "views,estimatedMinutesWatched,averageViewDuration,subscribersGained,subscribersLost,likes,comments,shares",
36851
- ...dateArgs(args)
36852
- });
36853
- case "youtube_analytics_top_videos":
36854
- return client.youtube.analyticsQuery({
36855
- metrics: "views,estimatedMinutesWatched,averageViewDuration,likes,comments,shares",
36856
- dimensions: "video",
36857
- filters: "creatorContentType==video_on_demand",
36858
- sort: "-views",
36859
- maxResults: typeof args.maxResults === "number" ? args.maxResults : 20,
36860
- ...dateArgs(args)
36861
- });
36862
- case "youtube_analytics_traffic_sources":
36863
- return client.youtube.analyticsQuery({
36864
- metrics: "views,estimatedMinutesWatched",
36865
- dimensions: "insightTrafficSourceType",
36866
- sort: "-views",
36867
- ...dateArgs(args)
36868
- });
36869
- case "youtube_analytics_demographics":
36870
- return client.youtube.analyticsQuery({
36871
- metrics: "viewerPercentage",
36872
- dimensions: "ageGroup,gender",
36873
- sort: "-viewerPercentage",
36874
- ...dateArgs(args)
36875
- });
36876
- default:
36877
- throw new Error(`unknown YouTube tool: ${name}`);
36878
- }
36879
- }
36880
- function youtubeAccessToken(env = process.env) {
36881
- let token = env.BEELINE_YOUTUBE_ACCESS_TOKEN?.trim();
36882
- const path = env.BEELINE_GOOGLE_CREDENTIALS_PATH;
36883
- if (path) {
36884
- try {
36885
- const stored = JSON.parse(readFileSync8(path, "utf8"));
36886
- token = stored.accessToken?.trim();
36887
- } catch {
36888
- token = void 0;
36889
- }
36890
- }
36891
- if (!token) {
36892
- throw new Error("YouTube is not signed in on this helper. Connect Google Workspace from the Workbench \u2014 the same in-app sign-in, not a second overlay.");
36893
- }
36894
- return token;
36895
- }
36896
- function asObject(value) {
36897
- return value && typeof value === "object" && !Array.isArray(value) ? value : {};
36898
- }
36899
- function send(message) {
36900
- process.stdout.write(`${JSON.stringify(message)}
36901
- `);
36902
- }
36903
- function success(id, result) {
36904
- send({ jsonrpc: "2.0", id: id ?? null, result });
36905
- }
36906
- function failure(id, code, message) {
36907
- send({ jsonrpc: "2.0", id: id ?? null, error: { code, message } });
36908
- }
36909
- async function handleYoutubeMcpLine(line, clientFactory = () => youtubeClientFromToken(youtubeAccessToken())) {
36910
- let request;
36911
- try {
36912
- request = JSON.parse(line);
36913
- } catch {
36914
- failure(null, -32700, "invalid JSON");
36915
- return;
36916
- }
36917
- if (request.id === void 0)
36918
- return;
36919
- try {
36920
- if (request.method === "initialize") {
36921
- const params = asObject(request.params);
36922
- success(request.id, {
36923
- protocolVersion: typeof params.protocolVersion === "string" ? params.protocolVersion : "2024-11-05",
36924
- capabilities: { tools: {} },
36925
- serverInfo: { name: YOUTUBE_MCP_SERVER_NAME, version: "1.0.0" }
36926
- });
36927
- return;
36928
- }
36929
- if (request.method === "ping") {
36930
- success(request.id, {});
36931
- return;
36932
- }
36933
- if (request.method === "tools/list") {
36934
- success(request.id, { tools: YOUTUBE_MCP_TOOLS });
36935
- return;
36936
- }
36937
- if (request.method === "tools/call") {
36938
- const params = asObject(request.params);
36939
- if (typeof params.name !== "string")
36940
- throw new Error("tool name must be a string");
36941
- try {
36942
- const output = await callYoutubeTool(params.name, asObject(params.arguments), clientFactory());
36943
- success(request.id, { content: [{ type: "text", text: output }] });
36944
- } catch (error) {
36945
- success(request.id, {
36946
- content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
36947
- isError: true
36948
- });
36949
- }
36950
- return;
36951
- }
36952
- failure(request.id, -32601, `method not found: ${request.method ?? ""}`);
36953
- } catch (error) {
36954
- failure(request.id, -32602, error instanceof Error ? error.message : String(error));
36955
- }
36956
- }
36957
- function listenYoutubeMcpStdio() {
36958
- const lines = createInterface6({ input: process.stdin, crlfDelay: Infinity });
36959
- lines.on("line", (line) => void handleYoutubeMcpLine(line));
36960
- }
36961
- if (/(?:^|\/)youtube-mcp\.(?:js|mjs|ts)$/.test(process.argv[1] ?? "")) {
36962
- listenYoutubeMcpStdio();
36963
- }
36964
-
36965
- // apps/body/dist/google-drive-mcp.js
36966
- var GOOGLE_DRIVE_MCP_SURFACE = "google-drive";
36967
- var GOOGLE_DRIVE_MCP_SERVER_NAME = "google-drive";
36968
-
36969
36321
  // apps/body/dist/room-session.js
36970
- function googleDriveMcpServer(config, accessToken, resourceAuthFile) {
36971
- if (!accessToken || !config.readonlyMcpCommand)
36972
- return void 0;
36973
- const server = {
36974
- name: GOOGLE_DRIVE_MCP_SERVER_NAME,
36975
- command: config.readonlyMcpCommand,
36976
- args: [...config.readonlyMcpArgs ?? []],
36977
- env: [
36978
- { name: "BEELINE_MCP_SURFACE", value: GOOGLE_DRIVE_MCP_SURFACE },
36979
- { name: "BEELINE_GOOGLE_DRIVE_ACCESS_TOKEN", value: accessToken }
36980
- ]
36981
- };
36982
- if (!resourceAuthFile)
36983
- return server;
36984
- const route = rewriteHostMcpDeclaration(server.name, {
36985
- command: server.command,
36986
- args: server.args,
36987
- env: Object.fromEntries((server.env ?? []).map((entry) => [entry.name, entry.value]))
36988
- }, config.operatorHome ?? "", resourceAuthFile);
36989
- return {
36990
- name: server.name,
36991
- command: String(route.command),
36992
- args: route.args,
36993
- env: Object.entries(route.env).map(([name, value]) => ({ name, value }))
36994
- };
36995
- }
36996
36322
  var ReadOnlyToolsUnavailableError = class extends Error {
36997
36323
  name = "ReadOnlyToolsUnavailableError";
36998
36324
  };
@@ -37049,79 +36375,18 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
37049
36375
  ]
37050
36376
  };
37051
36377
  }
37052
- function youtubeMcpServer(config, accessToken, resourceAuthFile) {
37053
- if (!accessToken || !config.readonlyMcpCommand)
37054
- return void 0;
37055
- const server = {
37056
- name: YOUTUBE_MCP_SERVER_NAME,
37057
- command: config.readonlyMcpCommand,
37058
- args: [...config.readonlyMcpArgs ?? []],
37059
- env: [
37060
- { name: "BEELINE_MCP_SURFACE", value: YOUTUBE_MCP_SURFACE },
37061
- { name: "BEELINE_YOUTUBE_ACCESS_TOKEN", value: accessToken },
37062
- {
37063
- name: "BEELINE_GOOGLE_CREDENTIALS_PATH",
37064
- value: resolve23(process.env.BEELINE_AGENT_HOME ?? process.cwd(), "google-credentials.json")
37065
- }
37066
- ]
37067
- };
37068
- if (!resourceAuthFile)
37069
- return server;
37070
- const route = rewriteHostMcpDeclaration(server.name, {
37071
- command: server.command,
37072
- args: server.args,
37073
- env: Object.fromEntries((server.env ?? []).map((entry) => [entry.name, entry.value]))
37074
- }, config.operatorHome ?? "", resourceAuthFile);
37075
- return {
37076
- name: server.name,
37077
- command: String(route.command),
37078
- args: route.args,
37079
- env: Object.entries(route.env).map(([name, value]) => ({ name, value }))
37080
- };
37081
- }
37082
-
37083
- // apps/body/dist/room-google-grant.js
37084
- import { createHash as createHash8 } from "node:crypto";
37085
- async function roomGoogleToolTokens(api, roomId) {
37086
- try {
37087
- let timeout;
37088
- const grant = await Promise.race([
37089
- api.execute("getRoomGoogleGrant", { roomId }),
37090
- new Promise((_resolve, reject) => {
37091
- timeout = setTimeout(() => reject(new Error("Google grant lookup timed out")), 3e3);
37092
- })
37093
- ]).finally(() => {
37094
- if (timeout)
37095
- clearTimeout(timeout);
37096
- });
37097
- if (grant.status !== "ready" || !grant.credentials)
37098
- return {};
37099
- const { accessToken, scopes } = grant.credentials;
37100
- const types = grant.connectedTypes ?? [];
37101
- const hasScopes = (type) => GOOGLE_TOOL_SCOPES[type].every((scope) => scopes.includes(scope));
37102
- return {
37103
- ...(types.includes("google-gmail") || types.includes("google-drive")) && hasScopes("google-drive") ? { drive: accessToken } : {},
37104
- ...types.includes("google-youtube") && hasScopes("google-youtube") ? { youtube: accessToken } : {}
37105
- };
37106
- } catch {
37107
- return {};
37108
- }
37109
- }
37110
- function roomGoogleToolFingerprint(tokens) {
37111
- return Object.entries(tokens).map(([name, token]) => `google-${name}:${createHash8("sha256").update(token).digest("hex")}`);
37112
- }
37113
36378
 
37114
36379
  // apps/body/dist/codegraph.js
37115
36380
  import { execFile as execFile10 } from "node:child_process";
37116
36381
  import { access as access2, appendFile, mkdir as mkdir14, readFile as readFile17 } from "node:fs/promises";
37117
- import { dirname as dirname15, isAbsolute as isAbsolute3, resolve as resolve24 } from "node:path";
36382
+ import { dirname as dirname14, isAbsolute as isAbsolute3, resolve as resolve24 } from "node:path";
37118
36383
  import { promisify as promisify6 } from "node:util";
37119
36384
  var execFileAsync6 = promisify6(execFile10);
37120
36385
  var CODEGRAPH_MCP_SERVER_NAME = "codegraph";
37121
36386
  var CODEGRAPH_INDEX_PATH = ".codegraph/codegraph.db";
37122
36387
  var CODEGRAPH_PREPARE_TIMEOUT_MS = 12e4;
37123
36388
  function codegraphIndexDirectory(cwd) {
37124
- return resolve24(cwd, dirname15(CODEGRAPH_INDEX_PATH));
36389
+ return resolve24(cwd, dirname14(CODEGRAPH_INDEX_PATH));
37125
36390
  }
37126
36391
  function codegraphMcpServer(config, cwd, options) {
37127
36392
  if (!config.codegraphCommand)
@@ -37162,7 +36427,7 @@ async function excludeIndexFromGitStatus(cwd) {
37162
36427
  if (!gitPath)
37163
36428
  return;
37164
36429
  const path = isAbsolute3(gitPath) ? gitPath : resolve24(cwd, gitPath);
37165
- await mkdir14(dirname15(path), { recursive: true });
36430
+ await mkdir14(dirname14(path), { recursive: true });
37166
36431
  const existing = await readFile17(path, "utf8").catch(() => "");
37167
36432
  if (existing.split("\n").includes(".codegraph/"))
37168
36433
  return;
@@ -37255,6 +36520,57 @@ function isAccountOrProviderRefusal(record6) {
37255
36520
  // apps/body/dist/monolith-corner-turn.js
37256
36521
  init_runtime();
37257
36522
 
36523
+ // apps/body/dist/transcript-budget.js
36524
+ function budgetTranscript(lines, modelContextTokens, otherPromptBytes) {
36525
+ const context = modelContextTokens && modelContextTokens > 0 ? modelContextTokens : 32768;
36526
+ const reserveTokens = Math.max(4096, Math.ceil(context * 0.3));
36527
+ const available = Math.max(0, context - Math.ceil(otherPromptBytes / 2) - reserveTokens);
36528
+ const budget = Math.max(0, Math.min(24e3, Math.floor(context * 0.25), available * 2) - 128);
36529
+ if (!budget)
36530
+ return [];
36531
+ const selected = [];
36532
+ let used = 0;
36533
+ const rowLimit = Math.min(4096, Math.floor(budget / 2));
36534
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
36535
+ const row = boundMessageText(lines[index], rowLimit);
36536
+ const bytes = Buffer.byteLength(row) + 1;
36537
+ if (used + bytes > budget)
36538
+ break;
36539
+ selected.push(row);
36540
+ used += bytes;
36541
+ }
36542
+ selected.reverse();
36543
+ if (selected.length < lines.length) {
36544
+ selected.unshift(`[${lines.length - selected.length} older messages omitted from this prompt]`);
36545
+ }
36546
+ return selected;
36547
+ }
36548
+ function boundRoomTaskBody(body, modelContextTokens) {
36549
+ const context = modelContextTokens && modelContextTokens > 0 ? modelContextTokens : 32768;
36550
+ return boundMessageText(body, Math.min(8e3, Math.floor(context / 4)));
36551
+ }
36552
+ function boundMessageText(original, maxBytes) {
36553
+ const sanitized = stripInlineData(original);
36554
+ const clean4 = sanitized === original ? original : sanitized + fetchPointer(original, "inline content omitted");
36555
+ return Buffer.byteLength(clean4) > maxBytes ? truncateRow(clean4, maxBytes) : clean4;
36556
+ }
36557
+ function stripInlineData(text2) {
36558
+ return text2.replace(/data:[^\s"'<>)]*/gi, "[inline data omitted]").replace(/\b[A-Za-z0-9+/]{512,}={0,2}\b/g, (candidate) => /[A-Z]/.test(candidate) && /[a-z]/.test(candidate) && /[0-9+/]/.test(candidate) ? "[inline binary data omitted]" : candidate);
36559
+ }
36560
+ function truncateRow(row, maxBytes) {
36561
+ const pointer = fetchPointer(row, "message truncated");
36562
+ const contentBytes = Math.max(0, maxBytes - Buffer.byteLength(pointer));
36563
+ let prefix = Buffer.from(row).subarray(0, contentBytes).toString("utf8");
36564
+ prefix = prefix.replace(/\uFFFD$/, "");
36565
+ return prefix + pointer;
36566
+ }
36567
+ function fetchPointer(row, reason) {
36568
+ const id = /^\[message id: ([^\]\n]+)\]/.exec(row)?.[1];
36569
+ return id ? `
36570
+ [${reason}; call get_room_message with messageId "${id}" and offset 0 for the full text]` : `
36571
+ [${reason}; read the source conversation for the full text]`;
36572
+ }
36573
+
37258
36574
  // apps/body/dist/prompt-assembly.js
37259
36575
  var PROMPT_SURFACES = [
37260
36576
  "room",
@@ -37756,7 +37072,23 @@ ${task.body}`,
37756
37072
  }
37757
37073
  ];
37758
37074
  function assembleTurnPrompt(context) {
37759
- const entries = applicable(TURN_SECTIONS, context);
37075
+ const boundedContext = ROOMS.includes(context.surface) ? {
37076
+ ...context,
37077
+ task: {
37078
+ ...context.task,
37079
+ body: boundRoomTaskBody(context.task.body, context.modelContextTokens)
37080
+ }
37081
+ } : context;
37082
+ const withoutTranscript = applicable(TURN_SECTIONS, {
37083
+ ...boundedContext,
37084
+ transcript: void 0
37085
+ });
37086
+ const otherBytes = withoutTranscript.reduce((sum, entry) => sum + Buffer.byteLength(entry.text) + 2, 0);
37087
+ const lines = budgetTranscript(boundedContext.transcript?.lines ?? [], boundedContext.modelContextTokens, otherBytes);
37088
+ const entries = applicable(TURN_SECTIONS, {
37089
+ ...boundedContext,
37090
+ transcript: boundedContext.transcript ? { ...boundedContext.transcript, lines } : void 0
37091
+ });
37760
37092
  return {
37761
37093
  text: entries.map((entry) => entry.text).join("\n\n"),
37762
37094
  report: entries.map(({ section, text: text2 }) => ({
@@ -38264,10 +37596,10 @@ process.exit(result.status ?? 1);
38264
37596
  }
38265
37597
 
38266
37598
  // apps/body/dist/warm-node-modules.js
38267
- import { createHash as createHash9, randomUUID as randomUUID8 } from "node:crypto";
38268
- import { constants as fsConstants2 } from "node:fs";
37599
+ import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
37600
+ import { constants as fsConstants3 } from "node:fs";
38269
37601
  import { chmod as chmod7, copyFile as copyFile2, link, lstat as lstat4, mkdir as mkdir17, readdir as readdir7, readFile as readFile18, readlink as readlink2, rename as rename6, rm as rm8, stat as stat6, symlink as symlink3, utimes } from "node:fs/promises";
38270
- import { dirname as dirname16, join as join13, resolve as resolve27 } from "node:path";
37602
+ import { dirname as dirname15, join as join12, resolve as resolve27 } from "node:path";
38271
37603
  var STORE_FORMAT = "v1";
38272
37604
  var STAGING_PREFIX = ".beeline-warm-";
38273
37605
  var STAGING_SWEEP_MS = 24 * 60 * 60 * 1e3;
@@ -38303,7 +37635,7 @@ async function readWarmPlan(worktreePath) {
38303
37635
  const unsafe = trees.find((tree) => !isContainedTreePath(tree));
38304
37636
  if (unsafe)
38305
37637
  return { failure: "unsafe-lockfile", detail: unsafe };
38306
- const key = createHash9("sha256").update(`${STORE_FORMAT}\0${process.platform}\0${process.arch}\0${process.versions.modules}\0`).update(lockfile).digest("hex").slice(0, 32);
37638
+ const key = createHash8("sha256").update(`${STORE_FORMAT}\0${process.platform}\0${process.arch}\0${process.versions.modules}\0`).update(lockfile).digest("hex").slice(0, 32);
38307
37639
  return { key, trees };
38308
37640
  }
38309
37641
  function nodeModulesTreePaths(packages) {
@@ -38341,7 +37673,7 @@ async function seedWarmNodeModules(input) {
38341
37673
  if (storeDevice === void 0 || storeDevice !== checkoutDevice) {
38342
37674
  return { reason: "cross-device", key: plan.key };
38343
37675
  }
38344
- const staging = resolve27(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID8()}`);
37676
+ const staging = resolve27(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID9()}`);
38345
37677
  const placed = [];
38346
37678
  const now2 = (input.now ?? Date.now)();
38347
37679
  try {
@@ -38352,7 +37684,7 @@ async function seedWarmNodeModules(input) {
38352
37684
  }
38353
37685
  for (const tree of plan.trees) {
38354
37686
  const target = resolve27(input.worktreePath, tree);
38355
- await mkdir17(dirname16(target), { recursive: true });
37687
+ await mkdir17(dirname15(target), { recursive: true });
38356
37688
  await rename6(resolve27(staging, tree), target);
38357
37689
  placed.push(target);
38358
37690
  }
@@ -38387,7 +37719,7 @@ async function harvestWarmNodeModules(input) {
38387
37719
  detail: `${missing.length} absent, e.g. ${missing.slice(0, 3).join(", ")}`
38388
37720
  };
38389
37721
  }
38390
- const staging = resolve27(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID8()}`);
37722
+ const staging = resolve27(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID9()}`);
38391
37723
  try {
38392
37724
  await mkdir17(input.storeRoot, { recursive: true, mode: 493 });
38393
37725
  await sweepStaleStaging(input.storeRoot, (input.now ?? Date.now)());
@@ -38413,7 +37745,7 @@ async function stagedTreeIsPublishable(worktreePath, staging, key) {
38413
37745
  const settled = await readWarmPlan(worktreePath);
38414
37746
  if (isPlanRefusal(settled) || settled.key !== key)
38415
37747
  return false;
38416
- const hidden = join13("node_modules", ".package-lock.json");
37748
+ const hidden = join12("node_modules", ".package-lock.json");
38417
37749
  const [copied, current] = await Promise.all([
38418
37750
  readFile18(resolve27(staging, hidden)).catch(() => void 0),
38419
37751
  readFile18(resolve27(worktreePath, hidden)).catch(() => void 0)
@@ -38451,7 +37783,7 @@ async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
38451
37783
  return missing.sort();
38452
37784
  }
38453
37785
  async function isInstalledPackage(path) {
38454
- return stat6(join13(path, "package.json")).then((info) => info.isFile(), () => false);
37786
+ return stat6(join12(path, "package.json")).then((info) => info.isFile(), () => false);
38455
37787
  }
38456
37788
  var INTEGRITY_READ_CONCURRENCY = 64;
38457
37789
  async function mapWithLimit(values, limit, visit) {
@@ -38485,8 +37817,8 @@ function isContainedTreePath(value) {
38485
37817
  async function cloneTree(source, target, file, topLevel = true) {
38486
37818
  await mkdir17(target, { recursive: true, mode: 493 });
38487
37819
  for (const entry of await readdir7(source, { withFileTypes: true })) {
38488
- const from = join13(source, entry.name);
38489
- const to = join13(target, entry.name);
37820
+ const from = join12(source, entry.name);
37821
+ const to = join12(target, entry.name);
38490
37822
  if (entry.isSymbolicLink()) {
38491
37823
  await symlink3(await readlink2(from), to);
38492
37824
  continue;
@@ -38500,7 +37832,7 @@ async function cloneTree(source, target, file, topLevel = true) {
38500
37832
  }
38501
37833
  }
38502
37834
  var harvestFile = async (source, target) => {
38503
- await copyFile2(source, target, fsConstants2.COPYFILE_FICLONE);
37835
+ await copyFile2(source, target, fsConstants3.COPYFILE_FICLONE);
38504
37836
  const info = await stat6(source);
38505
37837
  await chmod7(target, info.mode & 4095 & ~146);
38506
37838
  };
@@ -38516,13 +37848,13 @@ async function pruneWarmStore(storeRoot, keep) {
38516
37848
  const names = (await readdir7(storeRoot).catch(() => [])).filter((name) => !name.startsWith(STAGING_PREFIX));
38517
37849
  const entries = [];
38518
37850
  for (const name of names) {
38519
- const info = await lstat4(join13(storeRoot, name)).catch(() => void 0);
37851
+ const info = await lstat4(join12(storeRoot, name)).catch(() => void 0);
38520
37852
  if (info?.isDirectory())
38521
37853
  entries.push({ name, usedAt: info.mtimeMs });
38522
37854
  }
38523
37855
  const dropped = entries.sort((a2, b) => b.usedAt - a2.usedAt || a2.name.localeCompare(b.name)).slice(keep);
38524
37856
  for (const entry of dropped) {
38525
- await rm8(join13(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
37857
+ await rm8(join12(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
38526
37858
  }
38527
37859
  return dropped.map((entry) => entry.name);
38528
37860
  }
@@ -38531,7 +37863,7 @@ async function sweepStaleStaging(storeRoot, now2) {
38531
37863
  for (const name of entries) {
38532
37864
  if (!name.startsWith(STAGING_PREFIX))
38533
37865
  continue;
38534
- const path = join13(storeRoot, name);
37866
+ const path = join12(storeRoot, name);
38535
37867
  const info = await lstat4(path).catch(() => void 0);
38536
37868
  if (!info || now2 - info.mtimeMs < STAGING_SWEEP_MS)
38537
37869
  continue;
@@ -38692,7 +38024,7 @@ function filePaths(value, worktreePath) {
38692
38024
  visit(value);
38693
38025
  return [...paths];
38694
38026
  }
38695
- function resultStatus(call) {
38027
+ function resultStatus2(call) {
38696
38028
  const content = record5(call.content) ?? (typeof call.content === "string" ? (() => {
38697
38029
  try {
38698
38030
  return record5(JSON.parse(call.content));
@@ -38721,7 +38053,7 @@ function spentAuthorityOnLaneUpgrade(call) {
38721
38053
  return /(?:^|[._:/-])upgrade_corner_to_code$/i.test(call.title ?? "") && isCompletedToolCall(call);
38722
38054
  }
38723
38055
  function toolCallKey(call, index) {
38724
- return call.id ? `id-${createHash10("sha256").update(call.id).digest("hex")}` : `tool-${index}`;
38056
+ return call.id ? `id-${createHash9("sha256").update(call.id).digest("hex")}` : `tool-${index}`;
38725
38057
  }
38726
38058
  function toolCallSettled(call) {
38727
38059
  if (call.resultReceived)
@@ -38753,7 +38085,7 @@ async function cornerToolActivity(call, worktreePath, requestedBy) {
38753
38085
  kind: "tool",
38754
38086
  title: title.slice(0, 240),
38755
38087
  operation: operation.slice(0, 80),
38756
- status: resultStatus(call),
38088
+ status: resultStatus2(call),
38757
38089
  ...argumentsSummary,
38758
38090
  ...output ? { output } : {},
38759
38091
  ...requestedBy ? { requestedBy } : {},
@@ -38964,14 +38296,13 @@ var MonolithCornerTurnLoop = class {
38964
38296
  return await this.currentSessionFingerprint() === this.sessionFingerprint;
38965
38297
  }
38966
38298
  async currentSessionFingerprint() {
38967
- const [configuration, roster, grantedHostRoutes, googleTokens] = await Promise.all([
38299
+ const [configuration, roster, grantedHostRoutes] = await Promise.all([
38968
38300
  this.options.api.execute("getAgentConfiguration", {
38969
38301
  agentId: this.agent.publicKey,
38970
38302
  roomId: this.options.cornerId
38971
38303
  }),
38972
38304
  this.roster(),
38973
- this.grantedHostRoutes(),
38974
- roomGoogleToolTokens(this.options.api, this.options.cornerId)
38305
+ this.grantedHostRoutes()
38975
38306
  ]);
38976
38307
  const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
38977
38308
  const registryRoutes = configuration.registryMcpRoutes ?? [];
@@ -38991,8 +38322,7 @@ var MonolithCornerTurnLoop = class {
38991
38322
  ...registryRoutes.map((route) => route.routeName)
38992
38323
  ]
38993
38324
  }),
38994
- ...registryRoutes.map((route) => route.routeName),
38995
- ...roomGoogleToolFingerprint(googleTokens)
38325
+ ...registryRoutes.map((route) => route.routeName)
38996
38326
  ], this.sessionCodegraphReady),
38997
38327
  reviewerHandle: configuration.reviewerHandle
38998
38328
  });
@@ -39027,14 +38357,13 @@ var MonolithCornerTurnLoop = class {
39027
38357
  return this.sessionId;
39028
38358
  }
39029
38359
  trace?.noteActivation("cold");
39030
- const [configuration, roster, grantedHostRoutes, googleTokens] = await Promise.all([
38360
+ const [configuration, roster, grantedHostRoutes] = await Promise.all([
39031
38361
  this.options.api.execute("getAgentConfiguration", {
39032
38362
  agentId: this.agent.publicKey,
39033
38363
  roomId: this.options.cornerId
39034
38364
  }),
39035
38365
  this.roster(),
39036
- this.grantedHostRoutes(),
39037
- roomGoogleToolTokens(this.options.api, this.options.cornerId)
38366
+ this.grantedHostRoutes()
39038
38367
  ]);
39039
38368
  const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
39040
38369
  this.yoloMode = configuration.yoloMode;
@@ -39074,7 +38403,7 @@ var MonolithCornerTurnLoop = class {
39074
38403
  }) ? { relay: await this.squireRelay.listen() } : {}
39075
38404
  };
39076
38405
  const resourceAuthFile = `${this.commandContext.path}.resource-auth.json`;
39077
- await mkdir18(dirname17(resourceAuthFile), { recursive: true, mode: 448 });
38406
+ await mkdir18(dirname16(resourceAuthFile), { recursive: true, mode: 448 });
39078
38407
  await writeFile14(resourceAuthFile, JSON.stringify({
39079
38408
  ...this.options.api.connection(),
39080
38409
  turnContextPath: this.commandContext.path
@@ -39141,7 +38470,7 @@ var MonolithCornerTurnLoop = class {
39141
38470
  args: this.options.config.agentArgs ?? []
39142
38471
  }, selection);
39143
38472
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
39144
- this.attachmentDir = tmpDir ? join14(tmpDir, "beeline-attachments") : void 0;
38473
+ this.attachmentDir = tmpDir ? join13(tmpDir, "beeline-attachments") : void 0;
39145
38474
  this.sessionScratchDir = tmpDir;
39146
38475
  const homeStateDirs = harnessHomeStateDirs(harnessLabel, agentEnv.HOME ?? operatorHome);
39147
38476
  await Promise.all(homeStateDirs.map((dir) => mkdir18(dir, { recursive: true })));
@@ -39210,8 +38539,7 @@ var MonolithCornerTurnLoop = class {
39210
38539
  agentKind: this.options.config.agentKind,
39211
38540
  grantedHostRoutes: mountedHostRoutes
39212
38541
  }),
39213
- ...Object.keys(registryHostDeclarations),
39214
- ...roomGoogleToolFingerprint(googleTokens)
38542
+ ...Object.keys(registryHostDeclarations)
39215
38543
  ], codegraphReady),
39216
38544
  reviewerHandle: configuration.reviewerHandle
39217
38545
  });
@@ -39259,12 +38587,6 @@ var MonolithCornerTurnLoop = class {
39259
38587
  if (codegraph)
39260
38588
  servers.push(codegraph);
39261
38589
  }
39262
- const youtube = youtubeMcpServer(this.options.config, googleTokens.youtube, resourceAuthFile);
39263
- if (youtube)
39264
- servers.push(youtube);
39265
- const drive = googleDriveMcpServer(this.options.config, googleTokens.drive, resourceAuthFile);
39266
- if (drive)
39267
- servers.push(drive);
39268
38590
  const grantedRouteServers = grantedHostRouteWires(mountedHostRoutes, operatorHome, { ...hostDeclarations, ...registryHostDeclarations }, resourceAuthFile, squireScope);
39269
38591
  await installPiMcpBridge({
39270
38592
  agentCommand: harnessLabel,
@@ -39484,10 +38806,10 @@ var MonolithCornerTurnLoop = class {
39484
38806
  size: file.size
39485
38807
  }));
39486
38808
  const allAttachments = [...attachments, ...briefAttachments];
39487
- const delivered = this.attachmentDir && allAttachments.length ? await deliverAttachments(allAttachments, join14(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : [];
38809
+ const delivered = this.attachmentDir && allAttachments.length ? await deliverAttachments(allAttachments, join13(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : [];
39488
38810
  const briefFileLines = await Promise.all((restored.brief?.attachments ?? []).map(async (file, index) => {
39489
38811
  const entry = delivered.find((item) => item.attachment === briefAttachments[index]);
39490
- const verified = entry?.path && createHash10("sha256").update(await readFile19(entry.path)).digest("hex") === file.sha256;
38812
+ const verified = entry?.path && createHash9("sha256").update(await readFile19(entry.path)).digest("hex") === file.sha256;
39491
38813
  return `- ${file.title} (${file.purpose}; ${file.required ? "required" : "optional"}; sha256 ${file.sha256}): ${verified ? entry.path : "UNAVAILABLE OR CONTENT MISMATCH"}`;
39492
38814
  }));
39493
38815
  const missingRequiredBriefFile = (restored.brief?.attachments ?? []).some((file, index) => file.required && briefFileLines[index]?.includes("UNAVAILABLE OR CONTENT MISMATCH"));
@@ -39763,9 +39085,9 @@ var MonolithCornerTurnLoop = class {
39763
39085
  answer = durableReplyText(stream.remainderOf(result.agentText));
39764
39086
  const reply = withNudgeReply(answer);
39765
39087
  for (const call of result.toolCalls) {
39766
- const failure2 = toolCallFailureLine(call);
39767
- if (failure2)
39768
- console.warn(`[thin-core] corner ${cornerId} ${failure2}`);
39088
+ const failure = toolCallFailureLine(call);
39089
+ if (failure)
39090
+ console.warn(`[thin-core] corner ${cornerId} ${failure}`);
39769
39091
  }
39770
39092
  stream.close();
39771
39093
  if (!reply && explained) {
@@ -39958,12 +39280,34 @@ var MonolithCornerTurnLoop = class {
39958
39280
  // apps/body/dist/monolith-room-turn.js
39959
39281
  import { mkdir as mkdir19, writeFile as writeFile15 } from "node:fs/promises";
39960
39282
  import { homedir as homedir15, hostname as hostname2 } from "node:os";
39961
- import { dirname as dirname18, join as join15 } from "node:path";
39283
+ import { dirname as dirname17, join as join15 } from "node:path";
39962
39284
 
39963
39285
  // packages/api-contract/dist/scheduled-prompts.js
39964
39286
  var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
39965
39287
  var SCHEDULE_RAN_VERB = "ran a schedule for";
39966
39288
 
39289
+ // apps/body/dist/model-context-window.js
39290
+ import { readFile as readFile20 } from "node:fs/promises";
39291
+ import { join as join14 } from "node:path";
39292
+ async function modelContextWindowTokens(model, piHome) {
39293
+ if (!model || !piHome)
39294
+ return void 0;
39295
+ try {
39296
+ const catalog = JSON.parse(await readFile20(join14(piHome, "models.json"), "utf8"));
39297
+ const parts = model.split("/");
39298
+ const preferredProvider = parts.length > 2 ? parts.shift() : void 0;
39299
+ const modelId = parts.join("/");
39300
+ const providers = preferredProvider ? [catalog.providers?.[preferredProvider]].filter(Boolean) : Object.values(catalog.providers ?? {});
39301
+ for (const provider of providers) {
39302
+ const window = provider?.models?.find((entry) => entry.id === modelId)?.contextWindow;
39303
+ if (window && Number.isFinite(window) && window > 0)
39304
+ return Math.floor(window);
39305
+ }
39306
+ } catch {
39307
+ }
39308
+ return void 0;
39309
+ }
39310
+
39967
39311
  // apps/body/dist/monolith-room-turn.js
39968
39312
  init_cursor_acp_bridge();
39969
39313
  init_runtime();
@@ -40005,10 +39349,11 @@ function inboxItemAuthorName(item, names) {
40005
39349
  function inboxItemPromptBody(item) {
40006
39350
  return isScheduledPrompt(item) ? item.systemEvent?.consequence ?? item.body : item.body;
40007
39351
  }
40008
- function pendingGrantToolCall(call) {
40009
- if (!/(?:^|[._:/-])(?:request_grant|offer_connector)$/i.test(call.title ?? ""))
40010
- return false;
40011
- return /(?:pending|already offered), card (?:posted|still open)/i.test(typeof call.content === "string" ? call.content : JSON.stringify(call.content ?? ""));
39352
+ function pendingCardKind(call) {
39353
+ const kind = /(?:^|[._:/-])(request_grant|offer_connector)$/i.exec(call.title ?? "")?.[1];
39354
+ if (!kind || !/(?:pending|already offered), card (?:posted|still open)/i.test(typeof call.content === "string" ? call.content : JSON.stringify(call.content ?? "")))
39355
+ return void 0;
39356
+ return kind.toLowerCase() === "request_grant" ? "grant" : "connector";
40012
39357
  }
40013
39358
  function resumePrompt(item) {
40014
39359
  if (item.systemEvent?.kind === "connector-offer-decided") {
@@ -40071,6 +39416,7 @@ var MonolithRoomTurnLoop = class {
40071
39416
  queuedTurns = [];
40072
39417
  /** Session scratch directory attachments are downloaded into (`TMPDIR/beeline-attachments`). */
40073
39418
  attachmentDir;
39419
+ modelContextTokens;
40074
39420
  /** Whether the pinned model takes images; `undefined` when the pin did not say. */
40075
39421
  modelTakesImages;
40076
39422
  /** The session's TMPDIR: writable to a granted command in a Room, as it is to the harness (C94). */
@@ -40085,6 +39431,7 @@ var MonolithRoomTurnLoop = class {
40085
39431
  memberNames = /* @__PURE__ */ new Map();
40086
39432
  /** The request id of the turn that paused on a grant card, until its decision arrives. */
40087
39433
  pausedOnGrantRequestId;
39434
+ pausedOnGrantKind;
40088
39435
  /** Operator-local turn traces; built once when the daemon configured a directory. */
40089
39436
  turnTraceSink;
40090
39437
  constructor(options) {
@@ -40283,14 +39630,13 @@ var MonolithRoomTurnLoop = class {
40283
39630
  });
40284
39631
  }
40285
39632
  async currentSessionFingerprint() {
40286
- const [configuration, roster, grantedHostRoutes, googleTokens] = await Promise.all([
39633
+ const [configuration, roster, grantedHostRoutes] = await Promise.all([
40287
39634
  this.options.api.execute("getAgentConfiguration", {
40288
39635
  agentId: this.agent.publicKey,
40289
39636
  roomId: this.options.roomId
40290
39637
  }),
40291
39638
  this.roster(),
40292
- this.grantedHostRoutes(),
40293
- roomGoogleToolTokens(this.options.api, this.options.roomId)
39639
+ this.grantedHostRoutes()
40294
39640
  ]);
40295
39641
  const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
40296
39642
  const registryRoutes = configuration.registryMcpRoutes ?? [];
@@ -40309,8 +39655,7 @@ var MonolithRoomTurnLoop = class {
40309
39655
  ...registryRoutes.map((route) => route.routeName)
40310
39656
  ]
40311
39657
  }),
40312
- ...registryRoutes.map((route) => route.routeName),
40313
- ...roomGoogleToolFingerprint(googleTokens)
39658
+ ...registryRoutes.map((route) => route.routeName)
40314
39659
  ], this.sessionCodegraphReady)
40315
39660
  });
40316
39661
  }
@@ -40352,15 +39697,14 @@ var MonolithRoomTurnLoop = class {
40352
39697
  return this.sessionId;
40353
39698
  }
40354
39699
  trace?.noteActivation("cold");
40355
- const [configuration, roster, repositoryState, grantedHostRoutes, googleTokens] = await Promise.all([
39700
+ const [configuration, roster, repositoryState, grantedHostRoutes] = await Promise.all([
40356
39701
  this.options.api.execute("getAgentConfiguration", {
40357
39702
  agentId: this.agent.publicKey,
40358
39703
  roomId: this.options.roomId
40359
39704
  }),
40360
39705
  this.roster(),
40361
39706
  this.repositoryState(),
40362
- this.grantedHostRoutes(),
40363
- roomGoogleToolTokens(this.options.api, this.options.roomId)
39707
+ this.grantedHostRoutes()
40364
39708
  ]);
40365
39709
  const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
40366
39710
  const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
@@ -40384,7 +39728,7 @@ var MonolithRoomTurnLoop = class {
40384
39728
  }) ? { relay: await this.squireRelay.listen() } : {}
40385
39729
  };
40386
39730
  const resourceAuthFile = `${this.commandContext.path}.resource-auth.json`;
40387
- await mkdir19(dirname18(resourceAuthFile), { recursive: true, mode: 448 });
39731
+ await mkdir19(dirname17(resourceAuthFile), { recursive: true, mode: 448 });
40388
39732
  await writeFile15(resourceAuthFile, JSON.stringify({
40389
39733
  ...this.options.api.connection(),
40390
39734
  turnContextPath: this.commandContext.path
@@ -40415,6 +39759,7 @@ var MonolithRoomTurnLoop = class {
40415
39759
  });
40416
39760
  const agentEnv = { ...this.options.config.agentEnv, ...homeOverlay };
40417
39761
  this.agentEnv = agentEnv;
39762
+ this.modelContextTokens = await modelContextWindowTokens(selectionModel, agentEnv.PI_CODING_AGENT_DIR);
40418
39763
  const agentArgs = agentArgsWithModelSelection({
40419
39764
  kind: this.options.config.agentKind,
40420
39765
  command,
@@ -40442,8 +39787,7 @@ var MonolithRoomTurnLoop = class {
40442
39787
  agentKind: this.options.config.agentKind,
40443
39788
  grantedHostRoutes: mountedHostRoutes
40444
39789
  }),
40445
- ...Object.keys(registryHostDeclarations),
40446
- ...roomGoogleToolFingerprint(googleTokens)
39790
+ ...Object.keys(registryHostDeclarations)
40447
39791
  ], codegraphReady)
40448
39792
  });
40449
39793
  const spawnCommand = wrapAgentCommand({
@@ -40487,12 +39831,6 @@ var MonolithRoomTurnLoop = class {
40487
39831
  if (codegraph)
40488
39832
  servers.push(codegraph);
40489
39833
  }
40490
- const youtube = youtubeMcpServer(this.options.config, googleTokens.youtube, resourceAuthFile);
40491
- if (youtube)
40492
- servers.push(youtube);
40493
- const drive = googleDriveMcpServer(this.options.config, googleTokens.drive, resourceAuthFile);
40494
- if (drive)
40495
- servers.push(drive);
40496
39834
  const hostDeclarations = hostImportedMcpDeclarations({
40497
39835
  operatorHome,
40498
39836
  agentKind: this.options.config.agentKind
@@ -40672,6 +40010,10 @@ var MonolithRoomTurnLoop = class {
40672
40010
  * the press and the delivery, and the server's own receipt already said so.
40673
40011
  */
40674
40012
  stopTurn(requestId) {
40013
+ if (this.pausedOnGrantRequestId === requestId) {
40014
+ this.pausedOnGrantRequestId = void 0;
40015
+ this.pausedOnGrantKind = void 0;
40016
+ }
40675
40017
  this.squireRelay.cancel(requestId);
40676
40018
  for (let index = this.queuedTurns.length - 1; index >= 0; index -= 1)
40677
40019
  if (this.queuedTurns[index].id === requestId)
@@ -40736,10 +40078,15 @@ var MonolithRoomTurnLoop = class {
40736
40078
  authorId: message.authorId,
40737
40079
  line: roomMessagePrompt(names.get(message.authorId) ?? message.authorId.slice(0, 12), message.body, message.attachments, this.deliveredAttachments.get(message.id), this.acceptsImages(), message.id)
40738
40080
  }));
40739
- const grantDecision = this.commandContext.current?.action === "resume";
40740
- const resumedRequestId = grantDecision ? this.pausedOnGrantRequestId : void 0;
40741
- if (grantDecision)
40081
+ const command = this.commandContext.current;
40082
+ const grantDecision = command?.action === "resume";
40083
+ const decisionKind = command?.source.systemEvent?.kind;
40084
+ const decisionResume = grantDecision && command.turnRequestId === this.pausedOnGrantRequestId && (decisionKind === "grant-decided" && this.pausedOnGrantKind === "grant" || decisionKind === "connector-offer-decided" && this.pausedOnGrantKind === "connector");
40085
+ const resumedRequestId = decisionResume ? this.pausedOnGrantRequestId : void 0;
40086
+ if (decisionResume) {
40742
40087
  this.pausedOnGrantRequestId = void 0;
40088
+ this.pausedOnGrantKind = void 0;
40089
+ }
40743
40090
  const openCorners = (corners.corners ?? []).filter((corner) => !corner.archived);
40744
40091
  const closedSince = Math.floor(Date.now() / 1e3) - 24 * 60 * 60;
40745
40092
  const closedCorners = (corners.corners ?? []).filter((corner) => corner.archived && corner.closedAt !== void 0 && corner.closedAt >= closedSince).sort((a2, b) => (b.closedAt ?? 0) - (a2.closedAt ?? 0));
@@ -40747,6 +40094,7 @@ var MonolithRoomTurnLoop = class {
40747
40094
  const transcript = this.warmTranscript.select(this.sessionId, transcriptRows, this.agent.publicKey);
40748
40095
  const assembled = assembleTurnPrompt({
40749
40096
  surface: this.sessionSurface,
40097
+ modelContextTokens: this.modelContextTokens,
40750
40098
  sessionPrefix: this.turnInstructionPrefix,
40751
40099
  ...institutionalContext.standingPreference ? {
40752
40100
  standingPreference: {
@@ -40860,8 +40208,10 @@ var MonolithRoomTurnLoop = class {
40860
40208
  throw new TurnStoppedError("turn stopped by the requester");
40861
40209
  }
40862
40210
  active.phase = "finishing";
40863
- if (result.toolCalls.some((call) => pendingGrantToolCall(call))) {
40211
+ const pendingCard = result.toolCalls.map((call) => pendingCardKind(call)).find(Boolean);
40212
+ if (pendingCard) {
40864
40213
  this.pausedOnGrantRequestId = item.id;
40214
+ this.pausedOnGrantKind = pendingCard;
40865
40215
  console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id} paused on a grant card`);
40866
40216
  } else if (resumedRequestId) {
40867
40217
  console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${resumedRequestId} resumed by card decision ${item.id}`);
@@ -40872,9 +40222,9 @@ var MonolithRoomTurnLoop = class {
40872
40222
  this.options.onCornerOpened?.();
40873
40223
  }
40874
40224
  for (const call of result?.toolCalls ?? []) {
40875
- const failure2 = toolCallFailureLine(call);
40876
- if (failure2) {
40877
- console.warn(`[thin-core] monolith Room ${this.options.roomId} ${failure2}`);
40225
+ const failure = toolCallFailureLine(call);
40226
+ if (failure) {
40227
+ console.warn(`[thin-core] monolith Room ${this.options.roomId} ${failure}`);
40878
40228
  }
40879
40229
  }
40880
40230
  stream.close();
@@ -40978,7 +40328,7 @@ var MonolithRoomTurnLoop = class {
40978
40328
  console.error("[thin-core] Room command failed", error);
40979
40329
  },
40980
40330
  onEnter: (command) => this.squireRelay.activate(command, this.commandContext.generationId),
40981
- onLeave: (command) => this.squireRelay.deactivate(command.turnRequestId, this.pausedOnGrantRequestId === command.turnRequestId ? "grant-decision" : null),
40331
+ onLeave: (command) => this.squireRelay.deactivate(command.turnRequestId, this.pausedOnGrantRequestId),
40982
40332
  stop: (requestId) => this.stopTurn(requestId),
40983
40333
  restart: () => this.options.onRestartRequested?.(),
40984
40334
  canStartTurn: this.options.canStartTurn,
@@ -41535,8 +40885,8 @@ var DiscoveryWakes = class {
41535
40885
  this.served = Math.max(this.served, covered);
41536
40886
  }
41537
40887
  };
41538
- function shouldPostInitialCornerWorkingState(restore, isOpener = true) {
41539
- return isOpener && !restore.featureBranch && !restore.lifecycle?.branch && !restore.lifecycle?.pr;
40888
+ function shouldPostInitialCornerWorkingState(restore) {
40889
+ return !restore.lifecycle?.branch && !restore.lifecycle?.pr;
41540
40890
  }
41541
40891
  function cornerBranchIsSafeToDelete(lifecycle) {
41542
40892
  const pr = lifecycle?.pr;
@@ -41552,7 +40902,7 @@ function cornerStartConfigKey(repository, objective) {
41552
40902
  }
41553
40903
  function cornerRepositoryCacheDir(supervisorRoot, remote) {
41554
40904
  const normalizedRemote = roomCheckoutRemote(remote);
41555
- const repositoryHash = createHash11("sha256").update(normalizedRemote).digest("hex").slice(0, 24);
40905
+ const repositoryHash = createHash10("sha256").update(normalizedRemote).digest("hex").slice(0, 24);
41556
40906
  return resolve29(supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
41557
40907
  }
41558
40908
  function isStandingCornerStartFault(error) {
@@ -41563,8 +40913,8 @@ async function materializeCornerWorktree(input) {
41563
40913
  const remote = roomCheckoutRemote(input.remote);
41564
40914
  const gitCommonDir = cornerRepositoryCacheDir(input.supervisorRoot, remote);
41565
40915
  const path = resolve29(input.supervisorRoot, "beeline", "corners", input.cornerId);
41566
- await mkdir20(dirname19(gitCommonDir), { recursive: true, mode: 448 });
41567
- await mkdir20(dirname19(path), { recursive: true, mode: 448 });
40916
+ await mkdir20(dirname18(gitCommonDir), { recursive: true, mode: 448 });
40917
+ await mkdir20(dirname18(path), { recursive: true, mode: 448 });
41568
40918
  const authEnv = githubGitEnv(input.token);
41569
40919
  if (!existsSync8(resolve29(gitCommonDir, "HEAD"))) {
41570
40920
  await execFileAsync8("git", ["clone", "--bare", remote, gitCommonDir], {
@@ -41645,6 +40995,34 @@ async function materializeCornerWorktree(input) {
41645
40995
  }
41646
40996
  return { path, gitCommonDir };
41647
40997
  }
40998
+ async function cornerScratchFiles(root) {
40999
+ const files = [];
41000
+ const visit = async (directory, prefix) => {
41001
+ for (const entry of await readdir8(directory, { withFileTypes: true })) {
41002
+ const name = prefix ? `${prefix}/${entry.name}` : entry.name;
41003
+ if (entry.isDirectory())
41004
+ await visit(resolve29(directory, entry.name), name);
41005
+ else
41006
+ files.push(name);
41007
+ }
41008
+ };
41009
+ await visit(root, "");
41010
+ return files;
41011
+ }
41012
+ async function ignoredGitPaths(worktree, paths) {
41013
+ if (!paths.length)
41014
+ return /* @__PURE__ */ new Set();
41015
+ return new Promise((resolve40, reject) => {
41016
+ const child = execFile12("git", ["-C", worktree, "check-ignore", "-z", "--stdin"], { maxBuffer: 16 * 1024 * 1024 }, (error, stdout6) => {
41017
+ if (error && error.code !== 1)
41018
+ reject(error);
41019
+ else
41020
+ resolve40(new Set(stdout6.split("\0").filter(Boolean)));
41021
+ });
41022
+ child.stdin?.on("error", reject);
41023
+ child.stdin?.end(`${paths.join("\0")}\0`);
41024
+ });
41025
+ }
41648
41026
  async function mapWithConcurrency(values, limit, visit) {
41649
41027
  let cursor3 = 0;
41650
41028
  await Promise.all(Array.from({ length: Math.min(limit, values.length) }, async () => {
@@ -41657,7 +41035,7 @@ async function mapWithConcurrency(values, limit, visit) {
41657
41035
  async function discoverCornerWorktree(supervisorRoot, cornerId) {
41658
41036
  const cornersRoot = resolve29(supervisorRoot, "beeline", "corners");
41659
41037
  const path = resolve29(cornersRoot, cornerId);
41660
- if (dirname19(path) !== cornersRoot || !existsSync8(resolve29(path, ".git")))
41038
+ if (dirname18(path) !== cornersRoot || !existsSync8(resolve29(path, ".git")))
41661
41039
  return void 0;
41662
41040
  const [canonicalRoot, canonicalPath] = await Promise.all([
41663
41041
  realpath2(cornersRoot),
@@ -41790,6 +41168,8 @@ var RoomRuntimeCoordinator = class {
41790
41168
  localWorktreeIds;
41791
41169
  /** Event-driven cleanup retries stay scoped to the failed local corner. */
41792
41170
  archiveCleanupFaults = /* @__PURE__ */ new Map();
41171
+ /** A refused local checkout is kept until a later Room listing proves membership again. */
41172
+ archiveCleanupAccessDenied = /* @__PURE__ */ new Set();
41793
41173
  startingCorners = /* @__PURE__ */ new Set();
41794
41174
  /**
41795
41175
  * Rooms whose start is in flight. `running` is not set until the checkout
@@ -41986,12 +41366,16 @@ var RoomRuntimeCoordinator = class {
41986
41366
  return turns;
41987
41367
  }
41988
41368
  async reconcile() {
41369
+ if (this.stopped)
41370
+ return "member";
41989
41371
  this.confirmationPending = false;
41990
41372
  const existingRooms = new Set(this.running.keys());
41991
41373
  const coveredWakes = this.discoveryWakes.beginReconcile();
41992
41374
  const bootstrap = await this.options.daemonApi.execute("getDaemonBootstrap", {
41993
41375
  agentId: this.agent.publicKey
41994
41376
  });
41377
+ if (this.stopped)
41378
+ return "member";
41995
41379
  if (!bootstrap.workspaceIds.includes(this.runtime.communityId)) {
41996
41380
  this.workspaceRemovalConfirmations += 1;
41997
41381
  if (this.workspaceRemovalConfirmations < REMOVAL_CONFIRMATION_READS) {
@@ -42027,6 +41411,8 @@ var RoomRuntimeCoordinator = class {
42027
41411
  const desiredCorners = /* @__PURE__ */ new Map();
42028
41412
  const archivedCorners = /* @__PURE__ */ new Map();
42029
41413
  await mapWithConcurrency(topLevelRooms, ROOM_JOIN_CONCURRENCY, async (room) => {
41414
+ if (this.stopped)
41415
+ return;
42030
41416
  try {
42031
41417
  const result = await this.options.daemonApi.execute("listRoomCorners", {
42032
41418
  roomId: room.roomId
@@ -42057,6 +41443,8 @@ var RoomRuntimeCoordinator = class {
42057
41443
  console.error(`[thin-core] monolith Room ${room.roomId} corner listing failed; keeping known corners:`, error);
42058
41444
  }
42059
41445
  });
41446
+ if (this.stopped)
41447
+ return "member";
42060
41448
  for (const roomId of desiredTopRooms)
42061
41449
  this.surfaceHealth.discover(roomId, "room");
42062
41450
  for (const cornerId of desiredCorners.keys())
@@ -42064,7 +41452,11 @@ var RoomRuntimeCoordinator = class {
42064
41452
  for (const channelId of desired)
42065
41453
  this.roomRemovalConfirmations.delete(channelId);
42066
41454
  await this.retryPendingCornerReaps(desired);
41455
+ if (this.stopped)
41456
+ return "member";
42067
41457
  await this.sweepArchivedCornerWorktrees(archivedCorners, desired);
41458
+ if (this.stopped)
41459
+ return "member";
42068
41460
  for (const cornerId of this.idleCornerSubscriptions.keys()) {
42069
41461
  if (desired.has(cornerId))
42070
41462
  continue;
@@ -42084,6 +41476,8 @@ var RoomRuntimeCoordinator = class {
42084
41476
  }
42085
41477
  this.surfaceHealth.retain(/* @__PURE__ */ new Set([...desired, ...this.running.keys()]));
42086
41478
  await mapWithConcurrency(desiredTopRooms, ROOM_JOIN_CONCURRENCY, async (roomId) => {
41479
+ if (this.stopped)
41480
+ return;
42087
41481
  if (this.running.has(roomId))
42088
41482
  return;
42089
41483
  try {
@@ -42093,6 +41487,8 @@ var RoomRuntimeCoordinator = class {
42093
41487
  }
42094
41488
  });
42095
41489
  await mapWithConcurrency([...desiredCorners.values()], ROOM_JOIN_CONCURRENCY, async (corner) => {
41490
+ if (this.stopped)
41491
+ return;
42096
41492
  if (!this.running.has(corner.cornerId))
42097
41493
  await this.watchCorner(corner);
42098
41494
  });
@@ -42134,6 +41530,8 @@ var RoomRuntimeCoordinator = class {
42134
41530
  * An unscoped wake still uses the slow reconcile as recovery.
42135
41531
  */
42136
41532
  async applyMembershipEvent(event) {
41533
+ if (this.stopped)
41534
+ return;
42137
41535
  const roomId = event.roomId;
42138
41536
  if (!roomId) {
42139
41537
  this.wakeDiscovery();
@@ -42179,22 +41577,24 @@ var RoomRuntimeCoordinator = class {
42179
41577
  /** Retire the scratch runtime. Ordinary desired-state reconciliation starts
42180
41578
  * the same corner id again and re-reads its now-code lane. */
42181
41579
  async applyCornerRestart(cornerId) {
41580
+ if (this.stopped)
41581
+ return;
42182
41582
  const running = this.running.get(cornerId);
42183
41583
  if (!running) {
42184
41584
  this.wakeDiscovery();
42185
41585
  return;
42186
41586
  }
42187
- await this.stopRunning(cornerId, running);
41587
+ await this.stopRunning(cornerId, running, true);
42188
41588
  this.wakeDiscovery();
42189
41589
  }
42190
- async stopRunning(channelId, running) {
41590
+ async stopRunning(channelId, running, preserveScratch = false) {
42191
41591
  this.deferredRepositoryRestarts.delete(channelId);
42192
41592
  running.controller.abort();
42193
41593
  await running.promise.catch(() => void 0);
42194
41594
  try {
42195
41595
  if (running.worktree)
42196
41596
  await this.reapCornerWorktree(running.worktree);
42197
- else if (running.scratch)
41597
+ else if (running.scratch && !preserveScratch)
42198
41598
  await this.reapCornerScratch(running.scratch);
42199
41599
  } catch (error) {
42200
41600
  console.error(`[thin-core] corner ${channelId} cleanup failed; will retry:`, error);
@@ -42205,7 +41605,7 @@ var RoomRuntimeCoordinator = class {
42205
41605
  return this.runtime.rooms.find((room) => room.channelId === roomId);
42206
41606
  }
42207
41607
  roomRoot(roomId) {
42208
- return this.roomRecord(roomId)?.root ?? resolve29(dirname19(this.configPath), "rooms", roomId);
41608
+ return this.roomRecord(roomId)?.root ?? resolve29(dirname18(this.configPath), "rooms", roomId);
42209
41609
  }
42210
41610
  roomAgentHomeRoot(workspaceRoot, required = false) {
42211
41611
  const flag = process.env.BUZZY_BODY_ROOM_HOME;
@@ -42215,7 +41615,7 @@ var RoomRuntimeCoordinator = class {
42215
41615
  if (!required && flag !== "1" && !existsSync8(home) && existsSync8(workspaceRoot))
42216
41616
  return void 0;
42217
41617
  try {
42218
- mkdirSync4(home, { recursive: true, mode: 448 });
41618
+ mkdirSync3(home, { recursive: true, mode: 448 });
42219
41619
  return home;
42220
41620
  } catch (error) {
42221
41621
  console.error(`[thin-core] per-room agent home unavailable at ${home}:`, error);
@@ -42228,9 +41628,9 @@ var RoomRuntimeCoordinator = class {
42228
41628
  ...this.baseConfig,
42229
41629
  workspaceRoot,
42230
41630
  agentPrivateRoot: resolve29(workspaceRoot, "agent-private"),
42231
- agentMemoryRoot: resolve29(dirname19(this.configPath), "memory"),
42232
- openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname19(this.configPath)),
42233
- turnTraceDir: turnTraceDirectory(dirname19(this.configPath)),
41631
+ agentMemoryRoot: resolve29(dirname18(this.configPath), "memory"),
41632
+ openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname18(this.configPath)),
41633
+ turnTraceDir: turnTraceDirectory(dirname18(this.configPath)),
42234
41634
  ...agentHomeRoot ? { agentHomeRoot } : {}
42235
41635
  };
42236
41636
  }
@@ -42242,6 +41642,8 @@ var RoomRuntimeCoordinator = class {
42242
41642
  });
42243
41643
  }
42244
41644
  async startRoom(roomId) {
41645
+ if (this.stopped)
41646
+ return;
42245
41647
  if (this.running.has(roomId) || this.startingRooms.has(roomId))
42246
41648
  return;
42247
41649
  this.surfaceHealth.discover(roomId, "room");
@@ -42322,9 +41724,9 @@ var RoomRuntimeCoordinator = class {
42322
41724
  return this.roomRoot(roomId);
42323
41725
  const remote = roomCheckoutRemote(repository.remote);
42324
41726
  const targetBranch = repository.targetBranch || "main";
42325
- const checkoutId = createHash11("sha256").update(`${roomId}\0${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
41727
+ const checkoutId = createHash10("sha256").update(`${roomId}\0${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
42326
41728
  const path = resolve29(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
42327
- await mkdir20(dirname19(path), { recursive: true, mode: 448 });
41729
+ await mkdir20(dirname18(path), { recursive: true, mode: 448 });
42328
41730
  const token = remote.startsWith("https://github.com/") ? await this.parentRepositoryToken(roomId) : void 0;
42329
41731
  const env = token ? githubGitEnv(token.token) : process.env;
42330
41732
  if (!existsSync8(resolve29(path, ".git"))) {
@@ -42372,6 +41774,8 @@ var RoomRuntimeCoordinator = class {
42372
41774
  }
42373
41775
  }
42374
41776
  async startCorner(corner) {
41777
+ if (this.stopped)
41778
+ return;
42375
41779
  if (this.running.has(corner.cornerId) || this.startingCorners.has(corner.cornerId))
42376
41780
  return;
42377
41781
  this.surfaceHealth.discover(corner.cornerId, "corner");
@@ -42400,6 +41804,9 @@ var RoomRuntimeCoordinator = class {
42400
41804
  if (!objective)
42401
41805
  throw new Error("corner has no authoritative objective fact");
42402
41806
  const repositoryBacked = repository.resolution === "repository" && restore.lane !== "no_code";
41807
+ const scratchPath = resolve29(this.roomRoot(corner.cornerId), "scratch");
41808
+ if (repositoryBacked && existsSync8(scratchPath) && !restore.featureBranch)
41809
+ throw new Error("promoted corner has no server-assigned feature branch");
42403
41810
  const targetBranch = repositoryBacked ? repository.targetBranch || "main" : void 0;
42404
41811
  const featureBranch = repositoryBacked ? restore.featureBranch ?? `feature/corner-${corner.cornerId.replaceAll("-", "").slice(0, 12)}` : void 0;
42405
41812
  const granted = repositoryBacked ? await this.cornerRepositoryToken(corner.parentRoomId) : void 0;
@@ -42410,11 +41817,51 @@ var RoomRuntimeCoordinator = class {
42410
41817
  featureBranch,
42411
41818
  token: granted.token
42412
41819
  }) : void 0;
41820
+ if (worktree) {
41821
+ if (existsSync8(scratchPath)) {
41822
+ const entries = await readdir8(scratchPath);
41823
+ if (entries.includes(".git"))
41824
+ throw new Error("corner scratch contains a Git repository");
41825
+ const files = await cornerScratchFiles(scratchPath);
41826
+ const baselineIgnored = await ignoredGitPaths(worktree.path, files);
41827
+ for (const entry of entries)
41828
+ await cp(resolve29(scratchPath, entry), resolve29(worktree.path, entry), {
41829
+ recursive: true,
41830
+ force: true
41831
+ });
41832
+ if (entries.length) {
41833
+ const scratchIgnored = await ignoredGitPaths(worktree.path, files);
41834
+ const stageable = files.filter((file) => !baselineIgnored.has(file) && !scratchIgnored.has(file));
41835
+ for (let offset = 0; offset < stageable.length; offset += 256)
41836
+ await execFileAsync8("git", [
41837
+ "-C",
41838
+ worktree.path,
41839
+ "add",
41840
+ "-A",
41841
+ "--",
41842
+ ...stageable.slice(offset, offset + 256)
41843
+ ]);
41844
+ const changed = await execFileAsync8("git", ["-C", worktree.path, "diff", "--cached", "--quiet"]).then(() => false, (error) => {
41845
+ if (error.code === 1)
41846
+ return true;
41847
+ throw error;
41848
+ });
41849
+ if (changed)
41850
+ await execFileAsync8("git", [
41851
+ "-C",
41852
+ worktree.path,
41853
+ "commit",
41854
+ "-m",
41855
+ "Carry no-code corner files into code branch"
41856
+ ]);
41857
+ }
41858
+ await this.reapCornerScratch({ path: scratchPath, cornerId: corner.cornerId });
41859
+ }
41860
+ }
42413
41861
  const workspacePath = worktree?.path ?? resolve29(this.roomRoot(corner.cornerId), "scratch");
42414
41862
  if (!worktree)
42415
41863
  await mkdir20(workspacePath, { recursive: true, mode: 448 });
42416
- const isOpener = corner.openedBy === this.agent.publicKey;
42417
- if (worktree && shouldPostInitialCornerWorkingState(restore, isOpener)) {
41864
+ if (worktree && shouldPostInitialCornerWorkingState(restore)) {
42418
41865
  await this.options.daemonApi.execute("postCornerRemoteState", {
42419
41866
  cornerId: corner.cornerId,
42420
41867
  branch: featureBranch,
@@ -42516,6 +41963,8 @@ var RoomRuntimeCoordinator = class {
42516
41963
  }
42517
41964
  }
42518
41965
  async watchCorner(corner) {
41966
+ if (this.stopped)
41967
+ return;
42519
41968
  const cornerId = corner.cornerId;
42520
41969
  if (this.running.has(cornerId))
42521
41970
  return;
@@ -42700,6 +42149,9 @@ var RoomRuntimeCoordinator = class {
42700
42149
  continue;
42701
42150
  if (!this.archiveCleanupDue(cornerId))
42702
42151
  continue;
42152
+ if (this.archiveCleanupAccessDenied.has(cornerId) && !corners.has(cornerId))
42153
+ continue;
42154
+ this.archiveCleanupAccessDenied.delete(cornerId);
42703
42155
  let corner = corners.get(cornerId);
42704
42156
  let discovered;
42705
42157
  try {
@@ -42743,7 +42195,10 @@ var RoomRuntimeCoordinator = class {
42743
42195
  });
42744
42196
  console.log(`[thin-core] swept archived corner worktree ${cornerId}`);
42745
42197
  } catch (error) {
42746
- this.deferArchiveCleanup(cornerId);
42198
+ if (error instanceof DaemonApiError && error.status === 403)
42199
+ this.archiveCleanupAccessDenied.add(cornerId);
42200
+ else
42201
+ this.deferArchiveCleanup(cornerId);
42747
42202
  console.error(`[thin-core] archived corner ${cornerId} cleanup deferred:`, error);
42748
42203
  }
42749
42204
  }
@@ -42819,6 +42274,8 @@ var RoomRuntimeCoordinator = class {
42819
42274
  room.backoffUntil = Math.max(room.backoffUntil, this.now() + retryInMs);
42820
42275
  }
42821
42276
  async watchdogTick() {
42277
+ if (this.stopped)
42278
+ return;
42822
42279
  for (const [roomId, room] of [...this.running]) {
42823
42280
  if (room.recovering || room.body.isBusy())
42824
42281
  continue;
@@ -42829,17 +42286,25 @@ var RoomRuntimeCoordinator = class {
42829
42286
  await room.promise.catch(() => void 0);
42830
42287
  if (room.worktree) {
42831
42288
  this.confirmationPending = true;
42832
- } else if (!this.running.has(roomId)) {
42289
+ } else if (!this.stopped && !this.running.has(roomId)) {
42833
42290
  this.startRoom(roomId);
42834
42291
  }
42835
42292
  }
42836
42293
  }
42837
- async shutdown() {
42294
+ beginShutdown() {
42295
+ if (this.stopped)
42296
+ return;
42838
42297
  this.stopped = true;
42298
+ this.restartRequested = true;
42839
42299
  for (const cornerId of this.idleCornerSubscriptions.keys())
42840
42300
  this.unwatchCorner(cornerId);
42841
42301
  this.options.daemonApi.closeLive?.();
42842
42302
  this.pendingMembershipEvents.clear();
42303
+ for (const room of this.running.values())
42304
+ room.controller.abort();
42305
+ }
42306
+ async shutdown() {
42307
+ this.beginShutdown();
42843
42308
  const deadlineAt = Math.min(this.now() + this.drainDeadlineMs, this.drainDeadlineAt ?? Number.POSITIVE_INFINITY);
42844
42309
  const untilDeadline = async (work) => {
42845
42310
  let timer;
@@ -43024,8 +42489,16 @@ var ThinDaemonCore = class {
43024
42489
  this.roomRuntime.setDrainDeadlineAt(deadlineAt);
43025
42490
  }
43026
42491
  async run(opts = {}) {
43027
- await opts.onEstablished?.();
42492
+ const stop = () => {
42493
+ this.roomRuntime.setDrainDeadlineAt(Date.now() + 45e3);
42494
+ this.roomRuntime.beginShutdown();
42495
+ };
42496
+ opts.signal?.addEventListener("abort", stop, { once: true });
42497
+ if (opts.signal?.aborted)
42498
+ stop();
43028
42499
  try {
42500
+ if (!opts.signal?.aborted)
42501
+ await opts.onEstablished?.();
43029
42502
  while (!opts.signal?.aborted) {
43030
42503
  this.pendingDiscovery = false;
43031
42504
  try {
@@ -43040,19 +42513,46 @@ var ThinDaemonCore = class {
43040
42513
  this.discoveryStatus = `monolith discovery degraded: ${error instanceof Error ? error.message : String(error)}`;
43041
42514
  this.roomRuntime.reconnectAfterFailure();
43042
42515
  }
42516
+ if (opts.signal?.aborted)
42517
+ break;
43043
42518
  await opts.onProgress?.(this.healthStatus());
43044
42519
  if (!this.pendingDiscovery)
43045
42520
  await this.waitForDiscovery(opts.signal);
43046
42521
  }
43047
42522
  return "aborted";
43048
42523
  } finally {
42524
+ opts.signal?.removeEventListener("abort", stop);
43049
42525
  await this.roomRuntime.shutdown();
43050
42526
  }
43051
42527
  }
43052
42528
  };
43053
42529
 
42530
+ // apps/body/dist/daemon-shutdown.js
42531
+ var DAEMON_HARD_STOP_MS = 75e3;
42532
+ function installDaemonStopSignals(controller, options = {}) {
42533
+ const emitter = options.emitter ?? process;
42534
+ let timer;
42535
+ const stop = () => {
42536
+ if (controller.signal.aborted)
42537
+ return;
42538
+ timer = setTimeout(() => {
42539
+ console.error("[thin-core] shutdown deadline reached; exiting old helper");
42540
+ (options.hardExit ?? (() => process.exit(0)))();
42541
+ }, options.timeoutMs ?? DAEMON_HARD_STOP_MS);
42542
+ controller.abort();
42543
+ };
42544
+ emitter.once("SIGINT", stop);
42545
+ emitter.once("SIGTERM", stop);
42546
+ return () => {
42547
+ if (timer)
42548
+ clearTimeout(timer);
42549
+ emitter.removeListener("SIGINT", stop);
42550
+ emitter.removeListener("SIGTERM", stop);
42551
+ };
42552
+ }
42553
+
43054
42554
  // apps/body/dist/force-update-journal.js
43055
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync9, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
42555
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
43056
42556
  import { resolve as resolve30 } from "node:path";
43057
42557
  var NAME = "force-update-interruptions.json";
43058
42558
  function pathFor(runtimeDir) {
@@ -43060,7 +42560,7 @@ function pathFor(runtimeDir) {
43060
42560
  }
43061
42561
  function read(runtimeDir) {
43062
42562
  try {
43063
- const rows = JSON.parse(readFileSync9(pathFor(runtimeDir), "utf8"));
42563
+ const rows = JSON.parse(readFileSync8(pathFor(runtimeDir), "utf8"));
43064
42564
  if (!Array.isArray(rows))
43065
42565
  throw new Error("invalid force-update interruption journal");
43066
42566
  return rows.map((row) => {
@@ -43078,10 +42578,10 @@ function read(runtimeDir) {
43078
42578
  }
43079
42579
  }
43080
42580
  function write(runtimeDir, rows) {
43081
- mkdirSync5(runtimeDir, { recursive: true, mode: 448 });
42581
+ mkdirSync4(runtimeDir, { recursive: true, mode: 448 });
43082
42582
  const target = pathFor(runtimeDir);
43083
42583
  const temporary = `${target}.${process.pid}.tmp`;
43084
- writeFileSync4(temporary, `${JSON.stringify(rows)}
42584
+ writeFileSync3(temporary, `${JSON.stringify(rows)}
43085
42585
  `, { mode: 384 });
43086
42586
  renameSync(temporary, target);
43087
42587
  }
@@ -43136,9 +42636,9 @@ init_runtime();
43136
42636
  init_launchd();
43137
42637
  init_systemd();
43138
42638
  import { spawn as spawn11 } from "node:child_process";
43139
- import { createHash as createHash12 } from "node:crypto";
42639
+ import { createHash as createHash11 } from "node:crypto";
43140
42640
  import { mkdir as mkdir23, rm as rm11, stat as stat7, writeFile as writeFile17 } from "node:fs/promises";
43141
- import { dirname as dirname21, resolve as resolve33 } from "node:path";
42641
+ import { dirname as dirname20, resolve as resolve33 } from "node:path";
43142
42642
 
43143
42643
  // apps/body/dist/update-functional-probe.js
43144
42644
  import { mkdir as mkdir21, rm as rm10 } from "node:fs/promises";
@@ -43406,8 +42906,8 @@ async function runUpdateFunctionalProbe(input) {
43406
42906
  }
43407
42907
  let error = initialError;
43408
42908
  let detail = error instanceof Error ? error.message : String(error);
43409
- let failure2 = classifyAcpTurnFailure(error);
43410
- if (failure2) {
42909
+ let failure = classifyAcpTurnFailure(error);
42910
+ if (failure) {
43411
42911
  await new Promise((resolveWait) => setTimeout(resolveWait, input.retryDelayMs ?? UPDATE_PROBE_RETRY_DELAY_MS));
43412
42912
  try {
43413
42913
  const retried = await openSessionAndPrompt();
@@ -43420,27 +42920,27 @@ async function runUpdateFunctionalProbe(input) {
43420
42920
  } catch (retryError) {
43421
42921
  const retryDetail = retryError instanceof Error ? retryError.message : String(retryError);
43422
42922
  const retryFailure = classifyAcpTurnFailure(retryError);
43423
- if (!retryFailure || !sameAcpTurnFailure(failure2, retryFailure)) {
42923
+ if (!retryFailure || !sameAcpTurnFailure(failure, retryFailure)) {
43424
42924
  throw new UpdateFunctionalProbeError("turn-failed", retryDetail, {
43425
42925
  cause: retryError
43426
42926
  });
43427
42927
  }
43428
42928
  error = retryError;
43429
42929
  detail = retryDetail;
43430
- failure2 = retryFailure;
42930
+ failure = retryFailure;
43431
42931
  }
43432
42932
  }
43433
42933
  if (error === void 0) {
43434
- } else if (!failure2 || !input.compareWithCurrentRelease) {
42934
+ } else if (!failure || !input.compareWithCurrentRelease) {
43435
42935
  throw new UpdateFunctionalProbeError("turn-failed", detail, { cause: error });
43436
42936
  } else {
43437
42937
  const current = await input.compareWithCurrentRelease({
43438
42938
  kind: "acp-turn-failure",
43439
42939
  reason: detail,
43440
- failure: failure2
42940
+ failure
43441
42941
  });
43442
42942
  const currentFailure = current.kind === "unavailable" ? classifyAcpTurnFailure(current.reason) : void 0;
43443
- if (!currentFailure || !sameAcpTurnFailure(failure2, currentFailure)) {
42943
+ if (!currentFailure || !sameAcpTurnFailure(failure, currentFailure)) {
43444
42944
  throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { cause: error });
43445
42945
  }
43446
42946
  console.warn(`[body] update probe: the probe turn failed the same way on this release and the current release (${detail}); that failure is not this bundle's doing, so the probe passes as inconclusive`);
@@ -43471,8 +42971,8 @@ async function runUpdateFunctionalProbe(input) {
43471
42971
  }
43472
42972
 
43473
42973
  // apps/body/dist/update-rollback-alert.js
43474
- import { mkdir as mkdir22, readFile as readFile20, rename as rename7, unlink as unlink6, writeFile as writeFile16 } from "node:fs/promises";
43475
- import { dirname as dirname20, resolve as resolve32 } from "node:path";
42974
+ import { mkdir as mkdir22, readFile as readFile21, rename as rename7, unlink as unlink6, writeFile as writeFile16 } from "node:fs/promises";
42975
+ import { dirname as dirname19, resolve as resolve32 } from "node:path";
43476
42976
  var REPORT_INTERVAL_MS = 60 * 60 * 1e3;
43477
42977
  var lastLogged = /* @__PURE__ */ new Map();
43478
42978
  function updateRollbackAlertPath(runtimeDir) {
@@ -43481,7 +42981,7 @@ function updateRollbackAlertPath(runtimeDir) {
43481
42981
  async function writeAlert(runtimeDir, alert) {
43482
42982
  const path = updateRollbackAlertPath(runtimeDir);
43483
42983
  const staged = `${path}.${process.pid}.tmp`;
43484
- await mkdir22(dirname20(path), { recursive: true });
42984
+ await mkdir22(dirname19(path), { recursive: true });
43485
42985
  await writeFile16(staged, `${JSON.stringify(alert, null, 2)}
43486
42986
  `, { mode: 384 });
43487
42987
  await rename7(staged, path);
@@ -43494,7 +42994,7 @@ async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()
43494
42994
  }
43495
42995
  async function readUpdateRollbackAlert(runtimeDir) {
43496
42996
  try {
43497
- const value = JSON.parse(await readFile20(updateRollbackAlertPath(runtimeDir), "utf8"));
42997
+ const value = JSON.parse(await readFile21(updateRollbackAlertPath(runtimeDir), "utf8"));
43498
42998
  if (value.version !== 1 || typeof value.releaseId !== "string")
43499
42999
  return void 0;
43500
43000
  return value;
@@ -43540,21 +43040,21 @@ async function reportUpdateRollback(input) {
43540
43040
  init_adapter_install_lock();
43541
43041
  var UPDATE_CONVERGENCE_SLO_MS = 10 * 6e4;
43542
43042
  var DEFAULT_UPDATE_INTERVAL_MS = 3e4;
43543
- var UPDATE_DRAIN_DEADLINE_MS = UPDATE_CONVERGENCE_SLO_MS - 6e4;
43043
+ var UPDATE_DRAIN_DEADLINE_MS = UPDATE_CONVERGENCE_SLO_MS - 15e4;
43544
43044
  var MAX_HOST_RESTART_STAGGER_MS = 15e3;
43545
43045
  function managedRestartStaggerMs(agentId, desiredRelease, drainDeadlineAt, now2 = Date.now()) {
43546
- const digest = createHash12("sha256").update(agentId).update("\0").update(desiredRelease).digest();
43046
+ const digest = createHash11("sha256").update(agentId).update("\0").update(desiredRelease).digest();
43547
43047
  const spread = digest.readUInt32BE(0) % (MAX_HOST_RESTART_STAGGER_MS + 1);
43548
43048
  return Math.min(spread, Math.max(0, drainDeadlineAt - now2));
43549
43049
  }
43550
- var UPDATE_WORKER_DEADLINE_MS = UPDATE_DRAIN_DEADLINE_MS;
43050
+ var UPDATE_WORKER_DEADLINE_MS = UPDATE_CONVERGENCE_SLO_MS - 6e4;
43551
43051
  var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
43552
43052
  var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
43553
43053
  async function withInstallLock(layout, work, options = {}) {
43554
43054
  const now2 = options.now ?? Date.now;
43555
43055
  const lock = resolve33(layout.releasesRoot, ".state", "install.lock");
43556
43056
  const deadline = now2() + (options.waitMs ?? 1e4);
43557
- await mkdir23(dirname21(lock), { recursive: true });
43057
+ await mkdir23(dirname20(lock), { recursive: true });
43558
43058
  for (; ; ) {
43559
43059
  try {
43560
43060
  await mkdir23(lock);
@@ -44028,12 +43528,12 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
44028
43528
  if (!current || current.releaseId !== loadedRelease || current.status !== "pending")
44029
43529
  return false;
44030
43530
  const confirmed = [.../* @__PURE__ */ new Set([...current.confirmedProbeIds ?? [], probeId])].sort();
44031
- const required = current.requiredProbeIds ?? [probeId];
44032
- const satisfied = [...confirmed, ...current.unavailableProbeIds ?? []];
44033
43531
  await replaceUpdateAttempt(layout, {
44034
43532
  ...current,
44035
43533
  confirmedProbeIds: confirmed,
44036
- ...required.every((id) => satisfied.includes(id)) ? { status: "confirmed" } : {}
43534
+ // One verified successor is sufficient to validate the shared bundle.
43535
+ // A peer still running the old release cannot hold this journal pending.
43536
+ status: "confirmed"
44037
43537
  });
44038
43538
  return true;
44039
43539
  });
@@ -44180,7 +43680,7 @@ init_launchd();
44180
43680
  init_systemd();
44181
43681
  init_runtime();
44182
43682
  import { mkdir as mkdir24, rename as rename8 } from "node:fs/promises";
44183
- import { dirname as dirname22, resolve as resolve34 } from "node:path";
43683
+ import { dirname as dirname21, resolve as resolve34 } from "node:path";
44184
43684
  async function retireRemovedAgent(runtime, options = {}) {
44185
43685
  const deletedRoot = resolve34(runtime.supervisorRoot, "beeline", "deleted-runtimes");
44186
43686
  const target = resolve34(deletedRoot, `${runtime.agent.publicKey}-${Date.now()}`);
@@ -44203,13 +43703,13 @@ async function relocateAgentRuntime(runtime, target, options = {}) {
44203
43703
  ...options.run ? { run: options.run } : {}
44204
43704
  });
44205
43705
  }
44206
- await mkdir24(dirname22(destination), { recursive: true, mode: 448 });
43706
+ await mkdir24(dirname21(destination), { recursive: true, mode: 448 });
44207
43707
  await rename8(source, destination);
44208
43708
  return destination;
44209
43709
  }
44210
43710
 
44211
43711
  // apps/body/dist/start-command.js
44212
- import { basename as basename6, dirname as dirname23 } from "node:path";
43712
+ import { basename as basename6, dirname as dirname22 } from "node:path";
44213
43713
  var import_picocolors2 = __toESM(require_picocolors(), 1);
44214
43714
  init_agent_command();
44215
43715
  init_runtime();
@@ -44424,7 +43924,7 @@ async function startStoredRuntime(configPath, opts = {}, dependencyOverrides = {
44424
43924
  return { status: "started", pid };
44425
43925
  }
44426
43926
  function agentStartId(configPath) {
44427
- return basename6(dirname23(configPath));
43927
+ return basename6(dirname22(configPath));
44428
43928
  }
44429
43929
  async function startRuntime(configPath, spinnerHandle) {
44430
43930
  const report = (text2) => spinnerHandle ? spinnerHandle.message(text2) : console.log(text2);
@@ -44505,7 +44005,7 @@ async function runStartCommand(args, interactiveUi, dependencyOverrides = {}) {
44505
44005
  for (const path of unique) {
44506
44006
  const id = agentStartId(path);
44507
44007
  const spinnerHandle = interactiveUi ? spinner() : void 0;
44508
- spinnerHandle?.start(`Starting ${dirname23(path)}\u2026`);
44008
+ spinnerHandle?.start(`Starting ${dirname22(path)}\u2026`);
44509
44009
  try {
44510
44010
  const outcome = await deps.startOne(path, spinnerHandle);
44511
44011
  const report = { id, path, ...outcome };
@@ -44538,10 +44038,10 @@ async function runStartCommand(args, interactiveUi, dependencyOverrides = {}) {
44538
44038
 
44539
44039
  // apps/body/dist/connect-command.js
44540
44040
  import { spawn as spawn12 } from "node:child_process";
44541
- import { createHash as createHash13, randomUUID as randomUUID9 } from "node:crypto";
44542
- import { chmod as chmod8, mkdir as mkdir25, readFile as readFile21, unlink as unlink7, writeFile as writeFile18 } from "node:fs/promises";
44041
+ import { createHash as createHash12, randomUUID as randomUUID10 } from "node:crypto";
44042
+ import { chmod as chmod8, mkdir as mkdir25, readFile as readFile22, unlink as unlink7, writeFile as writeFile18 } from "node:fs/promises";
44543
44043
  import { homedir as homedir17, hostname as hostname3 } from "node:os";
44544
- import { dirname as dirname24, resolve as resolve35 } from "node:path";
44044
+ import { dirname as dirname23, resolve as resolve35 } from "node:path";
44545
44045
  import { stdin as stdin3, stdout as stdout4 } from "node:process";
44546
44046
  init_access_policy();
44547
44047
  init_agent_command();
@@ -45213,18 +44713,18 @@ async function readMachineId(env = process.env) {
45213
44713
  let machineId;
45214
44714
  let machineName = hostname3();
45215
44715
  try {
45216
- const existing = await readFile21(machineIdPath, "utf8");
44716
+ const existing = await readFile22(machineIdPath, "utf8");
45217
44717
  machineId = existing.trim();
45218
44718
  if (!/^[0-9a-f-]{32,}$/.test(machineId))
45219
44719
  throw new Error("invalid persisted machine id");
45220
44720
  } catch {
45221
- machineId = randomUUID9();
44721
+ machineId = randomUUID10();
45222
44722
  try {
45223
44723
  await mkdir25(configDir, { recursive: true, mode: 448 });
45224
44724
  await writeFile18(machineIdPath, `${machineId}
45225
44725
  `, { mode: 384 });
45226
44726
  } catch {
45227
- machineId = createHash13("sha256").update(machineName).digest("hex").slice(0, 36);
44727
+ machineId = createHash12("sha256").update(machineName).digest("hex").slice(0, 36);
45228
44728
  }
45229
44729
  }
45230
44730
  return { machineId, machineName };
@@ -45233,7 +44733,7 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, machine
45233
44733
  const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
45234
44734
  if (!normalizedPairingCode)
45235
44735
  throw new Error("invalid pairing code");
45236
- const avatarSeed = createHash13("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
44736
+ const avatarSeed = createHash12("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
45237
44737
  return jsonRequest(`${baseUrl}/auth/agent/connect`, {
45238
44738
  pairing_code: normalizedPairingCode,
45239
44739
  harness: selection.harness,
@@ -45305,7 +44805,7 @@ function providerEnvironment(selection) {
45305
44805
  };
45306
44806
  }
45307
44807
  async function writePrivateJson(path, value) {
45308
- await mkdir25(dirname24(path), { recursive: true, mode: 448 });
44808
+ await mkdir25(dirname23(path), { recursive: true, mode: 448 });
45309
44809
  await writeFile18(path, `${JSON.stringify(value, null, 2)}
45310
44810
  `, { mode: 384 });
45311
44811
  await chmod8(path, 384);
@@ -45315,7 +44815,7 @@ async function writeProviderEnv(selection, agentPubkey) {
45315
44815
  if (Object.keys(values).length === 0)
45316
44816
  return void 0;
45317
44817
  const path = resolve35(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
45318
- await mkdir25(dirname24(path), { recursive: true, mode: 448 });
44818
+ await mkdir25(dirname23(path), { recursive: true, mode: 448 });
45319
44819
  const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
45320
44820
  await writeFile18(path, `${contents}
45321
44821
  `, { mode: 384 });
@@ -45469,18 +44969,18 @@ async function runConnectFinishCommand(path) {
45469
44969
  throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
45470
44970
  }
45471
44971
  try {
45472
- const grant = JSON.parse(await readFile21(resolve35(path), "utf8"));
44972
+ const grant = JSON.parse(await readFile22(resolve35(path), "utf8"));
45473
44973
  if (!isDevicePairingGrant(grant))
45474
44974
  throw new Error("device connection grant is invalid");
45475
44975
  const connected = await completeDevicePairing(grant);
45476
44976
  await unlink7(resolve35(path));
45477
- const providerEnv = grant.llmEnvFile ? await readFile21(grant.llmEnvFile, "utf8").catch(() => "") : "";
44977
+ const providerEnv = grant.llmEnvFile ? await readFile22(grant.llmEnvFile, "utf8").catch(() => "") : "";
45478
44978
  const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
45479
44979
  const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
45480
44980
  if (model) {
45481
44981
  const decision2 = await resolveOpenRouterRouting({
45482
44982
  model,
45483
- cacheDir: openRouterRoutingCacheDir(dirname24(connected.configPath)),
44983
+ cacheDir: openRouterRoutingCacheDir(dirname23(connected.configPath)),
45484
44984
  ...apiKey ? { apiKey } : {},
45485
44985
  probeTimeoutMs: 1e4
45486
44986
  });
@@ -45498,8 +44998,8 @@ async function runConnectFinishCommand(path) {
45498
44998
  init_self_update();
45499
44999
 
45500
45000
  // apps/body/dist/daemon-failure.js
45501
- import { mkdir as mkdir26, readFile as readFile22, rename as rename9, rm as rm12, writeFile as writeFile19 } from "node:fs/promises";
45502
- import { dirname as dirname25, resolve as resolve36 } from "node:path";
45001
+ import { mkdir as mkdir26, readFile as readFile23, rename as rename9, rm as rm12, writeFile as writeFile19 } from "node:fs/promises";
45002
+ import { dirname as dirname24, resolve as resolve36 } from "node:path";
45503
45003
  var DAEMON_FAILURE_LIMIT = 3;
45504
45004
  var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
45505
45005
  function daemonFailurePath(runtimeDir) {
@@ -45507,8 +45007,8 @@ function daemonFailurePath(runtimeDir) {
45507
45007
  }
45508
45008
  async function readFailureRecord(runtimeDir) {
45509
45009
  try {
45510
- const value = JSON.parse(await readFile22(daemonFailurePath(runtimeDir), "utf8"));
45511
- if (value.version !== 1 || !Array.isArray(value.failures) || value.failures.some((failure2) => typeof failure2 !== "number") || typeof value.lastError !== "string") {
45010
+ const value = JSON.parse(await readFile23(daemonFailurePath(runtimeDir), "utf8"));
45011
+ if (value.version !== 1 || !Array.isArray(value.failures) || value.failures.some((failure) => typeof failure !== "number") || typeof value.lastError !== "string") {
45512
45012
  return void 0;
45513
45013
  }
45514
45014
  return value;
@@ -45519,14 +45019,14 @@ async function readFailureRecord(runtimeDir) {
45519
45019
  async function writeFailureRecord(runtimeDir, record6) {
45520
45020
  const path = daemonFailurePath(runtimeDir);
45521
45021
  const staged = `${path}.${process.pid}.tmp`;
45522
- await mkdir26(dirname25(path), { recursive: true, mode: 448 });
45022
+ await mkdir26(dirname24(path), { recursive: true, mode: 448 });
45523
45023
  await writeFile19(staged, `${JSON.stringify(record6, null, 2)}
45524
45024
  `, { mode: 384 });
45525
45025
  await rename9(staged, path);
45526
45026
  }
45527
45027
  async function recordDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
45528
45028
  const prior = await readFailureRecord(runtimeDir);
45529
- const failures = [...prior?.failures ?? [], now2].filter((failure2) => now2 - failure2 <= DAEMON_FAILURE_WINDOW_MS);
45029
+ const failures = [...prior?.failures ?? [], now2].filter((failure) => now2 - failure <= DAEMON_FAILURE_WINDOW_MS);
45530
45030
  const distressed = failures.length >= DAEMON_FAILURE_LIMIT;
45531
45031
  const record6 = {
45532
45032
  version: 1,
@@ -45546,7 +45046,7 @@ init_systemd();
45546
45046
 
45547
45047
  // apps/body/dist/current-release-probe.js
45548
45048
  import { spawn as spawn13 } from "node:child_process";
45549
- import { dirname as dirname26, join as join16 } from "node:path";
45049
+ import { dirname as dirname25, join as join16 } from "node:path";
45550
45050
  init_runtime();
45551
45051
  init_self_update();
45552
45052
  var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
@@ -45653,7 +45153,7 @@ async function runUpdateProbeCommand(args, options = {}) {
45653
45153
  const runtime = await readRuntimeRecord(configPath);
45654
45154
  const agent = runtimeAgentCommand(runtime);
45655
45155
  const config = loadBodyConfig({
45656
- workspaceRoot: join16(dirname26(configPath), "workspace"),
45156
+ workspaceRoot: join16(dirname25(configPath), "workspace"),
45657
45157
  llmEnvFile: runtime.llmEnvFile,
45658
45158
  env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
45659
45159
  agent
@@ -45671,7 +45171,7 @@ async function runUpdateProbeCommand(args, options = {}) {
45671
45171
  }
45672
45172
  const layout = beelineInstallLayout(env);
45673
45173
  const releaseId = (layout && await activeReleaseId(layout).catch(() => void 0)) ?? "unknown";
45674
- const runtimeDir = dirname26(configPath);
45174
+ const runtimeDir = dirname25(configPath);
45675
45175
  const outcome = await probeOutcome(() => (options.probe ?? runUpdateFunctionalProbe)({
45676
45176
  config,
45677
45177
  runtimeDir,
@@ -45686,7 +45186,7 @@ async function runUpdateProbeCommand(args, options = {}) {
45686
45186
  }
45687
45187
 
45688
45188
  // apps/body/dist/release-status.js
45689
- import { readFile as readFile23, readdir as readdir9, rename as rename10, writeFile as writeFile20 } from "node:fs/promises";
45189
+ import { readFile as readFile24, readdir as readdir9, rename as rename10, writeFile as writeFile20 } from "node:fs/promises";
45690
45190
  import { resolve as resolve37 } from "node:path";
45691
45191
  var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
45692
45192
  var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
@@ -45842,7 +45342,7 @@ var DaemonExitError = class extends Error {
45842
45342
  };
45843
45343
  async function runStoredDaemon(pathOrPointer) {
45844
45344
  const configPath = await resolveRuntimeConfigPath(pathOrPointer);
45845
- daemonFailureRuntimeDir = dirname27(configPath);
45345
+ daemonFailureRuntimeDir = dirname26(configPath);
45846
45346
  const accessMigration = await migrateRuntimeRecordAccessPolicy(configPath);
45847
45347
  let runtime = accessMigration.runtime;
45848
45348
  if (!runtime.transport) {
@@ -45876,7 +45376,7 @@ async function runStoredDaemon(pathOrPointer) {
45876
45376
  BUZZ_DEV_MCP_BIN: runtime.mcpBinary
45877
45377
  };
45878
45378
  const config = loadBodyConfig({
45879
- workspaceRoot: resolve39(dirname27(configPath), "workspace"),
45379
+ workspaceRoot: resolve39(dirname26(configPath), "workspace"),
45880
45380
  llmEnvFile: runtime.llmEnvFile,
45881
45381
  env,
45882
45382
  agent
@@ -45903,7 +45403,7 @@ async function runStoredDaemon(pathOrPointer) {
45903
45403
  config.runtimeConfigPath = configPath;
45904
45404
  const sandbox = await ensureBwrapSandbox({
45905
45405
  ...runtime.sandbox ? { policy: runtime.sandbox } : {},
45906
- stateDir: dirname27(configPath),
45406
+ stateDir: dirname26(configPath),
45907
45407
  beforeInstall: () => extendSystemdStartTimeout(BUBBLEWRAP_INSTALL_BUDGET_MS)
45908
45408
  });
45909
45409
  if (sandbox.path)
@@ -45914,10 +45414,8 @@ async function runStoredDaemon(pathOrPointer) {
45914
45414
  config.sandboxMaskPaths = [...config.sandboxMaskPaths ?? [], ...runtime.sandboxMaskPaths];
45915
45415
  }
45916
45416
  const controller = new AbortController();
45917
- const stop = () => controller.abort();
45918
- process.once("SIGINT", stop);
45919
- process.once("SIGTERM", stop);
45920
- const runtimeDir = dirname27(configPath);
45417
+ const disposeStopSignals = installDaemonStopSignals(controller);
45418
+ const runtimeDir = dirname26(configPath);
45921
45419
  const layout = beelineInstallLayout(process.env);
45922
45420
  const notifier = new SystemdNotifier();
45923
45421
  let rollbackAlertDrain;
@@ -46259,6 +45757,7 @@ async function runStoredDaemon(pathOrPointer) {
46259
45757
  institutionalMemoryWorker?.stop();
46260
45758
  await notifier.stopping(stoppingStatus).catch(() => void 0);
46261
45759
  await clearDaemonPidRecordIfPid(configPath, process.pid);
45760
+ disposeStopSignals();
46262
45761
  }
46263
45762
  }
46264
45763
  async function main() {
@@ -46282,7 +45781,7 @@ async function main() {
46282
45781
  if (process.env.BEELINE_SQUIRE_RELAY_URL)
46283
45782
  runSquireTaskProxy();
46284
45783
  else
46285
- runSquireFacade();
45784
+ await runSquireFacade();
46286
45785
  return;
46287
45786
  }
46288
45787
  if (command === SQUIRE_BROKER_FLAG) {
@@ -46363,7 +45862,7 @@ async function main() {
46363
45862
  }
46364
45863
  if (!configPath && agentPubkey) {
46365
45864
  const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
46366
- configPath = configs.find((candidate) => dirname27(candidate).endsWith(agentPubkey));
45865
+ configPath = configs.find((candidate) => dirname26(candidate).endsWith(agentPubkey));
46367
45866
  }
46368
45867
  if (!configPath && agentPubkey) {
46369
45868
  throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing service restart loop`, UNKNOWN_AGENT_EXIT_STATUS);
@@ -46391,7 +45890,7 @@ async function main() {
46391
45890
  if (!agentPubkey)
46392
45891
  throw new Error("stop requires --agent <pubkey>");
46393
45892
  const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
46394
- const configPath = configs.find((candidate) => dirname27(candidate).endsWith(agentPubkey));
45893
+ const configPath = configs.find((candidate) => dirname26(candidate).endsWith(agentPubkey));
46395
45894
  if (!configPath)
46396
45895
  throw new Error(`no stored runtime found for agent ${agentPubkey}`);
46397
45896
  const runtime = await readRuntimeRecord(configPath);
@@ -46425,10 +45924,10 @@ main().catch(async (err) => {
46425
45924
  let exitStatus = err instanceof DaemonExitError ? err.exitStatus : 1;
46426
45925
  if (process.argv[2] === "daemon" && daemonFailureRuntimeDir && exitStatus === 1) {
46427
45926
  try {
46428
- const failure2 = await recordDaemonStartFailure(daemonFailureRuntimeDir, err);
46429
- if (failure2.distressed) {
45927
+ const failure = await recordDaemonStartFailure(daemonFailureRuntimeDir, err);
45928
+ if (failure.distressed) {
46430
45929
  exitStatus = DAEMON_DISTRESS_EXIT_STATUS;
46431
- console.error(`[thin-core] daemon start failed ${failure2.count} times; service restart stopped. operator record: ${failure2.path}`);
45930
+ console.error(`[thin-core] daemon start failed ${failure.count} times; service restart stopped. operator record: ${failure.path}`);
46432
45931
  }
46433
45932
  } catch (recordError) {
46434
45933
  console.error("[thin-core] could not persist daemon distress record:", recordError);