usebeeline 0.0.48 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -148,7 +148,7 @@ Two MCP surfaces are mounted into every agent session.
148
148
  Beeline is on both stores:
149
149
 
150
150
  - [App Store](https://apps.apple.com/app/id6803948500)
151
- - [Google Play](https://play.google.com/store/apps/details?id=app.usebeeline.mobile)
151
+ - [Google Play](https://play.google.com/store/apps/details?id=app.usebeeline)
152
152
 
153
153
  Sign in with GitHub, and the app hands you the pairing code that `npx usebeeline connect` asks for.
154
154
 
@@ -309,12 +309,12 @@ __export(self_update_exports, {
309
309
  });
310
310
  import { createHash as createHash5 } from "node:crypto";
311
311
  import { constants as fsConstants } from "node:fs";
312
- import { access, chmod as chmod3, lstat as lstat2, mkdir as mkdir11, open, readFile as readFile9, rename as rename3, rm as rm5, symlink as symlink2, writeFile as writeFile8 } from "node:fs/promises";
312
+ import { access, chmod as chmod4, lstat as lstat2, mkdir as mkdir13, open, readFile as readFile9, rename as rename3, rm as rm5, symlink as symlink2, writeFile as writeFile9 } from "node:fs/promises";
313
313
  import { spawn as spawn4 } from "node:child_process";
314
314
  import { homedir as homedir9 } from "node:os";
315
- import { dirname as dirname9, join as join7, resolve as resolve19 } from "node:path";
315
+ import { dirname as dirname9, join as join7, resolve as resolve21 } from "node:path";
316
316
  function anchorLayout(rawLibDir) {
317
- const libDir = resolve19(rawLibDir);
317
+ const libDir = resolve21(rawLibDir);
318
318
  const segments = libDir.split(/[/\\]/);
319
319
  const idx = segments.lastIndexOf(RELEASES_SEGMENT);
320
320
  if (idx >= 2 && segments[idx - 1] === "lib") {
@@ -330,9 +330,9 @@ function anchorLayout(rawLibDir) {
330
330
  // prefix's bin, NOT <prefix>/lib/bin — deriving it one level up was the
331
331
  // defect that made activateRelease write its stable forwarders where
332
332
  // nothing executed them, leaving stale raw wrappers in <prefix>/bin.
333
- binDir: resolve19(libDir, "../../bin"),
333
+ binDir: resolve21(libDir, "../../bin"),
334
334
  libDir,
335
- releasesRoot: resolve19(libDir, `../${RELEASES_SEGMENT}`)
335
+ releasesRoot: resolve21(libDir, `../${RELEASES_SEGMENT}`)
336
336
  };
337
337
  }
338
338
  function beelineInstallLayout(env = process.env) {
@@ -343,7 +343,7 @@ function beelineInstallLayout(env = process.env) {
343
343
  }
344
344
  function defaultBeelineInstallLayout(env = process.env) {
345
345
  const home = env.HOME?.trim() || homedir9();
346
- return anchorLayout(resolve19(home, ".local", "lib", "beeline"));
346
+ return anchorLayout(resolve21(home, ".local", "lib", "beeline"));
347
347
  }
348
348
  function hostPlatformKey() {
349
349
  const os = process.platform === "linux" ? "linux" : process.platform === "darwin" ? "darwin" : "";
@@ -387,8 +387,8 @@ async function readUpdateState(layout) {
387
387
  }
388
388
  }
389
389
  async function writeUpdateState(layout, state) {
390
- await mkdir11(join7(layout.releasesRoot, ".state"), { recursive: true });
391
- await writeFile8(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
390
+ await mkdir13(join7(layout.releasesRoot, ".state"), { recursive: true });
391
+ await writeFile9(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
392
392
  `, "utf8");
393
393
  }
394
394
  async function readInstalledBundleIdentity(layout, _state = {}) {
@@ -501,7 +501,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
501
501
  previouslyVerified = true;
502
502
  } catch {
503
503
  }
504
- await mkdir11(releaseDir, { recursive: true });
504
+ await mkdir13(releaseDir, { recursive: true });
505
505
  const tempArchive = join7(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
506
506
  try {
507
507
  log2(`downloading ${published.file}`);
@@ -522,7 +522,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
522
522
  if (actual !== published.sha256.toLowerCase()) {
523
523
  throw new Error(`checksum mismatch for ${published.file}: expected ${published.sha256}, got ${actual} \u2014 aborting without touching the installed bundle`);
524
524
  }
525
- await writeFile8(tempArchive, Buffer.concat(chunks), { mode: 384 });
525
+ await writeFile9(tempArchive, Buffer.concat(chunks), { mode: 384 });
526
526
  const entries = (await new Promise((resolveList, rejectList) => {
527
527
  const child = spawn4("tar", ["-tzf", tempArchive], { stdio: ["ignore", "pipe", "inherit"] });
528
528
  let out = "";
@@ -553,7 +553,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
553
553
  throw new Error(`staged bundle failed its startup smoke test (--version exited ${probe.status})${probe.stderr ? `: ${probe.stderr.trim()}` : ""}`);
554
554
  }
555
555
  }
556
- await writeFile8(okMarker, `${published.sha256}
556
+ await writeFile9(okMarker, `${published.sha256}
557
557
  `, "utf8");
558
558
  log2(`staged release ${releaseId} (sha256 verified)`);
559
559
  return releaseId;
@@ -581,15 +581,15 @@ function forwarderScript(tool) {
581
581
  }
582
582
  async function replaceFile(path, contents, mode) {
583
583
  const temp = `${path}.new-${process.pid}`;
584
- await writeFile8(temp, contents, { mode });
585
- await chmod3(temp, mode);
584
+ await writeFile9(temp, contents, { mode });
585
+ await chmod4(temp, mode);
586
586
  await rename3(temp, path);
587
587
  }
588
588
  async function activateRelease(layout, releaseId) {
589
589
  const releaseDir = join7(layout.releasesRoot, releaseId);
590
590
  await access(join7(releaseDir, BUNDLE_ENTRYPOINT), fsConstants.F_OK);
591
- await mkdir11(layout.releasesRoot, { recursive: true });
592
- await mkdir11(layout.binDir, { recursive: true });
591
+ await mkdir13(layout.releasesRoot, { recursive: true });
592
+ await mkdir13(layout.binDir, { recursive: true });
593
593
  let previousReleaseId = await activeReleaseId(layout);
594
594
  const kind = await pathKind(layout.libDir);
595
595
  if (kind === "directory") {
@@ -628,7 +628,7 @@ async function normalizeLegacyBundleShape(bundleDir) {
628
628
  }
629
629
  if (!anyFlat)
630
630
  return;
631
- await mkdir11(innerLib, { recursive: true });
631
+ await mkdir13(innerLib, { recursive: true });
632
632
  for (const name of LEGACY_FLAT_BUNDLE_FILES) {
633
633
  try {
634
634
  await access(join7(innerLib, name), fsConstants.F_OK);
@@ -661,7 +661,7 @@ async function repairInstallForwarders(layout, opts = {}) {
661
661
  }
662
662
  if (current === forwarderScript("beeline"))
663
663
  return false;
664
- await mkdir11(layout.binDir, { recursive: true });
664
+ await mkdir13(layout.binDir, { recursive: true });
665
665
  await writeBinForwarders(layout, layout.libDir);
666
666
  opts.logger?.(`[body] self-update: repaired <prefix>/bin forwarders to follow the active-bundle anchor (${layout.libDir})`);
667
667
  return true;
@@ -693,10 +693,10 @@ async function readUpdateAttempt(layout) {
693
693
  }
694
694
  }
695
695
  async function writeUpdateAttempt(layout, record2) {
696
- await mkdir11(join7(layout.releasesRoot, ".state"), { recursive: true });
696
+ await mkdir13(join7(layout.releasesRoot, ".state"), { recursive: true });
697
697
  const path = updateAttemptPath(layout);
698
698
  const staged = `${path}.${process.pid}.tmp`;
699
- await writeFile8(staged, `${JSON.stringify(record2, null, 2)}
699
+ await writeFile9(staged, `${JSON.stringify(record2, null, 2)}
700
700
  `, { mode: 384 });
701
701
  await rename3(staged, path);
702
702
  }
@@ -955,8 +955,8 @@ var init_self_update = __esm({
955
955
  });
956
956
 
957
957
  // apps/body/dist/cli.js
958
- import { dirname as dirname15, resolve as resolve26 } from "node:path";
959
- import { readFile as readFile14, unlink as unlink3, writeFile as writeFile14 } from "node:fs/promises";
958
+ import { dirname as dirname15, resolve as resolve28 } from "node:path";
959
+ import { readFile as readFile14, unlink as unlink3, writeFile as writeFile15 } from "node:fs/promises";
960
960
  import { stdin as stdin4, stdout as stdout5 } from "node:process";
961
961
 
962
962
  // node_modules/@clack/core/dist/index.mjs
@@ -3832,7 +3832,7 @@ var AcpClient = class extends EventEmitter {
3832
3832
  const current = this.activeRunIds.get(sessionId);
3833
3833
  if (current)
3834
3834
  return Promise.resolve(current);
3835
- return new Promise((resolve27, reject) => {
3835
+ return new Promise((resolve29, reject) => {
3836
3836
  const onUpdate = (update) => {
3837
3837
  if (update.sessionId !== sessionId)
3838
3838
  return;
@@ -3840,7 +3840,7 @@ var AcpClient = class extends EventEmitter {
3840
3840
  if (!runId)
3841
3841
  return;
3842
3842
  cleanup();
3843
- resolve27(runId);
3843
+ resolve29(runId);
3844
3844
  };
3845
3845
  const timer = setTimeout(() => {
3846
3846
  cleanup();
@@ -3924,13 +3924,13 @@ var AcpClient = class extends EventEmitter {
3924
3924
  }
3925
3925
  const id = this.nextId++;
3926
3926
  const payload = { jsonrpc: "2.0", id, method, params };
3927
- return new Promise((resolve27, reject) => {
3927
+ return new Promise((resolve29, reject) => {
3928
3928
  const timer = setTimeout(() => {
3929
3929
  this.pending.delete(id);
3930
3930
  reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart), detail));
3931
3931
  }, timeoutMs);
3932
3932
  this.pending.set(id, {
3933
- resolve: resolve27,
3933
+ resolve: resolve29,
3934
3934
  reject,
3935
3935
  timer,
3936
3936
  method,
@@ -13283,8 +13283,8 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
13283
13283
  import { execFile as execFile4 } from "node:child_process";
13284
13284
  import { createHash as createHash4 } from "node:crypto";
13285
13285
  import { existsSync as existsSync4, mkdirSync } from "node:fs";
13286
- import { mkdir as mkdir9, rm as rm4 } from "node:fs/promises";
13287
- import { dirname as dirname6, resolve as resolve17 } from "node:path";
13286
+ import { mkdir as mkdir11, rm as rm4 } from "node:fs/promises";
13287
+ import { dirname as dirname6, resolve as resolve19 } from "node:path";
13288
13288
  import { promisify as promisify3 } from "node:util";
13289
13289
 
13290
13290
  // apps/body/dist/grant-runner.js
@@ -14126,7 +14126,7 @@ var GrantRunnerServer = class {
14126
14126
 
14127
14127
  // apps/body/dist/monolith-corner-turn.js
14128
14128
  import { execFile as execFile3 } from "node:child_process";
14129
- import { mkdir as mkdir7 } from "node:fs/promises";
14129
+ import { mkdir as mkdir9 } from "node:fs/promises";
14130
14130
  import { homedir as homedir6 } from "node:os";
14131
14131
  import { join as join5 } from "node:path";
14132
14132
  import { promisify as promisify2 } from "node:util";
@@ -14151,6 +14151,8 @@ var BEELINE_ROOM_CAPABILITIES = [
14151
14151
  "Files and photos people share are downloaded for you: read them at the local path named in the prompt (photos may also arrive inline); never fetch the reference URL.",
14152
14152
  "To create a file (this Room has no other way to write one), call beeline-agent write_scratch_file with a relative path and content - text by default, or base64 for bytes you computed; it returns a path in your writable session home. To send a file, call beeline-agent attach_file with a path inside your checkout or anywhere in your writable session home (wherever a file you or your harness generated actually landed, including one you just wrote); it is attached to your reply. write_scratch_file produces the file, not a picture - turning it into a raster image needs a converter, which needs shell, which this Room does not have.",
14153
14153
  "To run something later or repeatedly, call beeline-agent create_schedule (interval in minutes or a 5-field cron, optional maxRuns); list_schedules / delete_schedule manage them.",
14154
+ "To react to things that HAPPEN in this Room rather than only to what is said to you, call beeline-agent subscribe_events with the kinds you want (joined, schedule-ran, corner-opened, check-passed, check-failed, merged); each one then wakes you for a turn. It replaces your list, so send every kind you want - list_event_subscriptions shows the current one. You do this yourself: nobody has to configure it for you.",
14155
+ "To state something that happened so the Room and other agents can act on it, call beeline-agent emit_event with your own agent:<slug> kind, one sentence, and optionally the agent members to wake. Chains of events are bounded and a refused emit posts nothing.",
14154
14156
  "When repository work is needed, you MUST call beeline-agent open_corner with a name of at most three words - it titles the corner everywhere - and a complete objective of no more than 24 words. The host-governed call is the only way to start write work.",
14155
14157
  "When open_corner succeeds, the server posts the corner card: do not announce or restate the opening. End the turn with nothing more unless the person asked something else.",
14156
14158
  "Never claim an action or reply happened unless the prompt or a tool result proves it."
@@ -15668,8 +15670,191 @@ function sessionConfigFingerprint(input) {
15668
15670
  ]);
15669
15671
  }
15670
15672
 
15671
- // apps/body/dist/room-session.js
15673
+ // apps/body/dist/pi-mcp-bridge.js
15674
+ import { mkdir as mkdir6 } from "node:fs/promises";
15672
15675
  import { resolve as resolve14 } from "node:path";
15676
+ var PI_MCP_BRIDGE_FILENAME = "beeline-mcp-bridge.js";
15677
+ function harnessMountsSessionMcpServers(agentCommand) {
15678
+ return !(agentCommand && /(^|[/\\])pi-acp(\.[a-z]+)?$/i.test(agentCommand));
15679
+ }
15680
+ function piMcpBridgeSource(servers) {
15681
+ const manifest = servers.map((server) => ({
15682
+ name: server.name,
15683
+ command: server.command,
15684
+ args: server.args ?? [],
15685
+ env: Object.fromEntries((server.env ?? []).map((entry) => [entry.name, entry.value]))
15686
+ }));
15687
+ return `${BRIDGE_PREAMBLE}const SERVERS = ${JSON.stringify(manifest, null, 2)};
15688
+ ${BRIDGE_BODY}`;
15689
+ }
15690
+ async function installPiMcpBridge(input) {
15691
+ if (harnessMountsSessionMcpServers(input.agentCommand))
15692
+ return void 0;
15693
+ if (!input.piHome || !input.servers.length)
15694
+ return void 0;
15695
+ const directory = resolve14(input.piHome, "extensions");
15696
+ const path = resolve14(directory, PI_MCP_BRIDGE_FILENAME);
15697
+ try {
15698
+ await mkdir6(directory, { recursive: true, mode: 448 });
15699
+ await writeIsolatedHarnessFile(path, piMcpBridgeSource(input.servers));
15700
+ return path;
15701
+ } catch (error) {
15702
+ console.error("[body] pi MCP bridge could not be written", path, error);
15703
+ return void 0;
15704
+ }
15705
+ }
15706
+ var BRIDGE_PREAMBLE = `// Generated by Beeline for one Room session. Do not edit: it is rewritten on
15707
+ // every activation. It republishes this session's MCP servers as pi tools,
15708
+ // because pi has no MCP client of its own (apps/body/src/pi-mcp-bridge.ts).
15709
+ import { spawn } from 'node:child_process';
15710
+
15711
+ `;
15712
+ var BRIDGE_BODY = `const LIST_TIMEOUT_MS = 20000;
15713
+
15714
+ /**
15715
+ * One request/response against one MCP server over a short-lived process.
15716
+ *
15717
+ * A fresh process per call keeps nothing alive between turns: these servers
15718
+ * hold no session state - each tool call is a bounded daemon HTTP request - so
15719
+ * a pool would buy latency at the cost of processes outliving the session that
15720
+ * spawned them.
15721
+ */
15722
+ function callServer(server, request, signal, timeoutMs) {
15723
+ return new Promise((resolvePromise, rejectPromise) => {
15724
+ const child = spawn(server.command, server.args, {
15725
+ env: { ...process.env, ...server.env },
15726
+ stdio: ['pipe', 'pipe', 'ignore'],
15727
+ });
15728
+ let settled = false;
15729
+ let buffer = '';
15730
+ let timer;
15731
+ const finish = (error, value) => {
15732
+ if (settled) return;
15733
+ settled = true;
15734
+ if (timer) clearTimeout(timer);
15735
+ signal?.removeEventListener?.('abort', onAbort);
15736
+ child.kill('SIGKILL');
15737
+ if (error) rejectPromise(error); else resolvePromise(value);
15738
+ };
15739
+ const onAbort = () => finish(new Error(server.name + ' call cancelled'));
15740
+ if (timeoutMs) {
15741
+ timer = setTimeout(
15742
+ () => finish(new Error(server.name + ' did not answer in ' + timeoutMs + 'ms')),
15743
+ timeoutMs,
15744
+ );
15745
+ }
15746
+ if (signal) {
15747
+ if (signal.aborted) { onAbort(); return; }
15748
+ signal.addEventListener?.('abort', onAbort, { once: true });
15749
+ }
15750
+ child.on('error', (error) => finish(error));
15751
+ child.on('exit', () => finish(new Error(server.name + ' exited before answering')));
15752
+ child.stdout.setEncoding('utf8');
15753
+ child.stdout.on('data', (chunk) => {
15754
+ buffer += chunk;
15755
+ let newline = buffer.indexOf('\\n');
15756
+ while (newline >= 0) {
15757
+ const line = buffer.slice(0, newline).trim();
15758
+ buffer = buffer.slice(newline + 1);
15759
+ if (line) {
15760
+ let message;
15761
+ try { message = JSON.parse(line); } catch { message = undefined; }
15762
+ // Only the answer to OUR id: the initialize reply and any
15763
+ // notification the server writes share this stream.
15764
+ if (message && message.id === request.id) {
15765
+ if (message.error) {
15766
+ finish(new Error(message.error.message || 'MCP error'));
15767
+ } else {
15768
+ finish(undefined, message.result ?? {});
15769
+ }
15770
+ return;
15771
+ }
15772
+ }
15773
+ newline = buffer.indexOf('\\n');
15774
+ }
15775
+ });
15776
+ child.stdin.write(
15777
+ JSON.stringify({
15778
+ jsonrpc: '2.0',
15779
+ id: 0,
15780
+ method: 'initialize',
15781
+ params: {
15782
+ protocolVersion: '2024-11-05',
15783
+ capabilities: {},
15784
+ clientInfo: { name: 'beeline-pi-bridge', version: '1.0.0' },
15785
+ },
15786
+ }) + '\\n',
15787
+ );
15788
+ child.stdin.write(JSON.stringify(request) + '\\n');
15789
+ });
15790
+ }
15791
+
15792
+ function textOf(result) {
15793
+ const content = Array.isArray(result?.content) ? result.content : [];
15794
+ const text = content
15795
+ .filter((part) => part && part.type === 'text' && typeof part.text === 'string')
15796
+ .map((part) => part.text)
15797
+ .join('\\n');
15798
+ return text || 'The tool returned no text.';
15799
+ }
15800
+
15801
+ function labelOf(name) {
15802
+ return name.replace(/_/g, ' ').replace(/^./, (first) => first.toUpperCase());
15803
+ }
15804
+
15805
+ export default async function (pi) {
15806
+ for (const server of SERVERS) {
15807
+ let tools = [];
15808
+ try {
15809
+ const listed = await callServer(
15810
+ server,
15811
+ { jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} },
15812
+ undefined,
15813
+ LIST_TIMEOUT_MS,
15814
+ );
15815
+ tools = Array.isArray(listed?.tools) ? listed.tools : [];
15816
+ } catch (error) {
15817
+ // A server that will not list is a server whose tools this session does
15818
+ // not have. Say so once; never fail the session over it.
15819
+ console.error('[beeline] MCP server ' + server.name + ' did not list its tools:', error);
15820
+ continue;
15821
+ }
15822
+ for (const tool of tools) {
15823
+ if (!tool || typeof tool.name !== 'string') continue;
15824
+ const schema =
15825
+ tool.inputSchema && typeof tool.inputSchema === 'object'
15826
+ ? tool.inputSchema
15827
+ : { type: 'object', properties: {} };
15828
+ pi.registerTool({
15829
+ name: server.name + '__' + tool.name,
15830
+ label: labelOf(tool.name),
15831
+ description: typeof tool.description === 'string' ? tool.description : tool.name,
15832
+ parameters: schema,
15833
+ async execute(_toolCallId, params, signal) {
15834
+ const result = await callServer(
15835
+ server,
15836
+ {
15837
+ jsonrpc: '2.0',
15838
+ id: 1,
15839
+ method: 'tools/call',
15840
+ params: { name: tool.name, arguments: params ?? {} },
15841
+ },
15842
+ signal,
15843
+ );
15844
+ // An MCP refusal is a RESULT carrying isError. Throwing is how a pi
15845
+ // tool reports failure, so the sentence explaining the refusal is
15846
+ // what the model reads.
15847
+ if (result?.isError) throw new Error(textOf(result));
15848
+ return { content: [{ type: 'text', text: textOf(result) }], details: {} };
15849
+ },
15850
+ });
15851
+ }
15852
+ }
15853
+ }
15854
+ `;
15855
+
15856
+ // apps/body/dist/room-session.js
15857
+ import { resolve as resolve15 } from "node:path";
15673
15858
 
15674
15859
  // apps/body/dist/read-only-policy.js
15675
15860
  var READ_ONLY_MCP_SERVER_NAME = "beeline-readonly-mcp";
@@ -15892,21 +16077,21 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
15892
16077
  command: config.readonlyMcpCommand,
15893
16078
  args: [...config.readonlyMcpArgs ?? []],
15894
16079
  env: [
15895
- { name: "BEELINE_READONLY_ROOT", value: resolve14(cwd) },
16080
+ { name: "BEELINE_READONLY_ROOT", value: resolve15(cwd) },
15896
16081
  ...config.agentHomeRoot ? [
15897
16082
  {
15898
16083
  name: "BEELINE_READONLY_AGENT_SKILLS_ROOT",
15899
- value: resolve14(config.agentHomeRoot, skillDir, "skills")
16084
+ value: resolve15(config.agentHomeRoot, skillDir, "skills")
15900
16085
  }
15901
16086
  ] : [],
15902
- ...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value: resolve14(agentMemoryDir) }] : []
16087
+ ...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value: resolve15(agentMemoryDir) }] : []
15903
16088
  ]
15904
16089
  };
15905
16090
  }
15906
16091
 
15907
16092
  // apps/body/dist/pi-turn-record.js
15908
16093
  import { readdir as readdir3, readFile as readFile7 } from "node:fs/promises";
15909
- import { resolve as resolve15 } from "node:path";
16094
+ import { resolve as resolve16 } from "node:path";
15910
16095
  function summarizeProviderError(errorMessage2) {
15911
16096
  const trimmed = errorMessage2.trim();
15912
16097
  const statusMatch = /^(\d{3}):\s*([\s\S]*)$/.exec(trimmed);
@@ -15927,7 +16112,7 @@ function summarizeProviderError(errorMessage2) {
15927
16112
  }
15928
16113
  async function sessionFileFromMap(home, sessionId) {
15929
16114
  try {
15930
- const raw = await readFile7(resolve15(home, ".pi", "pi-acp", "session-map.json"), "utf8");
16115
+ const raw = await readFile7(resolve16(home, ".pi", "pi-acp", "session-map.json"), "utf8");
15931
16116
  const map = JSON.parse(raw);
15932
16117
  const file = map.sessions?.[sessionId]?.sessionFile;
15933
16118
  return typeof file === "string" && file ? file : void 0;
@@ -15936,7 +16121,7 @@ async function sessionFileFromMap(home, sessionId) {
15936
16121
  }
15937
16122
  }
15938
16123
  async function sessionFileFromLayout(piDir, sessionId) {
15939
- const sessionsRoot = resolve15(piDir, "sessions");
16124
+ const sessionsRoot = resolve16(piDir, "sessions");
15940
16125
  const suffix = `_${sessionId}.jsonl`;
15941
16126
  let projects;
15942
16127
  try {
@@ -15945,7 +16130,7 @@ async function sessionFileFromLayout(piDir, sessionId) {
15945
16130
  return void 0;
15946
16131
  }
15947
16132
  for (const project of projects) {
15948
- const dir = resolve15(sessionsRoot, project);
16133
+ const dir = resolve16(sessionsRoot, project);
15949
16134
  let files;
15950
16135
  try {
15951
16136
  files = await readdir3(dir);
@@ -15954,7 +16139,7 @@ async function sessionFileFromLayout(piDir, sessionId) {
15954
16139
  }
15955
16140
  const match = files.find((file) => file.endsWith(suffix));
15956
16141
  if (match)
15957
- return resolve15(dir, match);
16142
+ return resolve16(dir, match);
15958
16143
  }
15959
16144
  return void 0;
15960
16145
  }
@@ -16149,8 +16334,8 @@ async function withTurnReceiptHeartbeat(api, receipt, task, onHeartbeatError) {
16149
16334
  }
16150
16335
 
16151
16336
  // apps/body/dist/turn-trace.js
16152
- import { appendFile, mkdir as mkdir6, readdir as readdir4, rm as rm3 } from "node:fs/promises";
16153
- import { resolve as resolve16 } from "node:path";
16337
+ import { appendFile, mkdir as mkdir7, readdir as readdir4, rm as rm3 } from "node:fs/promises";
16338
+ import { resolve as resolve17 } from "node:path";
16154
16339
  import { performance as performance2 } from "node:perf_hooks";
16155
16340
  var TURN_PHASES = [
16156
16341
  /** Enqueued on `SessionScheduler` until this turn holds a slot. A capacity wait lives here. */
@@ -16380,7 +16565,7 @@ function formatTurnTraceLine(record2) {
16380
16565
  return [head, ...record2.attempts.map((attempt) => formatTurnAttempt(attempt))].join("\n ");
16381
16566
  }
16382
16567
  function turnTraceDirectory(runtimeDir) {
16383
- return resolve16(runtimeDir, "turn-traces");
16568
+ return resolve17(runtimeDir, "turn-traces");
16384
16569
  }
16385
16570
  var TURN_TRACE_RETENTION_DAYS = 7;
16386
16571
  function traceFileName(date) {
@@ -16397,13 +16582,13 @@ var TurnTraceFile = class {
16397
16582
  this.options = options;
16398
16583
  }
16399
16584
  path(now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))()) {
16400
- return resolve16(this.directory, traceFileName(now2));
16585
+ return resolve17(this.directory, traceFileName(now2));
16401
16586
  }
16402
16587
  write(record2) {
16403
16588
  this.tail = this.tail.catch(() => void 0).then(async () => {
16404
16589
  const now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))();
16405
16590
  const path = this.path(now2);
16406
- await mkdir6(this.directory, { recursive: true, mode: 448 });
16591
+ await mkdir7(this.directory, { recursive: true, mode: 448 });
16407
16592
  await appendFile(path, `${JSON.stringify(record2)}
16408
16593
  `, { mode: 384 });
16409
16594
  await this.prune(now2);
@@ -16421,10 +16606,61 @@ var TurnTraceFile = class {
16421
16606
  this.prunedDay = day;
16422
16607
  const cutoff = traceFileName(new Date(now2.getTime() - TURN_TRACE_RETENTION_DAYS * 864e5));
16423
16608
  const names = await readdir4(this.directory).catch(() => []);
16424
- await Promise.all(names.filter((name) => /^turns-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name) && name < cutoff).map((name) => rm3(resolve16(this.directory, name), { force: true })));
16609
+ await Promise.all(names.filter((name) => /^turns-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name) && name < cutoff).map((name) => rm3(resolve17(this.directory, name), { force: true })));
16425
16610
  }
16426
16611
  };
16427
16612
 
16613
+ // apps/body/dist/corner-github-auth.js
16614
+ import { chmod as chmod3, mkdir as mkdir8, writeFile as writeFile7 } from "node:fs/promises";
16615
+ import { delimiter as delimiter2, resolve as resolve18 } from "node:path";
16616
+ async function installCornerGitHubWrappers(input) {
16617
+ const bin = resolve18(input.root, "beeline-github-bin");
16618
+ await mkdir8(bin, { recursive: true, mode: 448 });
16619
+ const common = {
16620
+ node: process.execPath,
16621
+ cli: input.cliEntrypoint,
16622
+ config: input.runtimeConfigPath,
16623
+ room: input.roomId
16624
+ };
16625
+ await writeLauncher(resolve18(bin, "git"), { ...common, command: input.gitBinary });
16626
+ if (input.ghBinary)
16627
+ await writeLauncher(resolve18(bin, "gh"), { ...common, command: input.ghBinary });
16628
+ return {
16629
+ PATH: [bin, input.inheritedPath].filter(Boolean).join(delimiter2),
16630
+ // Static startup tokens take precedence over the refreshed token in gh.
16631
+ GH_TOKEN: "",
16632
+ GITHUB_TOKEN: ""
16633
+ };
16634
+ }
16635
+ async function writeLauncher(path, config) {
16636
+ const source = `#!/usr/bin/env node
16637
+ import { spawnSync } from 'node:child_process';
16638
+ const config = ${JSON.stringify(config)};
16639
+ const authFailure = /(?:authentication failed|bad credentials|could not read username|http(?:\\/\\d(?:\\.\\d)?)? 40[13]|status (?:code )?40[13])/i;
16640
+ function token() {
16641
+ const result = spawnSync(config.node, [config.cli, 'corner-read-token', '--config', config.config, '--room', config.room], { encoding: 'utf8' });
16642
+ if (result.status !== 0) {
16643
+ process.stderr.write(result.stderr || 'Beeline could not refresh the repository credential.\\n');
16644
+ process.exit(result.status || 1);
16645
+ }
16646
+ return result.stdout.trim();
16647
+ }
16648
+ function run(value) {
16649
+ const env = { ...process.env, GH_TOKEN: value, GITHUB_TOKEN: value, GIT_TERMINAL_PROMPT: '0' };
16650
+ return spawnSync(config.command, process.argv.slice(2), { env, encoding: 'buffer', stdio: ['inherit', 'pipe', 'pipe'] });
16651
+ }
16652
+ let result = run(token());
16653
+ const diagnostic = Buffer.concat([result.stdout || Buffer.alloc(0), result.stderr || Buffer.alloc(0)]).toString('utf8');
16654
+ if (result.status !== 0 && authFailure.test(diagnostic)) result = run(token());
16655
+ if (result.stdout) process.stdout.write(result.stdout);
16656
+ if (result.stderr) process.stderr.write(result.stderr);
16657
+ if (result.error) throw result.error;
16658
+ process.exit(result.status ?? 1);
16659
+ `;
16660
+ await writeFile7(path, source, { mode: 448 });
16661
+ await chmod3(path, 448);
16662
+ }
16663
+
16428
16664
  // apps/body/dist/monolith-corner-turn.js
16429
16665
  var execFileAsync2 = promisify2(execFile3);
16430
16666
  var TOOL_ARGUMENT_MAX_BYTES = 1200;
@@ -16681,7 +16917,7 @@ var MonolithCornerTurnLoop = class {
16681
16917
  soul: configuration.soul ?? self?.soul,
16682
16918
  agentName: self?.name ?? this.agent.name
16683
16919
  });
16684
- await mkdir7(this.options.worktreePath, { recursive: true });
16920
+ await mkdir9(this.options.worktreePath, { recursive: true });
16685
16921
  const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
16686
16922
  const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
16687
16923
  root: this.options.config.agentHomeRoot,
@@ -16698,11 +16934,27 @@ var MonolithCornerTurnLoop = class {
16698
16934
  })
16699
16935
  }) : {};
16700
16936
  const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
16937
+ let githubEnv = {
16938
+ GH_TOKEN: this.options.githubToken,
16939
+ GITHUB_TOKEN: this.options.githubToken
16940
+ };
16941
+ if (this.options.config.runtimeConfigPath && this.options.config.agentHomeRoot) {
16942
+ const gitBinary = (await execFileAsync2("which", ["git"])).stdout.trim();
16943
+ const ghBinary = await execFileAsync2("which", ["gh"]).then((result) => result.stdout.trim()).catch(() => void 0);
16944
+ githubEnv = await installCornerGitHubWrappers({
16945
+ root: this.options.config.agentHomeRoot,
16946
+ runtimeConfigPath: this.options.config.runtimeConfigPath,
16947
+ roomId: this.options.parentRoomId,
16948
+ cliEntrypoint: process.argv[1],
16949
+ gitBinary,
16950
+ ...ghBinary ? { ghBinary } : {},
16951
+ inheritedPath: this.options.config.agentEnv.PATH ?? process.env.PATH
16952
+ });
16953
+ }
16701
16954
  const agentEnv = {
16702
16955
  ...this.options.config.agentEnv,
16703
16956
  ...homeOverlay,
16704
- GH_TOKEN: this.options.githubToken,
16705
- GITHUB_TOKEN: this.options.githubToken
16957
+ ...githubEnv
16706
16958
  };
16707
16959
  this.agentEnv = agentEnv;
16708
16960
  const agentArgs = agentArgsWithModelSelection({
@@ -16715,7 +16967,7 @@ var MonolithCornerTurnLoop = class {
16715
16967
  this.attachmentDir = tmpDir ? join5(tmpDir, "beeline-attachments") : void 0;
16716
16968
  this.sessionScratchDir = tmpDir;
16717
16969
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
16718
- await Promise.all(homeStateDirs.map((dir) => mkdir7(dir, { recursive: true })));
16970
+ await Promise.all(homeStateDirs.map((dir) => mkdir9(dir, { recursive: true })));
16719
16971
  const spawnCommand = wrapAgentCommand({
16720
16972
  bwrapPath: this.options.config.bwrapPath,
16721
16973
  spec: {
@@ -16768,6 +17020,11 @@ var MonolithCornerTurnLoop = class {
16768
17020
  ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
16769
17021
  })
16770
17022
  ];
17023
+ await installPiMcpBridge({
17024
+ agentCommand: command,
17025
+ piHome: agentEnv.PI_CODING_AGENT_DIR,
17026
+ servers
17027
+ });
16771
17028
  const persona = configuration.soul ?? self?.soul;
16772
17029
  const identityInstructions = `Your Beeline identity is ${self?.name ?? this.agent.name}.`;
16773
17030
  const personaInstructions = [
@@ -17146,7 +17403,7 @@ async function wait(ms, signal) {
17146
17403
  }
17147
17404
 
17148
17405
  // apps/body/dist/monolith-room-turn.js
17149
- import { mkdir as mkdir8 } from "node:fs/promises";
17406
+ import { mkdir as mkdir10 } from "node:fs/promises";
17150
17407
  import { homedir as homedir7 } from "node:os";
17151
17408
  import { join as join6 } from "node:path";
17152
17409
 
@@ -17461,7 +17718,7 @@ var MonolithRoomTurnLoop = class {
17461
17718
  agentName: self?.name ?? this.agent.name
17462
17719
  });
17463
17720
  const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
17464
- await mkdir8(this.options.cwd, { recursive: true });
17721
+ await mkdir10(this.options.cwd, { recursive: true });
17465
17722
  const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
17466
17723
  const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
17467
17724
  root: this.options.config.agentHomeRoot,
@@ -17491,7 +17748,7 @@ var MonolithRoomTurnLoop = class {
17491
17748
  this.sessionScratchDir = tmpDir;
17492
17749
  this.sessionStateDirs = stateDirs;
17493
17750
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
17494
- await Promise.all(homeStateDirs.map((dir) => mkdir8(dir, { recursive: true })));
17751
+ await Promise.all(homeStateDirs.map((dir) => mkdir10(dir, { recursive: true })));
17495
17752
  const spawnCommand = wrapAgentCommand({
17496
17753
  bwrapPath: this.options.config.bwrapPath,
17497
17754
  spec: {
@@ -17520,6 +17777,11 @@ var MonolithRoomTurnLoop = class {
17520
17777
  ...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
17521
17778
  })
17522
17779
  ];
17780
+ await installPiMcpBridge({
17781
+ agentCommand: command,
17782
+ piHome: agentEnv.PI_CODING_AGENT_DIR,
17783
+ servers
17784
+ });
17523
17785
  const mountedServers = servers.map((server) => server.name);
17524
17786
  const clientOptions = {
17525
17787
  agentCommand: spawnCommand.command,
@@ -18535,13 +18797,13 @@ var RoomRuntimeCoordinator = class {
18535
18797
  return this.runtime.rooms.find((room) => room.channelId === roomId);
18536
18798
  }
18537
18799
  roomRoot(roomId) {
18538
- return this.roomRecord(roomId)?.root ?? resolve17(dirname6(this.configPath), "rooms", roomId);
18800
+ return this.roomRecord(roomId)?.root ?? resolve19(dirname6(this.configPath), "rooms", roomId);
18539
18801
  }
18540
18802
  roomAgentHomeRoot(workspaceRoot, required = false) {
18541
18803
  const flag = process.env.BUZZY_BODY_ROOM_HOME;
18542
18804
  if (!required && flag === "0")
18543
18805
  return void 0;
18544
- const home = resolve17(workspaceRoot, "agent-home");
18806
+ const home = resolve19(workspaceRoot, "agent-home");
18545
18807
  if (!required && flag !== "1" && !existsSync4(home) && existsSync4(workspaceRoot))
18546
18808
  return void 0;
18547
18809
  try {
@@ -18558,8 +18820,8 @@ var RoomRuntimeCoordinator = class {
18558
18820
  return {
18559
18821
  ...this.baseConfig,
18560
18822
  workspaceRoot,
18561
- agentPrivateRoot: resolve17(workspaceRoot, "agent-private"),
18562
- agentMemoryRoot: resolve17(dirname6(this.configPath), "memory"),
18823
+ agentPrivateRoot: resolve19(workspaceRoot, "agent-private"),
18824
+ agentMemoryRoot: resolve19(dirname6(this.configPath), "memory"),
18563
18825
  openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname6(this.configPath)),
18564
18826
  turnTraceDir: turnTraceDirectory(dirname6(this.configPath)),
18565
18827
  ...agentHomeRoot ? { agentHomeRoot } : {}
@@ -18628,11 +18890,11 @@ var RoomRuntimeCoordinator = class {
18628
18890
  const remote = roomCheckoutRemote(repository.remote);
18629
18891
  const targetBranch = repository.targetBranch || "main";
18630
18892
  const checkoutId = createHash4("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
18631
- const path = resolve17(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
18632
- await mkdir9(dirname6(path), { recursive: true, mode: 448 });
18893
+ const path = resolve19(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
18894
+ await mkdir11(dirname6(path), { recursive: true, mode: 448 });
18633
18895
  const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
18634
18896
  const env = token ? githubGitEnv(token.token) : process.env;
18635
- if (!existsSync4(resolve17(path, ".git"))) {
18897
+ if (!existsSync4(resolve19(path, ".git"))) {
18636
18898
  await execFileAsync3("git", ["clone", "--no-checkout", remote, path], {
18637
18899
  env,
18638
18900
  maxBuffer: 4 * 1024 * 1024
@@ -18757,12 +19019,12 @@ var RoomRuntimeCoordinator = class {
18757
19019
  async materializeCornerWorktree(input) {
18758
19020
  const remote = githubHttpsRemote(input.remote);
18759
19021
  const repositoryHash = createHash4("sha256").update(remote).digest("hex").slice(0, 24);
18760
- const gitCommonDir = resolve17(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
18761
- const path = resolve17(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
18762
- await mkdir9(dirname6(gitCommonDir), { recursive: true, mode: 448 });
18763
- await mkdir9(dirname6(path), { recursive: true, mode: 448 });
19022
+ const gitCommonDir = resolve19(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
19023
+ const path = resolve19(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
19024
+ await mkdir11(dirname6(gitCommonDir), { recursive: true, mode: 448 });
19025
+ await mkdir11(dirname6(path), { recursive: true, mode: 448 });
18764
19026
  const authEnv = githubGitEnv(input.token);
18765
- if (!existsSync4(resolve17(gitCommonDir, "HEAD"))) {
19027
+ if (!existsSync4(resolve19(gitCommonDir, "HEAD"))) {
18766
19028
  await execFileAsync3("git", ["clone", "--bare", remote, gitCommonDir], {
18767
19029
  env: authEnv,
18768
19030
  maxBuffer: 4 * 1024 * 1024
@@ -18775,7 +19037,7 @@ var RoomRuntimeCoordinator = class {
18775
19037
  "origin",
18776
19038
  `+refs/heads/${input.targetBranch}:refs/remotes/origin/${input.targetBranch}`
18777
19039
  ], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
18778
- if (!existsSync4(resolve17(path, ".git"))) {
19040
+ if (!existsSync4(resolve19(path, ".git"))) {
18779
19041
  await rm4(path, { recursive: true, force: true });
18780
19042
  await execFileAsync3("git", [
18781
19043
  `--git-dir=${gitCommonDir}`,
@@ -18812,7 +19074,7 @@ var RoomRuntimeCoordinator = class {
18812
19074
  `${this.agent.publicKey.slice(0, 16)}@users.noreply.github.com`
18813
19075
  ]);
18814
19076
  const top = await execFileAsync3("git", ["-C", path, "rev-parse", "--show-toplevel"]);
18815
- if (resolve17(top.stdout.trim()) !== resolve17(path)) {
19077
+ if (resolve19(top.stdout.trim()) !== resolve19(path)) {
18816
19078
  throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
18817
19079
  }
18818
19080
  return { path, gitCommonDir };
@@ -18990,9 +19252,9 @@ var ThinDaemonCore = class {
18990
19252
 
18991
19253
  // apps/body/dist/systemd.js
18992
19254
  import { execFile as execFile5 } from "node:child_process";
18993
- import { mkdir as mkdir10, readFile as readFile8, writeFile as writeFile7 } from "node:fs/promises";
19255
+ import { mkdir as mkdir12, readFile as readFile8, writeFile as writeFile8 } from "node:fs/promises";
18994
19256
  import { homedir as homedir8 } from "node:os";
18995
- import { dirname as dirname7, resolve as resolve18 } from "node:path";
19257
+ import { dirname as dirname7, resolve as resolve20 } from "node:path";
18996
19258
  import { setTimeout as sleep } from "node:timers/promises";
18997
19259
  import { promisify as promisify4 } from "node:util";
18998
19260
  var execFileAsync4 = promisify4(execFile5);
@@ -19034,9 +19296,9 @@ WantedBy=default.target
19034
19296
  }
19035
19297
  function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
19036
19298
  const home = env.HOME?.trim() || homedir8();
19037
- const expectedLibDir = resolve18(home, ".local", "lib", "beeline");
19299
+ const expectedLibDir = resolve20(home, ".local", "lib", "beeline");
19038
19300
  const expectedPrefix = `${expectedLibDir}/`;
19039
- return resolve18(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve18(invocationPath).startsWith(expectedPrefix);
19301
+ return resolve20(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve20(invocationPath).startsWith(expectedPrefix);
19040
19302
  }
19041
19303
  function assertCanonicalInstalledLauncher(env, invocationPath) {
19042
19304
  if (isCanonicalInstalledLauncher(env, invocationPath))
@@ -19044,8 +19306,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
19044
19306
  throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
19045
19307
  }
19046
19308
  function systemdUserUnitPath(env = process.env) {
19047
- const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve18(homedir8(), ".config");
19048
- return resolve18(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
19309
+ const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve20(homedir8(), ".config");
19310
+ return resolve20(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
19049
19311
  }
19050
19312
  var runSystemctl = async (args) => {
19051
19313
  const result = await execFileAsync4("systemctl", ["--user", ...args], {
@@ -19063,8 +19325,8 @@ async function installAgentService(publicKey, options = {}) {
19063
19325
  const content = agentServiceUnit();
19064
19326
  const existing = await readFile8(path, "utf8").catch(() => "");
19065
19327
  if (existing !== content) {
19066
- await mkdir10(dirname7(path), { recursive: true, mode: 448 });
19067
- await writeFile7(path, content, { mode: 384 });
19328
+ await mkdir12(dirname7(path), { recursive: true, mode: 448 });
19329
+ await writeFile8(path, content, { mode: 384 });
19068
19330
  }
19069
19331
  const run2 = options.run ?? runSystemctl;
19070
19332
  await run2(["daemon-reload"]);
@@ -19236,8 +19498,8 @@ async function runStartCommand(args, interactiveUi) {
19236
19498
  // apps/body/dist/connect-command.js
19237
19499
  import { spawn as spawn5 } from "node:child_process";
19238
19500
  import { createHash as createHash6 } from "node:crypto";
19239
- import { chmod as chmod4, mkdir as mkdir12, readFile as readFile10, unlink as unlink2, writeFile as writeFile9 } from "node:fs/promises";
19240
- import { dirname as dirname10, resolve as resolve20 } from "node:path";
19501
+ import { chmod as chmod5, mkdir as mkdir14, readFile as readFile10, unlink as unlink2, writeFile as writeFile10 } from "node:fs/promises";
19502
+ import { dirname as dirname10, resolve as resolve22 } from "node:path";
19241
19503
  import { stdin as stdin3, stdout as stdout4 } from "node:process";
19242
19504
 
19243
19505
  // packages/api-contract/dist/agent-pairing-code.js
@@ -19820,7 +20082,7 @@ function parseConnectSubscriptions(value) {
19820
20082
  ...new Set((value ?? "").split(",").map((entry) => entry.trim().toLowerCase()).filter(Boolean))
19821
20083
  ];
19822
20084
  }
19823
- function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, eventSubscriptions = []) {
20085
+ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
19824
20086
  const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
19825
20087
  if (!normalizedPairingCode)
19826
20088
  throw new Error("invalid pairing code");
@@ -19831,7 +20093,10 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, eventSu
19831
20093
  ...selection.provider ? { provider: selection.provider } : {},
19832
20094
  model: selection.model,
19833
20095
  avatar_seed: avatarSeed,
19834
- ...eventSubscriptions.length ? { event_subscriptions: [...eventSubscriptions] } : {}
20096
+ // This wizard always finishes the join itself (`finishConnectedAgentPairing`,
20097
+ // called once the rename prompt below settles), so the claim must not
20098
+ // join Rooms or announce yet.
20099
+ defer_join: true
19835
20100
  }, fetchImpl);
19836
20101
  }
19837
20102
  async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
@@ -19841,6 +20106,16 @@ async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
19841
20106
  const renamed = await jsonRequest(`${baseUrl}/auth/agent/connect/name`, { pairing_code: normalizedPairingCode, agent_name: name.trim().replace(/\s+/g, " ") }, fetchImpl);
19842
20107
  return renamed.agent_name;
19843
20108
  }
20109
+ async function finishConnectedAgentPairing(baseUrl, pairingCode, workspaceJoined, eventSubscriptions, fetchImpl) {
20110
+ const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
20111
+ if (!normalizedPairingCode)
20112
+ throw new Error("invalid pairing code");
20113
+ await jsonRequest(`${baseUrl}/auth/agent/connect/finish`, {
20114
+ pairing_code: normalizedPairingCode,
20115
+ workspace_joined: workspaceJoined,
20116
+ ...eventSubscriptions.length ? { event_subscriptions: [...eventSubscriptions] } : {}
20117
+ }, fetchImpl);
20118
+ }
19844
20119
  function seededIdentityLine(grant) {
19845
20120
  return grant.agent_face ? `${grant.agent_name} the ${grant.agent_face}` : grant.agent_name;
19846
20121
  }
@@ -19858,7 +20133,7 @@ async function installCurrentRelease(fetchImpl) {
19858
20133
  });
19859
20134
  await activateRelease(layout, releaseId);
19860
20135
  return {
19861
- binary: resolve20(layout.binDir, "beeline"),
20136
+ binary: resolve22(layout.binDir, "beeline"),
19862
20137
  version: published.version ?? releaseId
19863
20138
  };
19864
20139
  }
@@ -19881,21 +20156,21 @@ function providerEnvironment(selection) {
19881
20156
  };
19882
20157
  }
19883
20158
  async function writePrivateJson(path, value) {
19884
- await mkdir12(dirname10(path), { recursive: true, mode: 448 });
19885
- await writeFile9(path, `${JSON.stringify(value, null, 2)}
20159
+ await mkdir14(dirname10(path), { recursive: true, mode: 448 });
20160
+ await writeFile10(path, `${JSON.stringify(value, null, 2)}
19886
20161
  `, { mode: 384 });
19887
- await chmod4(path, 384);
20162
+ await chmod5(path, 384);
19888
20163
  }
19889
20164
  async function writeProviderEnv(selection, agentPubkey) {
19890
20165
  const values = providerEnvironment(selection);
19891
20166
  if (Object.keys(values).length === 0)
19892
20167
  return void 0;
19893
- const path = resolve20(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
19894
- await mkdir12(dirname10(path), { recursive: true, mode: 448 });
20168
+ const path = resolve22(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
20169
+ await mkdir14(dirname10(path), { recursive: true, mode: 448 });
19895
20170
  const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
19896
- await writeFile9(path, `${contents}
20171
+ await writeFile10(path, `${contents}
19897
20172
  `, { mode: 384 });
19898
- await chmod4(path, 384);
20173
+ await chmod5(path, 384);
19899
20174
  return path;
19900
20175
  }
19901
20176
  async function runInstalledFinish(binary, grantPath) {
@@ -19951,11 +20226,12 @@ async function runConnectWizard(code, fetchImpl, eventSubscriptions, accessPolic
19951
20226
  });
19952
20227
  const selection = await collectConnectWizard(clackPrompts, loadConnectModelCatalog, fileConnectKeyStore, process.env, (input) => verifyProviderKey({ ...input, fetchImpl }));
19953
20228
  const baseUrl = (process.env.BEELINE_AUTH_URL ?? "https://server.usebeeline.app").replace(/\/$/, "");
19954
- const claimed = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, eventSubscriptions), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
20229
+ const claimed = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
19955
20230
  const grant = { ...claimed, agent_name: await confirmSeededName(baseUrl, pairingCode, claimed, fetchImpl) };
20231
+ await finishConnectedAgentPairing(baseUrl, pairingCode, grant.workspace_joined, eventSubscriptions, fetchImpl);
19956
20232
  const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
19957
20233
  const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
19958
- const grantPath = resolve20(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
20234
+ const grantPath = resolve22(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
19959
20235
  await writePrivateJson(grantPath, {
19960
20236
  agentSecretKey: grant.agent_secret_key,
19961
20237
  bodySecretKey: grant.body_secret_key,
@@ -20037,11 +20313,11 @@ async function runConnectFinishCommand(path) {
20037
20313
  throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
20038
20314
  }
20039
20315
  try {
20040
- const grant = JSON.parse(await readFile10(resolve20(path), "utf8"));
20316
+ const grant = JSON.parse(await readFile10(resolve22(path), "utf8"));
20041
20317
  if (!isDevicePairingGrant(grant))
20042
20318
  throw new Error("device connection grant is invalid");
20043
20319
  const connected = await completeDevicePairing(grant);
20044
- await unlink2(resolve20(path));
20320
+ await unlink2(resolve22(path));
20045
20321
  const providerEnv = grant.llmEnvFile ? await readFile10(grant.llmEnvFile, "utf8").catch(() => "") : "";
20046
20322
  const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
20047
20323
  const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
@@ -20070,20 +20346,20 @@ init_self_update_manifest();
20070
20346
  // apps/body/dist/managed-update.js
20071
20347
  init_self_update();
20072
20348
  import { spawn as spawn6 } from "node:child_process";
20073
- import { mkdir as mkdir14, rm as rm6, stat as stat2, writeFile as writeFile11 } from "node:fs/promises";
20074
- import { dirname as dirname12, resolve as resolve22 } from "node:path";
20349
+ import { mkdir as mkdir16, rm as rm6, stat as stat2, writeFile as writeFile12 } from "node:fs/promises";
20350
+ import { dirname as dirname12, resolve as resolve24 } from "node:path";
20075
20351
 
20076
20352
  // apps/body/dist/update-rollback-alert.js
20077
- import { mkdir as mkdir13, readFile as readFile11, rename as rename4, writeFile as writeFile10 } from "node:fs/promises";
20078
- import { dirname as dirname11, resolve as resolve21 } from "node:path";
20353
+ import { mkdir as mkdir15, readFile as readFile11, rename as rename4, writeFile as writeFile11 } from "node:fs/promises";
20354
+ import { dirname as dirname11, resolve as resolve23 } from "node:path";
20079
20355
  function updateRollbackAlertPath(runtimeDir) {
20080
- return resolve21(runtimeDir, "update-rollback-alert.json");
20356
+ return resolve23(runtimeDir, "update-rollback-alert.json");
20081
20357
  }
20082
20358
  async function writeAlert(runtimeDir, alert) {
20083
20359
  const path = updateRollbackAlertPath(runtimeDir);
20084
20360
  const staged = `${path}.${process.pid}.tmp`;
20085
- await mkdir13(dirname11(path), { recursive: true });
20086
- await writeFile10(staged, `${JSON.stringify(alert, null, 2)}
20361
+ await mkdir15(dirname11(path), { recursive: true });
20362
+ await writeFile11(staged, `${JSON.stringify(alert, null, 2)}
20087
20363
  `, { mode: 384 });
20088
20364
  await rename4(staged, path);
20089
20365
  }
@@ -20120,13 +20396,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
20120
20396
  var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
20121
20397
  async function withInstallLock(layout, work, options = {}) {
20122
20398
  const now2 = options.now ?? Date.now;
20123
- const lock = resolve22(layout.releasesRoot, ".state", "install.lock");
20399
+ const lock = resolve24(layout.releasesRoot, ".state", "install.lock");
20124
20400
  const deadline = now2() + (options.waitMs ?? 1e4);
20125
- await mkdir14(dirname12(lock), { recursive: true });
20401
+ await mkdir16(dirname12(lock), { recursive: true });
20126
20402
  for (; ; ) {
20127
20403
  try {
20128
- await mkdir14(lock);
20129
- await writeFile11(resolve22(lock, "owner"), `${process.pid}
20404
+ await mkdir16(lock);
20405
+ await writeFile12(resolve24(lock, "owner"), `${process.pid}
20130
20406
  ${now2()}
20131
20407
  `, "utf8");
20132
20408
  break;
@@ -20249,7 +20525,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
20249
20525
  if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
20250
20526
  const from = await readInstalledBundleIdentity({
20251
20527
  ...this.#layout,
20252
- libDir: resolve22(this.#layout.releasesRoot, this.#loadedRelease)
20528
+ libDir: resolve24(this.#layout.releasesRoot, this.#loadedRelease)
20253
20529
  }).catch(() => void 0) ?? {};
20254
20530
  const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
20255
20531
  const record2 = {
@@ -20536,7 +20812,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
20536
20812
  });
20537
20813
  if (!accepted)
20538
20814
  return false;
20539
- await writeFile11(resolve22(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
20815
+ await writeFile12(resolve24(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
20540
20816
  readyAt: (options.now ?? Date.now)(),
20541
20817
  loadedRelease,
20542
20818
  functionalProof: options.functionalProof
@@ -20741,12 +21017,12 @@ async function runUpdateCommand(args) {
20741
21017
  init_self_update();
20742
21018
 
20743
21019
  // apps/body/dist/daemon-failure.js
20744
- import { mkdir as mkdir15, readFile as readFile12, rename as rename5, rm as rm7, writeFile as writeFile12 } from "node:fs/promises";
20745
- import { dirname as dirname13, resolve as resolve23 } from "node:path";
21020
+ import { mkdir as mkdir17, readFile as readFile12, rename as rename5, rm as rm7, writeFile as writeFile13 } from "node:fs/promises";
21021
+ import { dirname as dirname13, resolve as resolve25 } from "node:path";
20746
21022
  var DAEMON_FAILURE_LIMIT = 3;
20747
21023
  var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
20748
21024
  function daemonFailurePath(runtimeDir) {
20749
- return resolve23(runtimeDir, "daemon-distress.json");
21025
+ return resolve25(runtimeDir, "daemon-distress.json");
20750
21026
  }
20751
21027
  async function readFailureRecord(runtimeDir) {
20752
21028
  try {
@@ -20762,8 +21038,8 @@ async function readFailureRecord(runtimeDir) {
20762
21038
  async function writeFailureRecord(runtimeDir, record2) {
20763
21039
  const path = daemonFailurePath(runtimeDir);
20764
21040
  const staged = `${path}.${process.pid}.tmp`;
20765
- await mkdir15(dirname13(path), { recursive: true, mode: 448 });
20766
- await writeFile12(staged, `${JSON.stringify(record2, null, 2)}
21041
+ await mkdir17(dirname13(path), { recursive: true, mode: 448 });
21042
+ await writeFile13(staged, `${JSON.stringify(record2, null, 2)}
20767
21043
  `, { mode: 384 });
20768
21044
  await rename5(staged, path);
20769
21045
  }
@@ -20785,9 +21061,9 @@ async function clearDaemonStartFailures(runtimeDir) {
20785
21061
  }
20786
21062
 
20787
21063
  // apps/body/dist/update-functional-probe.js
20788
- import { mkdir as mkdir16, rm as rm8 } from "node:fs/promises";
21064
+ import { mkdir as mkdir18, rm as rm8 } from "node:fs/promises";
20789
21065
  import { homedir as homedir10 } from "node:os";
20790
- import { resolve as resolve24 } from "node:path";
21066
+ import { resolve as resolve26 } from "node:path";
20791
21067
  var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
20792
21068
  var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
20793
21069
  var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
@@ -20833,11 +21109,11 @@ async function runUpdateFunctionalProbe(input) {
20833
21109
  if (input.sandboxRequired && !input.config.bwrapPath) {
20834
21110
  throw new UpdateFunctionalProbeError("sandbox-unavailable", "the configured bubblewrap boundary did not pass its startup self-test");
20835
21111
  }
20836
- const root = input.probeRoot ?? resolve24(input.runtimeDir, "update-functional-probe");
20837
- const cwd = resolve24(root, "checkout");
20838
- const homeRoot = resolve24(root, "agent-home");
21112
+ const root = input.probeRoot ?? resolve26(input.runtimeDir, "update-functional-probe");
21113
+ const cwd = resolve26(root, "checkout");
21114
+ const homeRoot = resolve26(root, "agent-home");
20839
21115
  await rm8(root, { recursive: true, force: true });
20840
- await mkdir16(cwd, { recursive: true, mode: 448 });
21116
+ await mkdir18(cwd, { recursive: true, mode: 448 });
20841
21117
  let client;
20842
21118
  try {
20843
21119
  const agentEnv = {
@@ -20866,7 +21142,7 @@ async function runUpdateFunctionalProbe(input) {
20866
21142
  const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
20867
21143
  const operatorHome = input.config.operatorHome ?? homedir10();
20868
21144
  const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
20869
- await Promise.all(homeStateDirs.map((dir) => mkdir16(dir, { recursive: true })));
21145
+ await Promise.all(homeStateDirs.map((dir) => mkdir18(dir, { recursive: true })));
20870
21146
  spawnCommand = wrapAgentCommand({
20871
21147
  bwrapPath: input.config.bwrapPath,
20872
21148
  spec: {
@@ -21002,7 +21278,7 @@ async function probeReleaseInSubprocess(input) {
21002
21278
  return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
21003
21279
  }
21004
21280
  const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
21005
- return new Promise((resolve27) => {
21281
+ return new Promise((resolve29) => {
21006
21282
  const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
21007
21283
  let stdout6 = "";
21008
21284
  let stderr = "";
@@ -21012,7 +21288,7 @@ async function probeReleaseInSubprocess(input) {
21012
21288
  return;
21013
21289
  settled = true;
21014
21290
  clearTimeout(timer);
21015
- resolve27(outcome);
21291
+ resolve29(outcome);
21016
21292
  };
21017
21293
  const timer = setTimeout(() => {
21018
21294
  child.kill("SIGKILL");
@@ -21091,8 +21367,8 @@ async function runUpdateProbeCommand(args, options = {}) {
21091
21367
  }
21092
21368
 
21093
21369
  // apps/body/dist/release-status.js
21094
- import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as writeFile13 } from "node:fs/promises";
21095
- import { resolve as resolve25 } from "node:path";
21370
+ import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as writeFile14 } from "node:fs/promises";
21371
+ import { resolve as resolve27 } from "node:path";
21096
21372
  var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
21097
21373
  var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
21098
21374
  var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
@@ -21109,9 +21385,9 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
21109
21385
  pid: options.pid ?? process.pid,
21110
21386
  readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
21111
21387
  };
21112
- const target = resolve25(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
21388
+ const target = resolve27(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
21113
21389
  const temporary = `${target}.${status.pid}.tmp`;
21114
- await writeFile13(temporary, `${JSON.stringify(status, null, 2)}
21390
+ await writeFile14(temporary, `${JSON.stringify(status, null, 2)}
21115
21391
  `, { mode: 384 });
21116
21392
  await rename6(temporary, target);
21117
21393
  return status;
@@ -21169,7 +21445,7 @@ async function runStoredDaemon(pathOrPointer) {
21169
21445
  runtime = activated.runtime;
21170
21446
  const daemonApi = activated.client;
21171
21447
  const agent = runtimeAgentCommand(runtime);
21172
- await writeFile14(resolve26(dirname15(configPath), "daemon.pid"), `${process.pid}
21448
+ await writeFile15(resolve28(dirname15(configPath), "daemon.pid"), `${process.pid}
21173
21449
  `, { mode: 384 });
21174
21450
  const env = {
21175
21451
  ...process.env,
@@ -21177,7 +21453,7 @@ async function runStoredDaemon(pathOrPointer) {
21177
21453
  BUZZ_DEV_MCP_BIN: runtime.mcpBinary
21178
21454
  };
21179
21455
  const config = loadBodyConfig({
21180
- workspaceRoot: resolve26(dirname15(configPath), "workspace"),
21456
+ workspaceRoot: resolve28(dirname15(configPath), "workspace"),
21181
21457
  llmEnvFile: runtime.llmEnvFile,
21182
21458
  env,
21183
21459
  agent
@@ -21347,7 +21623,7 @@ async function runStoredDaemon(pathOrPointer) {
21347
21623
  throw error;
21348
21624
  } finally {
21349
21625
  await notifier.stopping(stoppingStatus).catch(() => void 0);
21350
- const pidPath = resolve26(dirname15(configPath), "daemon.pid");
21626
+ const pidPath = resolve28(dirname15(configPath), "daemon.pid");
21351
21627
  const recorded = Number((await readFile14(pidPath, "utf8").catch(() => "")).trim());
21352
21628
  if (recorded === process.pid) {
21353
21629
  await unlink3(pidPath).catch(() => void 0);
@@ -21368,6 +21644,21 @@ async function main() {
21368
21644
  console.log(JSON.stringify(await runManagedUpdateWorker()));
21369
21645
  return;
21370
21646
  }
21647
+ if (command === "corner-read-token") {
21648
+ const configFlag = args.indexOf("--config");
21649
+ const roomFlag = args.indexOf("--room");
21650
+ const configPath = configFlag >= 0 ? args[configFlag + 1] : void 0;
21651
+ const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
21652
+ if (!configPath || !roomId)
21653
+ throw new Error("corner-read-token requires --config and --room");
21654
+ const activated = await activateDaemonTransport(resolve28(configPath));
21655
+ if (!activated)
21656
+ throw new Error("corner-read-token requires monolith transport");
21657
+ const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
21658
+ process.stdout.write(`${credential.token}
21659
+ `);
21660
+ return;
21661
+ }
21371
21662
  if (command === "connect") {
21372
21663
  const subscribeFlag = args.indexOf("--subscribe");
21373
21664
  const subscribe = subscribeFlag >= 0 ? parseConnectSubscriptions(args[subscribeFlag + 1]) : [];
@@ -21422,7 +21713,7 @@ async function main() {
21422
21713
  }
21423
21714
  if (!configPath)
21424
21715
  throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
21425
- await runStoredDaemon(resolve26(configPath));
21716
+ await runStoredDaemon(resolve28(configPath));
21426
21717
  return;
21427
21718
  }
21428
21719
  if (command === "update") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.0.48",
3
+ "version": "0.0.50",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {