usebeeline 0.1.181 → 0.1.183

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 +226 -112
  2. package/package.json +1 -1
@@ -176,7 +176,12 @@ var init_lifecycle_test_guard = __esm({
176
176
  // apps/body/dist/self-update-manifest.js
177
177
  function resolveManifestUrl(env = process.env) {
178
178
  const override = env.BEELINE_UPDATE_MANIFEST_URL?.trim();
179
- return override && override.length > 0 ? override : DEFAULT_UPDATE_MANIFEST_URL;
179
+ if (override)
180
+ return override;
181
+ const channel = env.BEELINE_RELEASE_CHANNEL?.trim() || "latest";
182
+ if (!["latest", "next"].includes(channel))
183
+ throw new Error(`invalid helper release channel: ${channel}`);
184
+ return channel === "next" ? "https://usebeeline.app/dl/next/manifest.json" : DEFAULT_UPDATE_MANIFEST_URL;
180
185
  }
181
186
  function parseUpdateManifest(raw, platform) {
182
187
  let parsed;
@@ -1231,7 +1236,6 @@ var init_managed_update = __esm({
1231
1236
  #interruptAt;
1232
1237
  #deadlineAt;
1233
1238
  #handingOff;
1234
- #notice;
1235
1239
  #completed = false;
1236
1240
  #draining = false;
1237
1241
  constructor(options) {
@@ -1243,10 +1247,7 @@ var init_managed_update = __esm({
1243
1247
  get pending() {
1244
1248
  return this.#preparing ?? this.#handingOff;
1245
1249
  }
1246
- notify(releaseKey, minimum) {
1247
- if (releaseKey && releaseKey === this.#notice)
1248
- return;
1249
- this.#notice = releaseKey;
1250
+ notify(_releaseKey, minimum) {
1250
1251
  if (minimum && (!this.#minimum || !versionAtLeast(this.#minimum, minimum))) {
1251
1252
  this.#minimum = minimum;
1252
1253
  this.#handoffAt = this.now();
@@ -3445,9 +3446,9 @@ var require_dispatcher_base = __commonJS({
3445
3446
  }
3446
3447
  close(callback) {
3447
3448
  if (callback === void 0) {
3448
- return new Promise((resolve12, reject) => {
3449
+ return new Promise((resolve13, reject) => {
3449
3450
  this.close((err, data) => {
3450
- return err ? reject(err) : resolve12(data);
3451
+ return err ? reject(err) : resolve13(data);
3451
3452
  });
3452
3453
  });
3453
3454
  }
@@ -3485,12 +3486,12 @@ var require_dispatcher_base = __commonJS({
3485
3486
  err = null;
3486
3487
  }
3487
3488
  if (callback === void 0) {
3488
- return new Promise((resolve12, reject) => {
3489
+ return new Promise((resolve13, reject) => {
3489
3490
  this.destroy(err, (err2, data) => {
3490
3491
  return err2 ? (
3491
3492
  /* istanbul ignore next: should never error */
3492
3493
  reject(err2)
3493
- ) : resolve12(data);
3494
+ ) : resolve13(data);
3494
3495
  });
3495
3496
  });
3496
3497
  }
@@ -5757,8 +5758,8 @@ var require_util2 = __commonJS({
5757
5758
  function createDeferredPromise() {
5758
5759
  let res;
5759
5760
  let rej;
5760
- const promise = new Promise((resolve12, reject) => {
5761
- res = resolve12;
5761
+ const promise = new Promise((resolve13, reject) => {
5762
+ res = resolve13;
5762
5763
  rej = reject;
5763
5764
  });
5764
5765
  return { promise, resolve: res, reject: rej };
@@ -8004,12 +8005,12 @@ upgrade: ${upgrade}\r
8004
8005
  cb();
8005
8006
  }
8006
8007
  }
8007
- const waitForDrain = () => new Promise((resolve12, reject) => {
8008
+ const waitForDrain = () => new Promise((resolve13, reject) => {
8008
8009
  assert(callback === null);
8009
8010
  if (socket[kError]) {
8010
8011
  reject(socket[kError]);
8011
8012
  } else {
8012
- callback = resolve12;
8013
+ callback = resolve13;
8013
8014
  }
8014
8015
  });
8015
8016
  socket.on("close", onDrain).on("drain", onDrain);
@@ -8646,12 +8647,12 @@ var require_client_h2 = __commonJS({
8646
8647
  cb();
8647
8648
  }
8648
8649
  }
8649
- const waitForDrain = () => new Promise((resolve12, reject) => {
8650
+ const waitForDrain = () => new Promise((resolve13, reject) => {
8650
8651
  assert(callback === null);
8651
8652
  if (socket[kError]) {
8652
8653
  reject(socket[kError]);
8653
8654
  } else {
8654
- callback = resolve12;
8655
+ callback = resolve13;
8655
8656
  }
8656
8657
  });
8657
8658
  h2stream.on("close", onDrain).on("drain", onDrain);
@@ -9129,16 +9130,16 @@ var require_client = __commonJS({
9129
9130
  return this[kNeedDrain] < 2;
9130
9131
  }
9131
9132
  async [kClose]() {
9132
- return new Promise((resolve12) => {
9133
+ return new Promise((resolve13) => {
9133
9134
  if (this[kSize]) {
9134
- this[kClosedResolve] = resolve12;
9135
+ this[kClosedResolve] = resolve13;
9135
9136
  } else {
9136
- resolve12(null);
9137
+ resolve13(null);
9137
9138
  }
9138
9139
  });
9139
9140
  }
9140
9141
  async [kDestroy](err) {
9141
- return new Promise((resolve12) => {
9142
+ return new Promise((resolve13) => {
9142
9143
  const requests = this[kQueue].splice(this[kPendingIdx]);
9143
9144
  for (let i = 0; i < requests.length; i++) {
9144
9145
  const request2 = requests[i];
@@ -9149,7 +9150,7 @@ var require_client = __commonJS({
9149
9150
  this[kClosedResolve]();
9150
9151
  this[kClosedResolve] = null;
9151
9152
  }
9152
- resolve12(null);
9153
+ resolve13(null);
9153
9154
  };
9154
9155
  if (this[kHTTPContext]) {
9155
9156
  this[kHTTPContext].destroy(err, callback);
@@ -9200,7 +9201,7 @@ var require_client = __commonJS({
9200
9201
  });
9201
9202
  }
9202
9203
  try {
9203
- const socket = await new Promise((resolve12, reject) => {
9204
+ const socket = await new Promise((resolve13, reject) => {
9204
9205
  client[kConnector]({
9205
9206
  host,
9206
9207
  hostname,
@@ -9212,7 +9213,7 @@ var require_client = __commonJS({
9212
9213
  if (err) {
9213
9214
  reject(err);
9214
9215
  } else {
9215
- resolve12(socket2);
9216
+ resolve13(socket2);
9216
9217
  }
9217
9218
  });
9218
9219
  });
@@ -9548,8 +9549,8 @@ var require_pool_base = __commonJS({
9548
9549
  if (this[kQueue].isEmpty()) {
9549
9550
  await Promise.all(this[kClients].map((c) => c.close()));
9550
9551
  } else {
9551
- await new Promise((resolve12) => {
9552
- this[kClosedResolve] = resolve12;
9552
+ await new Promise((resolve13) => {
9553
+ this[kClosedResolve] = resolve13;
9553
9554
  });
9554
9555
  }
9555
9556
  }
@@ -10792,7 +10793,7 @@ var require_readable = __commonJS({
10792
10793
  if (this._readableState.closeEmitted) {
10793
10794
  return null;
10794
10795
  }
10795
- return await new Promise((resolve12, reject) => {
10796
+ return await new Promise((resolve13, reject) => {
10796
10797
  if (this[kContentLength] > limit) {
10797
10798
  this.destroy(new AbortError());
10798
10799
  }
@@ -10805,7 +10806,7 @@ var require_readable = __commonJS({
10805
10806
  if (signal?.aborted) {
10806
10807
  reject(signal.reason ?? new AbortError());
10807
10808
  } else {
10808
- resolve12(null);
10809
+ resolve13(null);
10809
10810
  }
10810
10811
  }).on("error", noop).on("data", function(chunk) {
10811
10812
  limit -= chunk.length;
@@ -10824,7 +10825,7 @@ var require_readable = __commonJS({
10824
10825
  }
10825
10826
  async function consume(stream, type) {
10826
10827
  assert(!stream[kConsume]);
10827
- return new Promise((resolve12, reject) => {
10828
+ return new Promise((resolve13, reject) => {
10828
10829
  if (isUnusable(stream)) {
10829
10830
  const rState = stream._readableState;
10830
10831
  if (rState.destroyed && rState.closeEmitted === false) {
@@ -10841,7 +10842,7 @@ var require_readable = __commonJS({
10841
10842
  stream[kConsume] = {
10842
10843
  type,
10843
10844
  stream,
10844
- resolve: resolve12,
10845
+ resolve: resolve13,
10845
10846
  reject,
10846
10847
  length: 0,
10847
10848
  body: []
@@ -10911,18 +10912,18 @@ var require_readable = __commonJS({
10911
10912
  return buffer;
10912
10913
  }
10913
10914
  function consumeEnd(consume2) {
10914
- const { type, body, resolve: resolve12, stream, length } = consume2;
10915
+ const { type, body, resolve: resolve13, stream, length } = consume2;
10915
10916
  try {
10916
10917
  if (type === "text") {
10917
- resolve12(chunksDecode(body, length));
10918
+ resolve13(chunksDecode(body, length));
10918
10919
  } else if (type === "json") {
10919
- resolve12(JSON.parse(chunksDecode(body, length)));
10920
+ resolve13(JSON.parse(chunksDecode(body, length)));
10920
10921
  } else if (type === "arrayBuffer") {
10921
- resolve12(chunksConcat(body, length).buffer);
10922
+ resolve13(chunksConcat(body, length).buffer);
10922
10923
  } else if (type === "blob") {
10923
- resolve12(new Blob(body, { type: stream[kContentType] }));
10924
+ resolve13(new Blob(body, { type: stream[kContentType] }));
10924
10925
  } else if (type === "bytes") {
10925
- resolve12(chunksConcat(body, length));
10926
+ resolve13(chunksConcat(body, length));
10926
10927
  }
10927
10928
  consumeFinish(consume2);
10928
10929
  } catch (err) {
@@ -11179,9 +11180,9 @@ var require_api_request = __commonJS({
11179
11180
  };
11180
11181
  function request2(opts, callback) {
11181
11182
  if (callback === void 0) {
11182
- return new Promise((resolve12, reject) => {
11183
+ return new Promise((resolve13, reject) => {
11183
11184
  request2.call(this, opts, (err, data) => {
11184
- return err ? reject(err) : resolve12(data);
11185
+ return err ? reject(err) : resolve13(data);
11185
11186
  });
11186
11187
  });
11187
11188
  }
@@ -11404,9 +11405,9 @@ var require_api_stream = __commonJS({
11404
11405
  };
11405
11406
  function stream(opts, factory, callback) {
11406
11407
  if (callback === void 0) {
11407
- return new Promise((resolve12, reject) => {
11408
+ return new Promise((resolve13, reject) => {
11408
11409
  stream.call(this, opts, factory, (err, data) => {
11409
- return err ? reject(err) : resolve12(data);
11410
+ return err ? reject(err) : resolve13(data);
11410
11411
  });
11411
11412
  });
11412
11413
  }
@@ -11691,9 +11692,9 @@ var require_api_upgrade = __commonJS({
11691
11692
  };
11692
11693
  function upgrade(opts, callback) {
11693
11694
  if (callback === void 0) {
11694
- return new Promise((resolve12, reject) => {
11695
+ return new Promise((resolve13, reject) => {
11695
11696
  upgrade.call(this, opts, (err, data) => {
11696
- return err ? reject(err) : resolve12(data);
11697
+ return err ? reject(err) : resolve13(data);
11697
11698
  });
11698
11699
  });
11699
11700
  }
@@ -11785,9 +11786,9 @@ var require_api_connect = __commonJS({
11785
11786
  };
11786
11787
  function connect(opts, callback) {
11787
11788
  if (callback === void 0) {
11788
- return new Promise((resolve12, reject) => {
11789
+ return new Promise((resolve13, reject) => {
11789
11790
  connect.call(this, opts, (err, data) => {
11790
- return err ? reject(err) : resolve12(data);
11791
+ return err ? reject(err) : resolve13(data);
11791
11792
  });
11792
11793
  });
11793
11794
  }
@@ -15649,7 +15650,7 @@ var require_fetch = __commonJS({
15649
15650
  function dispatch({ body }) {
15650
15651
  const url = requestCurrentURL(request2);
15651
15652
  const agent = fetchParams.controller.dispatcher;
15652
- return new Promise((resolve12, reject) => agent.dispatch(
15653
+ return new Promise((resolve13, reject) => agent.dispatch(
15653
15654
  {
15654
15655
  path: url.pathname + url.search,
15655
15656
  origin: url.origin,
@@ -15725,7 +15726,7 @@ var require_fetch = __commonJS({
15725
15726
  }
15726
15727
  }
15727
15728
  const onError = this.onError.bind(this);
15728
- resolve12({
15729
+ resolve13({
15729
15730
  status,
15730
15731
  statusText,
15731
15732
  headersList,
@@ -15771,7 +15772,7 @@ var require_fetch = __commonJS({
15771
15772
  for (let i = 0; i < rawHeaders.length; i += 2) {
15772
15773
  headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString("latin1"), true);
15773
15774
  }
15774
- resolve12({
15775
+ resolve13({
15775
15776
  status,
15776
15777
  statusText: STATUS_CODES[status],
15777
15778
  headersList,
@@ -19501,8 +19502,8 @@ var require_util8 = __commonJS({
19501
19502
  return true;
19502
19503
  }
19503
19504
  function delay(ms) {
19504
- return new Promise((resolve12) => {
19505
- setTimeout(resolve12, ms).unref();
19505
+ return new Promise((resolve13) => {
19506
+ setTimeout(resolve13, ms).unref();
19506
19507
  });
19507
19508
  }
19508
19509
  module.exports = {
@@ -20187,7 +20188,7 @@ import { watch as watch2 } from "node:fs";
20187
20188
  import { stat as stat2 } from "node:fs/promises";
20188
20189
  import { dirname as dirname6 } from "node:path";
20189
20190
  function waitForPathRemoval(path) {
20190
- return new Promise((resolve12, reject) => {
20191
+ return new Promise((resolve13, reject) => {
20191
20192
  let reading = false, dirty = false, ended = false;
20192
20193
  const finish = (error) => {
20193
20194
  if (ended)
@@ -20197,7 +20198,7 @@ function waitForPathRemoval(path) {
20197
20198
  if (error)
20198
20199
  reject(error);
20199
20200
  else
20200
- resolve12();
20201
+ resolve13();
20201
20202
  };
20202
20203
  const inspect = async () => {
20203
20204
  dirty = true;
@@ -20674,6 +20675,35 @@ var init_beeline_api = __esm({
20674
20675
  }
20675
20676
  });
20676
20677
 
20678
+ // apps/body/dist/process-exit.js
20679
+ import { spawn as spawn5 } from "node:child_process";
20680
+ function waitForProcessExit(pid, signal) {
20681
+ return new Promise((resolve13, reject) => {
20682
+ const child = spawn5("/usr/bin/python3", ["-c", WAIT, String(pid)], { stdio: "ignore", signal });
20683
+ child.once("error", reject);
20684
+ child.once("close", (code) => code === 0 ? resolve13() : reject(new Error(`process exit observer failed (${code})`)));
20685
+ });
20686
+ }
20687
+ var WAIT;
20688
+ var init_process_exit = __esm({
20689
+ "apps/body/dist/process-exit.js"() {
20690
+ "use strict";
20691
+ WAIT = `import os,sys,select
20692
+ pid=int(sys.argv[1])
20693
+ try:
20694
+ if hasattr(os,'pidfd_open'):
20695
+ fd=os.pidfd_open(pid)
20696
+ try: select.select([fd],[],[])
20697
+ finally: os.close(fd)
20698
+ else:
20699
+ queue=select.kqueue()
20700
+ try: queue.control([select.kevent(pid,filter=select.KQ_FILTER_PROC,flags=select.KQ_EV_ADD|select.KQ_EV_ONESHOT,fflags=select.KQ_NOTE_EXIT)],1)
20701
+ finally: queue.close()
20702
+ except ProcessLookupError: pass
20703
+ `;
20704
+ }
20705
+ });
20706
+
20677
20707
  // packages/api-contract/dist/phone-types-room-live-delta.js
20678
20708
  var init_phone_types_room_live_delta = __esm({
20679
20709
  "packages/api-contract/dist/phone-types-room-live-delta.js"() {
@@ -23915,12 +23945,12 @@ function scanCodex(proc = "/proc") {
23915
23945
  return found;
23916
23946
  }
23917
23947
  function codexQueue(threadId, text, bin = "codex", timeoutMs = 3e4) {
23918
- return new Promise((resolve12, reject) => {
23948
+ return new Promise((resolve13, reject) => {
23919
23949
  execFile3(bin, ["queue", "--thread", threadId, "--message", text], { timeout: timeoutMs }, (error, _stdout, stderr) => {
23920
23950
  if (error)
23921
23951
  reject(new Error(String(stderr).trim() || error.message));
23922
23952
  else
23923
- resolve12();
23953
+ resolve13();
23924
23954
  });
23925
23955
  });
23926
23956
  }
@@ -23967,7 +23997,7 @@ function chosenName(session2) {
23967
23997
  return ["user", "peer", "hook"].includes(session2.nameSource ?? "") ? session2.name : void 0;
23968
23998
  }
23969
23999
  function postToClaude(socket, text, _timeoutMs = 5e3) {
23970
- return new Promise((resolve12, reject) => {
24000
+ return new Promise((resolve13, reject) => {
23971
24001
  const connection = createConnection3(socket.path);
23972
24002
  connection.once("error", (error) => {
23973
24003
  reject(error);
@@ -23976,7 +24006,7 @@ function postToClaude(socket, text, _timeoutMs = 5e3) {
23976
24006
  if (socket.token)
23977
24007
  connection.write(JSON.stringify({ type: "auth", token: socket.token }) + "\n");
23978
24008
  connection.end(JSON.stringify({ type: "user", message: { role: "user", content: text } }) + "\n", () => {
23979
- resolve12();
24009
+ resolve13();
23980
24010
  });
23981
24011
  });
23982
24012
  });
@@ -24066,17 +24096,19 @@ function hasClaudeMcp(dir, claudePid) {
24066
24096
  }
24067
24097
  async function flushClaudeMcp(dir, session2, token, post = postToClaude) {
24068
24098
  if (!session2.messagingSocketPath)
24069
- return;
24099
+ return false;
24070
24100
  const joined2 = readState(dir).sessions.find((s) => s.agent === "claude-code" && (s.pid === session2.pid || s.sessionId === session2.sessionId));
24071
24101
  if (!joined2)
24072
- return;
24102
+ return false;
24073
24103
  const text = takeInbox(dir, joined2.key);
24074
24104
  if (!text)
24075
- return;
24105
+ return false;
24076
24106
  try {
24077
24107
  await post({ path: session2.messagingSocketPath, token }, text);
24108
+ return true;
24078
24109
  } catch {
24079
24110
  queueInbox(dir, joined2.key, text);
24111
+ return false;
24080
24112
  }
24081
24113
  }
24082
24114
  function joinedClaude(dir, env, chain) {
@@ -24086,32 +24118,38 @@ function joinedClaude(dir, env, chain) {
24086
24118
  return void 0;
24087
24119
  return readState(dir).sessions.find((s) => s.agent === "claude-code" && (s.pid === session2.pid || s.sessionId === session2.sessionId));
24088
24120
  }
24089
- async function runClaudeMcp(dir, env, rulesFor) {
24121
+ async function runClaudeMcp(dir, env, rulesFor, post = postToClaude) {
24090
24122
  const chain = ancestors(process.pid);
24091
24123
  let registration;
24092
- let flushing = false;
24124
+ let flushing = false, dirty = false;
24093
24125
  const flush2 = async () => {
24126
+ dirty = true;
24094
24127
  if (flushing || !env.CLAUDE_CODE_MESSAGING_TOKEN)
24095
24128
  return;
24096
24129
  flushing = true;
24097
24130
  try {
24098
- const live = scanClaude(env);
24099
- const session2 = chain.map((pid) => live.find((s) => s.pid === pid)).find(Boolean);
24100
- if (!session2)
24101
- return;
24102
- if (!registration) {
24103
- const folder = join6(dir, "claude-mcp");
24104
- mkdirSync2(folder, { recursive: true, mode: 448 });
24105
- registration = join6(folder, `${process.pid}.json`);
24106
- writeFileSync2(registration, JSON.stringify({ pid: process.pid, claudePid: session2.pid }), { mode: 384 });
24131
+ while (dirty) {
24132
+ dirty = false;
24133
+ const live = scanClaude(env);
24134
+ const session2 = chain.map((pid) => live.find((s) => s.pid === pid)).find(Boolean);
24135
+ if (!session2)
24136
+ return;
24137
+ if (!registration) {
24138
+ const folder = join6(dir, "claude-mcp");
24139
+ mkdirSync2(folder, { recursive: true, mode: 448 });
24140
+ registration = join6(folder, `${process.pid}.json`);
24141
+ writeFileSync2(registration, JSON.stringify({ pid: process.pid, claudePid: session2.pid }), { mode: 384 });
24142
+ }
24143
+ if (!await flushClaudeMcp(dir, session2, env.CLAUDE_CODE_MESSAGING_TOKEN, post))
24144
+ break;
24107
24145
  }
24108
- await flushClaudeMcp(dir, session2, env.CLAUDE_CODE_MESSAGING_TOKEN);
24109
24146
  } finally {
24110
24147
  flushing = false;
24111
24148
  }
24112
24149
  };
24113
24150
  const watcher = watch3(dir, { recursive: true }, (_event, name) => {
24114
- if (String(name ?? "").startsWith("inbox/"))
24151
+ const path = String(name ?? "");
24152
+ if (path === "state.json" || path.startsWith("inbox/"))
24115
24153
  void flush2().catch(() => void 0);
24116
24154
  });
24117
24155
  try {
@@ -24200,10 +24238,10 @@ var init_sessions = __esm({
24200
24238
  });
24201
24239
 
24202
24240
  // apps/body/dist/session-join/bridge.js
24203
- import { spawn as spawn5 } from "node:child_process";
24241
+ import { execFileSync, spawn as spawn6 } from "node:child_process";
24204
24242
  import { chmodSync as chmodSync2, closeSync as closeSync3, existsSync as existsSync2, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync6, readdirSync as readdirSync5, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync3, watch as watch4 } from "node:fs";
24205
24243
  import { createConnection as createConnection4, createServer as createServer3 } from "node:net";
24206
- import { join as join7 } from "node:path";
24244
+ import { basename as basename4, join as join7, resolve as resolve10 } from "node:path";
24207
24245
  import { createHash as createHash6 } from "node:crypto";
24208
24246
  function command(runner2, joined2, args) {
24209
24247
  const q = (v) => /^[A-Za-z0-9_./:@=-]+$/.test(v) ? v : `"${v.replace(/(["\\$`])/g, "\\$1")}"`;
@@ -24402,14 +24440,14 @@ async function toolViaOutbox(cwd, name, args) {
24402
24440
  const request2 = join7(dirPath, `${id}.request.json`), result = join7(dirPath, `${id}.result.json`);
24403
24441
  writeFileSync3(`${request2}.tmp`, JSON.stringify({ name, args }));
24404
24442
  renameSync2(`${request2}.tmp`, request2);
24405
- return new Promise((resolve12) => {
24443
+ return new Promise((resolve13) => {
24406
24444
  let settled = false;
24407
24445
  const finish = (answer) => {
24408
24446
  if (settled)
24409
24447
  return;
24410
24448
  settled = true;
24411
24449
  watcher.close();
24412
- resolve12(answer);
24450
+ resolve13(answer);
24413
24451
  };
24414
24452
  const inspect = () => {
24415
24453
  try {
@@ -24427,7 +24465,7 @@ async function toolViaOutbox(cwd, name, args) {
24427
24465
  });
24428
24466
  }
24429
24467
  function toolViaBridge(dir, key, name, args) {
24430
- return new Promise((resolve12) => {
24468
+ return new Promise((resolve13) => {
24431
24469
  const connection = createConnection4(join7(dir, "bridge.sock"));
24432
24470
  let text = "", sent = false, settled = false;
24433
24471
  const unknown = { ok: false, error: "Beeline tool result is awaiting confirmation" };
@@ -24435,7 +24473,7 @@ function toolViaBridge(dir, key, name, args) {
24435
24473
  if (settled)
24436
24474
  return;
24437
24475
  settled = true;
24438
- resolve12(answer);
24476
+ resolve13(answer);
24439
24477
  connection.destroy();
24440
24478
  };
24441
24479
  connection.setEncoding("utf8");
@@ -24477,6 +24515,7 @@ async function runBridge(dir, runner2) {
24477
24515
  wake?.();
24478
24516
  };
24479
24517
  serveTools(dir);
24518
+ writeFileSync3(join7(dir, "bridge-owner.json"), JSON.stringify({ pid: process.pid, digest: bundleDigest(runner2) }), { mode: 384 });
24480
24519
  const localWatch = watch4(dir, { recursive: true }, (_event, name) => {
24481
24520
  const path = String(name ?? "");
24482
24521
  if (path === "state.json" || path.startsWith("hooks/") || path.startsWith("inbox/") || path.startsWith("deliveries/"))
@@ -24573,8 +24612,8 @@ async function runBridge(dir, runner2) {
24573
24612
  await serveOutboxes(dir).catch((error) => log(dir, `outbox: ${String(error)}`));
24574
24613
  await flush(dir, sources).catch((error) => log(dir, `flush: ${String(error)}`));
24575
24614
  if (!localDirty)
24576
- await new Promise((resolve12) => {
24577
- wake = resolve12;
24615
+ await new Promise((resolve13) => {
24616
+ wake = resolve13;
24578
24617
  });
24579
24618
  wake = void 0;
24580
24619
  }
@@ -24599,19 +24638,90 @@ function bridgeRunning(dir) {
24599
24638
  return false;
24600
24639
  }
24601
24640
  }
24602
- function ensureBridge(dir, runner2, env = process.env) {
24603
- if (bridgeRunning(dir))
24604
- return;
24605
- const out = openSync3(join7(dir, "bridge.log"), "a", 384);
24606
- const child = spawn5(runner2.node, [runner2.bundle, "session", "bridge"], { detached: true, stdio: ["ignore", out, out], env });
24607
- child.unref();
24608
- closeSync3(out);
24641
+ function bundleDigest(runner2) {
24642
+ return createHash6("sha256").update(readFileSync6(runner2.bundle)).digest("hex");
24643
+ }
24644
+ function bridgeOwner(dir) {
24645
+ try {
24646
+ return JSON.parse(readFileSync6(join7(dir, "bridge-owner.json"), "utf8"));
24647
+ } catch {
24648
+ return void 0;
24649
+ }
24650
+ }
24651
+ function isBridgeProcess(pid) {
24652
+ try {
24653
+ if (process.platform === "linux") {
24654
+ const args2 = readFileSync6(`/proc/${pid}/cmdline`, "utf8").split("\0").filter(Boolean);
24655
+ return args2.length === 4 && /^node(?:\.exe)?$/.test(basename4(args2[0])) && /^(?:beeline|usebeeline\.mjs|recovery-cli\.mjs)$/.test(basename4(args2[1])) && args2[2] === "session" && args2[3] === "bridge";
24656
+ }
24657
+ const args = execFileSync("ps", ["-ww", "-p", String(pid), "-o", "args="], { encoding: "utf8" }).trim();
24658
+ return /(?:^|\/)node\s+.*\/(?:beeline|usebeeline\.mjs|recovery-cli\.mjs) session bridge$/.test(args);
24659
+ } catch {
24660
+ return false;
24661
+ }
24662
+ }
24663
+ async function ensureBridge(dir, runner2, env = process.env) {
24664
+ await withKernelLock(`beeline-session-bridge:${resolve10(dir)}`, async () => {
24665
+ const digest = bundleDigest(runner2);
24666
+ const pidFile = join7(dir, "bridge.pid");
24667
+ if (bridgeRunning(dir)) {
24668
+ const pid = Number(readFileSync6(pidFile, "utf8"));
24669
+ if (!isBridgeProcess(pid))
24670
+ throw new Error("Beeline bridge PID belongs to an unrecognized process; refusing takeover");
24671
+ const owner = bridgeOwner(dir);
24672
+ if (owner?.pid === pid && owner.digest === digest)
24673
+ return;
24674
+ log(dir, `replacing stale bridge ${pid}`);
24675
+ await withLock(dir, async () => {
24676
+ try {
24677
+ process.kill(pid, "SIGTERM");
24678
+ } catch (error) {
24679
+ if (error.code !== "ESRCH")
24680
+ throw error;
24681
+ }
24682
+ await waitForProcessExit(pid);
24683
+ });
24684
+ if (existsSync2(pidFile) && Number(readFileSync6(pidFile, "utf8")) === pid)
24685
+ rmSync3(pidFile);
24686
+ }
24687
+ const out = openSync3(join7(dir, "bridge.log"), "a", 384);
24688
+ const child = spawn6(runner2.node, [runner2.bundle, "session", "bridge"], { detached: true, stdio: ["ignore", out, out], env });
24689
+ closeSync3(out);
24690
+ child.unref();
24691
+ await new Promise((done, fail) => {
24692
+ const finish = (error) => {
24693
+ watcher.close();
24694
+ child.removeListener("error", failed);
24695
+ child.removeListener("exit", exited);
24696
+ if (error)
24697
+ fail(error);
24698
+ else
24699
+ done();
24700
+ };
24701
+ const inspect = () => {
24702
+ const owner = bridgeOwner(dir);
24703
+ if (owner && owner.pid === child.pid && owner.digest === digest)
24704
+ finish();
24705
+ };
24706
+ const failed = (error) => finish(error);
24707
+ const exited = () => finish(new Error("Beeline bridge exited before readiness; see bridge.log"));
24708
+ const watcher = watch4(dir, (_event, name) => {
24709
+ if (String(name) === "bridge-owner.json")
24710
+ inspect();
24711
+ });
24712
+ child.once("error", failed);
24713
+ child.once("exit", exited);
24714
+ inspect();
24715
+ });
24716
+ });
24609
24717
  }
24610
24718
  var realDeps;
24611
24719
  var init_bridge = __esm({
24612
24720
  "apps/body/dist/session-join/bridge.js"() {
24613
24721
  "use strict";
24614
24722
  init_agent_command();
24723
+ init_kernel_lock();
24724
+ init_process_exit();
24615
24725
  init_phone();
24616
24726
  init_beeline_api();
24617
24727
  init_stream_frame();
@@ -25232,7 +25342,7 @@ var init_claude_inbound = __esm({
25232
25342
  });
25233
25343
 
25234
25344
  // apps/body/dist/session-join/codex-trust.js
25235
- import { spawn as spawn6 } from "node:child_process";
25345
+ import { spawn as spawn7 } from "node:child_process";
25236
25346
  import { join as join10 } from "node:path";
25237
25347
  function beelineTrustEdits(hooks, context) {
25238
25348
  const path = join10(codexHome(context.env), "hooks.json");
@@ -25244,7 +25354,7 @@ function beelineTrustEdits(hooks, context) {
25244
25354
  return [{ keyPath: `hooks.state.${JSON.stringify(hook.key)}.trusted_hash`, value: hook.currentHash, mergeStrategy: "replace" }];
25245
25355
  }
25246
25356
  async function trustCodexHook(context, bin, cwd) {
25247
- const child = spawn6(bin, ["app-server", "--stdio"], { env: context.env, cwd, stdio: ["pipe", "pipe", "ignore"] });
25357
+ const child = spawn7(bin, ["app-server", "--stdio"], { env: context.env, cwd, stdio: ["pipe", "pipe", "ignore"] });
25248
25358
  let id = 0, buffer = "";
25249
25359
  const pending = /* @__PURE__ */ new Map();
25250
25360
  const fail = () => {
@@ -25282,9 +25392,9 @@ async function trustCodexHook(context, bin, cwd) {
25282
25392
  }
25283
25393
  }
25284
25394
  });
25285
- const request2 = (method, params) => new Promise((resolve12, reject) => {
25395
+ const request2 = (method, params) => new Promise((resolve13, reject) => {
25286
25396
  const key = ++id;
25287
- pending.set(key, { resolve: resolve12, reject: () => reject(new Error("Codex hook trust unavailable")) });
25397
+ pending.set(key, { resolve: resolve13, reject: () => reject(new Error("Codex hook trust unavailable")) });
25288
25398
  child.stdin.write(JSON.stringify({ id: key, method, params }) + "\n");
25289
25399
  });
25290
25400
  try {
@@ -25465,7 +25575,7 @@ var init_pull_apps = __esm({
25465
25575
  "use strict";
25466
25576
  init_store();
25467
25577
  init_beeline_api();
25468
- agentapi = (sessionId, text) => new Promise((resolve12, reject) => execFile4("agentapi", ["send-message", sessionId, text], { timeout: 3e4 }, (error) => error ? reject(error) : resolve12()));
25578
+ agentapi = (sessionId, text) => new Promise((resolve13, reject) => execFile4("agentapi", ["send-message", sessionId, text], { timeout: 3e4 }, (error) => error ? reject(error) : resolve13()));
25469
25579
  }
25470
25580
  });
25471
25581
 
@@ -25475,9 +25585,9 @@ __export(command_exports, {
25475
25585
  findOwnSession: () => findOwnSession,
25476
25586
  runSessionCommand: () => runSessionCommand
25477
25587
  });
25478
- import { spawn as spawn7, spawnSync as spawnSync2 } from "node:child_process";
25588
+ import { spawn as spawn8, spawnSync as spawnSync2 } from "node:child_process";
25479
25589
  import { closeSync as closeSync4, copyFileSync as copyFileSync2, existsSync as existsSync5, fsyncSync, mkdirSync as mkdirSync5, openSync as openSync4, readFileSync as readFileSync9, readdirSync as readdirSync6, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "node:fs";
25480
- import { delimiter, dirname as dirname8, join as join11, resolve as resolve10 } from "node:path";
25590
+ import { delimiter, dirname as dirname8, join as join11, resolve as resolve11 } from "node:path";
25481
25591
  import { createHash as createHash7, randomUUID as randomUUID2 } from "node:crypto";
25482
25592
  function writePending(file, pending) {
25483
25593
  const temporary = file + "." + randomUUID2() + ".tmp";
@@ -25547,7 +25657,7 @@ function runner(dir, env) {
25547
25657
  if (env.BEELINE_SESSION_BUNDLE)
25548
25658
  return { node: process.execPath, bundle: env.BEELINE_SESSION_BUNDLE };
25549
25659
  const bundle = join11(dir, "usebeeline.mjs");
25550
- const running = resolve10(process.argv[1] ?? "");
25660
+ const running = resolve11(process.argv[1] ?? "");
25551
25661
  if (running !== bundle && running.endsWith(".mjs")) {
25552
25662
  mkdirSync5(dir, { recursive: true, mode: 448 });
25553
25663
  copyFileSync2(running, bundle);
@@ -25600,6 +25710,7 @@ async function joinCommand(args, env) {
25600
25710
  const server = serverUrl(args, env);
25601
25711
  const existing = readState(dir).sessions.find((s) => s.key === key && s.server === server);
25602
25712
  if (existing) {
25713
+ let connected = false;
25603
25714
  try {
25604
25715
  await accessToken(dir, key);
25605
25716
  await updateState(dir, (state) => {
@@ -25609,10 +25720,13 @@ async function joinCommand(args, env) {
25609
25720
  s.pid = own2.pid ?? s.pid;
25610
25721
  }
25611
25722
  });
25612
- ensureBridge(dir, run2, env);
25723
+ connected = true;
25724
+ } catch {
25725
+ }
25726
+ if (connected) {
25727
+ await ensureBridge(dir, run2, env);
25613
25728
  console.log(`This ${agentLabel(own2.agent)} session is on Beeline as @${existing.handle ?? existing.name}. Tags in its Rooms arrive here.`);
25614
25729
  return;
25615
- } catch {
25616
25730
  }
25617
25731
  }
25618
25732
  const taken = new Set(readState(dir).sessions.filter((s) => s.key !== key).map((s) => s.name));
@@ -25644,7 +25758,7 @@ async function joinCommand(args, env) {
25644
25758
  if (!resume && previous && previous.file !== file)
25645
25759
  rmSync6(previous.file, { force: true });
25646
25760
  const out = join11(dir, "bridge.log");
25647
- const child = spawn7(run2.node, [run2.bundle, "session", "finish-join", file], { detached: true, stdio: "ignore", env: { ...env, BEELINE_SESSION_BUNDLE: run2.bundle } });
25761
+ const child = spawn8(run2.node, [run2.bundle, "session", "finish-join", file], { detached: true, stdio: "ignore", env: { ...env, BEELINE_SESSION_BUNDLE: run2.bundle } });
25648
25762
  child.unref();
25649
25763
  console.log([
25650
25764
  `Show your person this link. They open it on any device (a phone works) and sign in with GitHub or Google:`,
@@ -25721,7 +25835,7 @@ async function finishJoinOwned(file, env) {
25721
25835
  changes.splice(prompt, 1);
25722
25836
  changes.push("Trusted only Beeline\u2019s SessionStart hook, pinned to its current Codex hash.");
25723
25837
  }
25724
- ensureBridge(dir, run2, env);
25838
+ await ensureBridge(dir, run2, env);
25725
25839
  const rooms = me.rooms.map((r) => r.name).slice(0, 5).join(", ");
25726
25840
  await announce(joined2, `Beeline: you joined as @${joined2.handle ?? joined2.name}${rooms ? ` in ${rooms}` : ""}. When someone tags you there, the message arrives here with the command that answers it.${changes.length ? `
25727
25841
  (${changes.join("; ")})` : ""}
@@ -25815,7 +25929,7 @@ async function session(args, env) {
25815
25929
  if (out)
25816
25930
  process.stdout.write(out + "\n");
25817
25931
  if (event === "session-start" && readState(dir).sessions.length)
25818
- ensureBridge(dir, runner(dir, env), env);
25932
+ await ensureBridge(dir, runner(dir, env), env);
25819
25933
  } catch {
25820
25934
  }
25821
25935
  return;
@@ -25878,14 +25992,14 @@ async function session(args, env) {
25878
25992
  throw new Error("Usage: usebeeline join | usebeeline session reply|read|tool|status|leave");
25879
25993
  }
25880
25994
  function readStdin(_limitMs) {
25881
- return new Promise((resolve12) => {
25995
+ return new Promise((resolve13) => {
25882
25996
  let text = "";
25883
25997
  process.stdin.setEncoding("utf8");
25884
25998
  process.stdin.on("data", (chunk) => {
25885
25999
  text += chunk;
25886
26000
  });
25887
26001
  process.stdin.on("end", () => {
25888
- resolve12(text);
26002
+ resolve13(text);
25889
26003
  });
25890
26004
  });
25891
26005
  }
@@ -25923,15 +26037,15 @@ var init_command = __esm({
25923
26037
  init_setup();
25924
26038
  init_store();
25925
26039
  init_kernel_lock();
25926
- finisherKey = (file) => "beeline-session-sign-in:" + resolve10(file);
26040
+ finisherKey = (file) => "beeline-session-sign-in:" + resolve11(file);
25927
26041
  VALUED = ["--as", "--room", "--reply-to", "--server", "--name", "--session", "--state", "--limit"];
25928
26042
  }
25929
26043
  });
25930
26044
 
25931
26045
  // apps/body/dist/recovery-cli.js
25932
- import { spawn as spawn8 } from "node:child_process";
26046
+ import { spawn as spawn9 } from "node:child_process";
25933
26047
  import { readFile as readFile5, readdir as readdir5, stat as stat3, unlink } from "node:fs/promises";
25934
- import { resolve as resolve11 } from "node:path";
26048
+ import { resolve as resolve12 } from "node:path";
25935
26049
 
25936
26050
  // apps/body/dist/recovery.js
25937
26051
  import { readFile as readFile4, readdir as readdir4, stat } from "node:fs/promises";
@@ -26448,18 +26562,18 @@ async function main() {
26448
26562
  if (args[i] === "--manifest-url" && !args[++i])
26449
26563
  throw new Error("--manifest-url requires a URL");
26450
26564
  }
26451
- const stateRoot2 = process.env.XDG_STATE_HOME || resolve11(process.env.HOME || "", ".local/state");
26565
+ const stateRoot2 = process.env.XDG_STATE_HOME || resolve12(process.env.HOME || "", ".local/state");
26452
26566
  if (args.includes("--status")) {
26453
26567
  const [native, helper] = await Promise.all([
26454
26568
  nativeHelperStatus(),
26455
26569
  requestMachine(stateRoot2, { operation: "status" }, () => true, 2e3).catch(() => void 0)
26456
26570
  ]);
26457
- const root = resolve11(stateRoot2, "beeline/agents");
26571
+ const root = resolve12(stateRoot2, "beeline/agents");
26458
26572
  const agents = await Promise.all((await readdir5(root).catch(() => [])).filter((id) => /^[0-9a-f]{64}$/.test(id)).map(async (id) => ({
26459
26573
  agentId: id,
26460
- enabled: !await stat3(resolve11(root, id, "stopped")).then(() => true, () => false),
26574
+ enabled: !await stat3(resolve12(root, id, "stopped")).then(() => true, () => false),
26461
26575
  ...helper?.agents[id] ?? { state: "not hosted" },
26462
- validRecord: await readFile5(resolve11(root, id, "runtime.json"), "utf8").then((raw) => Boolean(JSON.parse(raw).agent)).catch(() => false)
26576
+ validRecord: await readFile5(resolve12(root, id, "runtime.json"), "utf8").then((raw) => Boolean(JSON.parse(raw).agent)).catch(() => false)
26463
26577
  })));
26464
26578
  console.log(JSON.stringify({
26465
26579
  native,
@@ -26508,7 +26622,7 @@ async function main() {
26508
26622
  console.log(`[beeline] executing release ${status.loadedRelease}; helper ${status.pid}; every enabled agent serving`);
26509
26623
  return;
26510
26624
  }
26511
- const stateRoot = process.env.XDG_STATE_HOME || resolve11(process.env.HOME || "", ".local/state");
26625
+ const stateRoot = process.env.XDG_STATE_HOME || resolve12(process.env.HOME || "", ".local/state");
26512
26626
  let selectedRelease;
26513
26627
  if (command2 === "start") {
26514
26628
  for (let i = 1; i < args.length; i++) {
@@ -26523,13 +26637,13 @@ async function main() {
26523
26637
  const requested = agentFlag >= 0 ? args[agentFlag + 1] : args[1] && !args[1].startsWith("--") ? args[1] : void 0;
26524
26638
  if (agentFlag >= 0 && !requested)
26525
26639
  throw new Error("--agent requires an agent public key");
26526
- const agentRoot = resolve11(stateRoot, "beeline/agents");
26640
+ const agentRoot = resolve12(stateRoot, "beeline/agents");
26527
26641
  const ids = (await readdir5(agentRoot).catch(() => [])).filter((id) => /^[0-9a-f]{64}$/.test(id));
26528
26642
  const selected = requested ? ids.filter((id) => id.startsWith(requested)) : args.includes("--all") ? ids : [];
26529
26643
  if (requested && selected.length !== 1)
26530
26644
  throw new Error(`no unique paired agent matches ${requested}`);
26531
26645
  for (const id of selected)
26532
- await unlink(resolve11(agentRoot, id, "stopped")).catch((error) => {
26646
+ await unlink(resolve12(agentRoot, id, "stopped")).catch((error) => {
26533
26647
  if (error.code !== "ENOENT")
26534
26648
  throw error;
26535
26649
  });
@@ -26553,7 +26667,7 @@ async function main() {
26553
26667
  const entry = await resolveBundleEntrypoint(layout.libDir);
26554
26668
  if (!entry)
26555
26669
  throw new Error("no installed Beeline body; run npx usebeeline connect");
26556
- const child = spawn8(process.execPath, [entry, ...args], {
26670
+ const child = spawn9(process.execPath, [entry, ...args], {
26557
26671
  env: {
26558
26672
  ...process.env,
26559
26673
  BEELINE_LIB_DIR: layout.libDir,
@@ -26571,7 +26685,7 @@ async function convergeDependencies(layout, _deadlineAt) {
26571
26685
  if (!entry)
26572
26686
  throw new Error("dependency phase has no selected body");
26573
26687
  await new Promise((done, reject) => {
26574
- const child = spawn8(process.execPath, [entry, "converge-dependencies"], {
26688
+ const child = spawn9(process.execPath, [entry, "converge-dependencies"], {
26575
26689
  env: { ...process.env, BEELINE_LIB_DIR: layout.libDir, BEELINE_INTERNAL_RECOVERY: "1" },
26576
26690
  stdio: "inherit"
26577
26691
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usebeeline",
3
- "version": "0.1.181",
3
+ "version": "0.1.183",
4
4
  "description": "Connect an AI coding agent to Beeline with one command.",
5
5
  "homepage": "https://usebeeline.app",
6
6
  "bugs": {