@open-bus/cli 0.43.2 → 0.43.3

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/index.js +562 -271
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -66,7 +66,7 @@ ${neutralize(a.text)}
66
66
  };
67
67
  }
68
68
  function inject(a) {
69
- return new Promise((resolve6, reject) => {
69
+ return new Promise((resolve7, reject) => {
70
70
  const sock = connect(a.socketPath);
71
71
  let connected = false;
72
72
  const fail = (e) => {
@@ -90,7 +90,7 @@ function inject(a) {
90
90
  sock.once("finish", () => {
91
91
  clearTimeout(timer);
92
92
  sock.destroy();
93
- resolve6();
93
+ resolve7();
94
94
  });
95
95
  sock.end(`${JSON.stringify(frameOf(a))}
96
96
  `);
@@ -4653,7 +4653,7 @@ function isRef(value) {
4653
4653
  function cloneIssues(issues) {
4654
4654
  return issues.map((iss) => iss.path ? { ...iss, path: iss.path.slice() } : { ...iss });
4655
4655
  }
4656
- function isRecursive(inst, stack, resolve6) {
4656
+ function isRecursive(inst, stack, resolve7) {
4657
4657
  const cached2 = recursive.get(inst);
4658
4658
  if (cached2 !== void 0)
4659
4659
  return cached2 ? PROVEN : NONE;
@@ -4663,7 +4663,7 @@ function isRecursive(inst, stack, resolve6) {
4663
4663
  let result = NONE;
4664
4664
  const check2 = (child) => {
4665
4665
  if (result !== PROVEN && child?._zod) {
4666
- const answer = isRecursive(child, stack, resolve6);
4666
+ const answer = isRecursive(child, stack, resolve7);
4667
4667
  if (answer > result)
4668
4668
  result = answer;
4669
4669
  }
@@ -4674,7 +4674,7 @@ function isRecursive(inst, stack, resolve6) {
4674
4674
  const desc = Object.getOwnPropertyDescriptor(sh, key);
4675
4675
  if (spread && !desc.enumerable)
4676
4676
  continue;
4677
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve6) : NONE;
4677
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve7) : NONE;
4678
4678
  if (child > answer)
4679
4679
  answer = child;
4680
4680
  }
@@ -4738,7 +4738,7 @@ function isRecursive(inst, stack, resolve6) {
4738
4738
  break;
4739
4739
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
4740
4740
  case "lazy": {
4741
- const inner = def._cachedInner ?? (resolve6 ? inst._zod.innerType : void 0);
4741
+ const inner = def._cachedInner ?? (resolve7 ? inst._zod.innerType : void 0);
4742
4742
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
4743
4743
  break;
4744
4744
  }
@@ -21640,8 +21640,8 @@ var init_lines = __esm({
21640
21640
  import { connect as connect2 } from "node:net";
21641
21641
  async function connectDaemon(opts) {
21642
21642
  const sock = connect2(opts.path);
21643
- await new Promise((resolve6, reject) => {
21644
- sock.once("connect", resolve6);
21643
+ await new Promise((resolve7, reject) => {
21644
+ sock.once("connect", resolve7);
21645
21645
  sock.once("error", reject);
21646
21646
  });
21647
21647
  const decoder = new LineDecoder();
@@ -21701,8 +21701,8 @@ async function connectDaemon(opts) {
21701
21701
  sock.on("error", (e) => failAll(e));
21702
21702
  sock.on("close", () => failAll(new Error("daemon connection closed")));
21703
21703
  let timer;
21704
- const welcomeRaw = await new Promise((resolve6, reject) => {
21705
- waiters.push({ resolve: resolve6, reject });
21704
+ const welcomeRaw = await new Promise((resolve7, reject) => {
21705
+ waiters.push({ resolve: resolve7, reject });
21706
21706
  timer = setTimeout(() => {
21707
21707
  reject(new Error("daemon did not answer hello"));
21708
21708
  sock.destroy();
@@ -21724,7 +21724,7 @@ async function connectDaemon(opts) {
21724
21724
  if (state === "closed")
21725
21725
  return Promise.reject(new Error("daemon connection closed"));
21726
21726
  const id = partial2.id ?? String(++seq);
21727
- return new Promise((resolve6, reject) => {
21727
+ return new Promise((resolve7, reject) => {
21728
21728
  const ms = opts.requestTimeoutMs ?? 2e4;
21729
21729
  const timer2 = setTimeout(() => {
21730
21730
  if (pending.delete(id))
@@ -21739,7 +21739,7 @@ async function connectDaemon(opts) {
21739
21739
  clearTimeout(timer2);
21740
21740
  f(...a);
21741
21741
  };
21742
- pending.set(id, { resolve: done(resolve6), reject: done(reject) });
21742
+ pending.set(id, { resolve: done(resolve7), reject: done(reject) });
21743
21743
  sock.write(`${JSON.stringify({ v: 1, ...partial2, id })}
21744
21744
  `);
21745
21745
  });
@@ -21763,7 +21763,7 @@ async function connectDaemon(opts) {
21763
21763
  };
21764
21764
  }
21765
21765
  function daemonStatus(opts) {
21766
- return new Promise((resolve6, reject) => {
21766
+ return new Promise((resolve7, reject) => {
21767
21767
  const sock = connect2(opts.path);
21768
21768
  const decoder = new LineDecoder();
21769
21769
  const done = (f) => {
@@ -21791,7 +21791,7 @@ function daemonStatus(opts) {
21791
21791
  try {
21792
21792
  for (const raw of decoder.push(chunk)) {
21793
21793
  const f = DaemonFrame.parse(raw);
21794
- if (f.type === "status") return done(() => resolve6(f));
21794
+ if (f.type === "status") return done(() => resolve7(f));
21795
21795
  if (f.type === "error")
21796
21796
  return done(
21797
21797
  () => reject(new Error(`daemon refused status: ${f.message}`))
@@ -21990,13 +21990,13 @@ async function clearStale(path) {
21990
21990
  code: "ENOTSOCK"
21991
21991
  });
21992
21992
  }
21993
- const live = await new Promise((resolve6) => {
21993
+ const live = await new Promise((resolve7) => {
21994
21994
  const probe = connect3(path);
21995
21995
  probe.once("connect", () => {
21996
21996
  probe.destroy();
21997
- resolve6(true);
21997
+ resolve7(true);
21998
21998
  });
21999
- probe.once("error", () => resolve6(false));
21999
+ probe.once("error", () => resolve7(false));
22000
22000
  });
22001
22001
  if (live) {
22002
22002
  throw Object.assign(new Error(`daemon already listening on ${path}`), {
@@ -22016,16 +22016,16 @@ async function serveDaemon(opts) {
22016
22016
  sock.once("close", () => sockets.delete(sock));
22017
22017
  handle(sock, opts);
22018
22018
  });
22019
- await new Promise((resolve6, reject) => {
22019
+ await new Promise((resolve7, reject) => {
22020
22020
  server3.once("error", reject);
22021
- server3.listen(opts.path, () => resolve6());
22021
+ server3.listen(opts.path, () => resolve7());
22022
22022
  });
22023
22023
  chmodSync(opts.path, 384);
22024
22024
  const st = statSync(opts.path);
22025
22025
  const mode = st.mode & 511;
22026
22026
  return {
22027
22027
  mode,
22028
- close: () => new Promise((resolve6) => {
22028
+ close: () => new Promise((resolve7) => {
22029
22029
  for (const s of sockets) s.destroy();
22030
22030
  let parked;
22031
22031
  try {
@@ -22043,7 +22043,7 @@ async function serveDaemon(opts) {
22043
22043
  } catch {
22044
22044
  }
22045
22045
  }
22046
- resolve6();
22046
+ resolve7();
22047
22047
  });
22048
22048
  })
22049
22049
  };
@@ -24789,7 +24789,7 @@ var require_websocket = __commonJS({
24789
24789
  var http = __require("http");
24790
24790
  var net = __require("net");
24791
24791
  var tls = __require("tls");
24792
- var { randomBytes: randomBytes3, createHash: createHash5 } = __require("crypto");
24792
+ var { randomBytes: randomBytes4, createHash: createHash5 } = __require("crypto");
24793
24793
  var { Duplex, Readable } = __require("stream");
24794
24794
  var { URL: URL2 } = __require("url");
24795
24795
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -25340,7 +25340,7 @@ var require_websocket = __commonJS({
25340
25340
  }
25341
25341
  }
25342
25342
  const defaultPort = isSecure ? 443 : 80;
25343
- const key = randomBytes3(16).toString("base64");
25343
+ const key = randomBytes4(16).toString("base64");
25344
25344
  const request = isSecure ? https.request : http.request;
25345
25345
  const protocolSet = /* @__PURE__ */ new Set();
25346
25346
  let perMessageDeflate;
@@ -26235,12 +26235,12 @@ var require_websocket_server = __commonJS({
26235
26235
 
26236
26236
  // ../adapters/opencode/src/session.ts
26237
26237
  import { execFile as execFile3 } from "node:child_process";
26238
- import { isAbsolute as isAbsolute4 } from "node:path";
26238
+ import { isAbsolute as isAbsolute5 } from "node:path";
26239
26239
  import { promisify as promisify2 } from "node:util";
26240
26240
  function directoryOf(s) {
26241
26241
  const loc = s.location;
26242
26242
  const dir = s.directory ?? loc?.directory;
26243
- return typeof dir === "string" && isAbsolute4(dir) ? dir : null;
26243
+ return typeof dir === "string" && isAbsolute5(dir) ? dir : null;
26244
26244
  }
26245
26245
  async function rootSession(sessionId, deps) {
26246
26246
  const cache = deps.cache ?? ROOTS;
@@ -28941,7 +28941,7 @@ var init_protocol2 = __esm({
28941
28941
  return;
28942
28942
  }
28943
28943
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
28944
- await new Promise((resolve6) => setTimeout(resolve6, pollInterval));
28944
+ await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
28945
28945
  options?.signal?.throwIfAborted();
28946
28946
  }
28947
28947
  } catch (error62) {
@@ -28958,7 +28958,7 @@ var init_protocol2 = __esm({
28958
28958
  */
28959
28959
  request(request, resultSchema, options) {
28960
28960
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
28961
- return new Promise((resolve6, reject) => {
28961
+ return new Promise((resolve7, reject) => {
28962
28962
  const earlyReject = (error62) => {
28963
28963
  reject(error62);
28964
28964
  };
@@ -29036,7 +29036,7 @@ var init_protocol2 = __esm({
29036
29036
  if (!parseResult.success) {
29037
29037
  reject(parseResult.error);
29038
29038
  } else {
29039
- resolve6(parseResult.data);
29039
+ resolve7(parseResult.data);
29040
29040
  }
29041
29041
  } catch (error62) {
29042
29042
  reject(error62);
@@ -29298,12 +29298,12 @@ var init_protocol2 = __esm({
29298
29298
  }
29299
29299
  } catch {
29300
29300
  }
29301
- return new Promise((resolve6, reject) => {
29301
+ return new Promise((resolve7, reject) => {
29302
29302
  if (signal.aborted) {
29303
29303
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
29304
29304
  return;
29305
29305
  }
29306
- const timeoutId = setTimeout(resolve6, interval);
29306
+ const timeoutId = setTimeout(resolve7, interval);
29307
29307
  signal.addEventListener("abort", () => {
29308
29308
  clearTimeout(timeoutId);
29309
29309
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -32330,7 +32330,7 @@ var require_compile = __commonJS({
32330
32330
  const schOrFunc = root.refs[ref];
32331
32331
  if (schOrFunc)
32332
32332
  return schOrFunc;
32333
- let _sch = resolve6.call(this, root, ref);
32333
+ let _sch = resolve7.call(this, root, ref);
32334
32334
  if (_sch === void 0) {
32335
32335
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
32336
32336
  const { schemaId } = this.opts;
@@ -32357,7 +32357,7 @@ var require_compile = __commonJS({
32357
32357
  function sameSchemaEnv(s1, s2) {
32358
32358
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
32359
32359
  }
32360
- function resolve6(root, ref) {
32360
+ function resolve7(root, ref) {
32361
32361
  let sch;
32362
32362
  while (typeof (sch = this.refs[ref]) == "string")
32363
32363
  ref = sch;
@@ -33221,7 +33221,7 @@ var require_fast_uri = __commonJS({
33221
33221
  }
33222
33222
  return uri;
33223
33223
  }
33224
- function resolve6(baseURI, relativeURI, options) {
33224
+ function resolve7(baseURI, relativeURI, options) {
33225
33225
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
33226
33226
  const {
33227
33227
  parsed: baseParsed,
@@ -33612,7 +33612,7 @@ var require_fast_uri = __commonJS({
33612
33612
  var fastUri = {
33613
33613
  SCHEMES,
33614
33614
  normalize,
33615
- resolve: resolve6,
33615
+ resolve: resolve7,
33616
33616
  resolveComponent,
33617
33617
  equal,
33618
33618
  serialize,
@@ -37418,12 +37418,12 @@ var init_stdio2 = __esm({
37418
37418
  this.onclose?.();
37419
37419
  }
37420
37420
  send(message) {
37421
- return new Promise((resolve6) => {
37421
+ return new Promise((resolve7) => {
37422
37422
  const json3 = serializeMessage(message);
37423
37423
  if (this._stdout.write(json3)) {
37424
- resolve6();
37424
+ resolve7();
37425
37425
  } else {
37426
- this._stdout.once("drain", resolve6);
37426
+ this._stdout.once("drain", resolve7);
37427
37427
  }
37428
37428
  });
37429
37429
  }
@@ -37539,16 +37539,16 @@ var init_main2 = __esm({
37539
37539
  });
37540
37540
 
37541
37541
  // src/main.ts
37542
- import { resolve as resolve5 } from "node:path";
37542
+ import { resolve as resolve6 } from "node:path";
37543
37543
 
37544
37544
  // src/commands/daemon.ts
37545
37545
  import { existsSync as existsSync3 } from "node:fs";
37546
- import { join as join11 } from "node:path";
37546
+ import { join as join12 } from "node:path";
37547
37547
 
37548
37548
  // ../daemon/src/index.ts
37549
37549
  init_src2();
37550
- import { lstatSync as lstatSync4, writeFileSync as writeFileSync3 } from "node:fs";
37551
- import { basename as basename4, isAbsolute as isAbsolute2, join as join8 } from "node:path";
37550
+ import { lstatSync as lstatSync5, writeFileSync as writeFileSync3 } from "node:fs";
37551
+ import { basename as basename4, isAbsolute as isAbsolute3, join as join9 } from "node:path";
37552
37552
 
37553
37553
  // ../adapters/opencode/src/version.ts
37554
37554
  var MIN_PROMPT_ID_VERSION = "2.0.0";
@@ -38502,67 +38502,187 @@ function defaultBackoff(attempt) {
38502
38502
  // ../daemon/src/namespace.ts
38503
38503
  init_dist();
38504
38504
  import { execFileSync as execFileSync3 } from "node:child_process";
38505
+ import { realpathSync as realpathSync3 } from "node:fs";
38506
+ import { basename as basename3, dirname as dirname4, join as join7, resolve as resolve2 } from "node:path";
38507
+
38508
+ // ../daemon/src/global.ts
38509
+ import { randomBytes } from "node:crypto";
38510
+ import {
38511
+ chmodSync as chmodSync3,
38512
+ closeSync as closeSync2,
38513
+ lstatSync as lstatSync3,
38514
+ mkdirSync as mkdirSync4,
38515
+ openSync as openSync2,
38516
+ realpathSync as realpathSync2,
38517
+ renameSync as renameSync2,
38518
+ statSync as statSync5,
38519
+ unlinkSync,
38520
+ writeSync
38521
+ } from "node:fs";
38522
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join6, sep } from "node:path";
38523
+
38524
+ // ../daemon/src/own-file.ts
38505
38525
  import {
38506
38526
  closeSync,
38507
38527
  constants,
38508
38528
  fstatSync,
38509
38529
  openSync,
38510
- readFileSync as readFileSync5,
38511
- realpathSync as realpathSync2
38530
+ readFileSync as readFileSync5
38512
38531
  } from "node:fs";
38513
- import { basename as basename3, dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
38532
+ function readOwnFile(file2, uid = process.getuid?.()) {
38533
+ let fd;
38534
+ try {
38535
+ fd = openSync(
38536
+ file2,
38537
+ constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0)
38538
+ );
38539
+ } catch (e) {
38540
+ const code2 = e.code;
38541
+ if (code2 === "ENOENT" || code2 === "ENOTDIR") return { state: "none" };
38542
+ return {
38543
+ state: "unsafe",
38544
+ why: code2 === "ELOOP" ? "is a symlink" : `cannot be read (${code2})`
38545
+ };
38546
+ }
38547
+ try {
38548
+ const st = fstatSync(fd);
38549
+ if (!st.isFile()) return { state: "unsafe", why: "is not a regular file" };
38550
+ if (uid !== void 0 && st.uid !== uid)
38551
+ return { state: "unsafe", why: "belongs to another user" };
38552
+ if (st.mode & 18)
38553
+ return { state: "unsafe", why: "is writable by others" };
38554
+ return { state: "ok", text: readFileSync5(fd, "utf8") };
38555
+ } catch (e) {
38556
+ return {
38557
+ state: "unsafe",
38558
+ why: `cannot be read (${e.code ?? String(e)})`
38559
+ };
38560
+ } finally {
38561
+ closeSync(fd);
38562
+ }
38563
+ }
38564
+
38565
+ // ../daemon/src/global.ts
38566
+ var globalFile = (h = home()) => join6(h, "global.json");
38567
+ var canonicalPath = (path) => realpathSync2.native(path);
38568
+ function readGlobalDirs(file2 = globalFile()) {
38569
+ const own2 = readOwnFile(file2);
38570
+ if (own2.state === "none") return { dirs: [] };
38571
+ if (own2.state === "unsafe") return { dirs: [], error: own2.why };
38572
+ try {
38573
+ const raw = JSON.parse(own2.text);
38574
+ const dirs = raw?.dirs;
38575
+ if (!Array.isArray(raw) && Array.isArray(dirs) && dirs.every((d) => typeof d === "string" && isAbsolute2(d)))
38576
+ return { dirs };
38577
+ } catch {
38578
+ }
38579
+ return { dirs: [], error: "is not valid JSON" };
38580
+ }
38581
+ var idOf = (path, follow = true) => {
38582
+ try {
38583
+ const st = follow ? statSync5(path) : lstatSync3(path);
38584
+ return st.isDirectory() ? `${st.dev}:${st.ino}` : void 0;
38585
+ } catch {
38586
+ return void 0;
38587
+ }
38588
+ };
38589
+ var loose = (p) => p.normalize("NFC").toLowerCase();
38590
+ function isGlobalDir(dir, dirs, onStale) {
38591
+ let real2;
38592
+ try {
38593
+ real2 = realpathSync2(dir);
38594
+ } catch {
38595
+ return false;
38596
+ }
38597
+ const near = loose(real2);
38598
+ const ids = /* @__PURE__ */ new Set();
38599
+ for (const entry of dirs) {
38600
+ const e = loose(entry);
38601
+ const prefix = e.endsWith(sep) ? e : `${e}${sep}`;
38602
+ if (near !== e && !near.startsWith(prefix)) continue;
38603
+ let still;
38604
+ try {
38605
+ still = realpathSync2.native(entry);
38606
+ } catch {
38607
+ }
38608
+ if (still !== entry) {
38609
+ if (still !== void 0) onStale?.(entry);
38610
+ continue;
38611
+ }
38612
+ const id = idOf(entry, false);
38613
+ if (id !== void 0) ids.add(id);
38614
+ }
38615
+ if (ids.size === 0) return false;
38616
+ for (let d = real2; ; d = dirname3(d)) {
38617
+ const id = idOf(d);
38618
+ if (id !== void 0 && ids.has(id)) return true;
38619
+ if (dirname3(d) === d) return false;
38620
+ }
38621
+ }
38622
+ function sameDir(entry, dir) {
38623
+ try {
38624
+ if (realpathSync2.native(entry) !== entry) return false;
38625
+ } catch {
38626
+ return false;
38627
+ }
38628
+ const id = idOf(entry, false);
38629
+ return id !== void 0 && id === idOf(dir);
38630
+ }
38631
+ function writeGlobalDirs(dirs, h = home()) {
38632
+ mkdirSync4(h, { recursive: true, mode: 448 });
38633
+ chmodSync3(h, 448);
38634
+ const tmp = join6(h, `.global.json.${randomBytes(8).toString("hex")}.tmp`);
38635
+ const fd = openSync2(tmp, "wx", 384);
38636
+ try {
38637
+ writeSync(fd, `${JSON.stringify({ dirs }, null, 2)}
38638
+ `);
38639
+ } catch (e) {
38640
+ closeSync2(fd);
38641
+ unlinkSync(tmp);
38642
+ throw e;
38643
+ }
38644
+ closeSync2(fd);
38645
+ try {
38646
+ chmodSync3(tmp, 384);
38647
+ renameSync2(tmp, globalFile(h));
38648
+ } catch (e) {
38649
+ unlinkSync(tmp);
38650
+ throw e;
38651
+ }
38652
+ }
38653
+
38654
+ // ../daemon/src/namespace.ts
38514
38655
  var warned = /* @__PURE__ */ new Set();
38656
+ var once = (deps, key, msg) => {
38657
+ if (warned.has(key)) return;
38658
+ warned.add(key);
38659
+ deps.log?.(msg);
38660
+ };
38515
38661
  function resolveNamespace(start, deps = {}) {
38516
38662
  let cwd;
38663
+ let missing2 = false;
38517
38664
  try {
38518
- cwd = realpathSync2(start);
38665
+ cwd = realpathSync3(start);
38519
38666
  } catch (e) {
38520
38667
  if (!deps.allowMissing) throw e;
38521
38668
  cwd = resolve2(start);
38669
+ missing2 = true;
38522
38670
  if (!warned.has(cwd)) {
38523
38671
  warned.add(cwd);
38524
38672
  deps.log?.(`${cwd} does not resolve; using it as given`);
38525
38673
  }
38526
38674
  }
38527
- const uid = deps.uid ?? process.getuid?.();
38528
- const configs = [];
38529
- for (let dir = cwd; ; dir = dirname3(dir)) {
38530
- const file2 = join6(dir, CONFIG_FILE);
38531
- let text3;
38532
- let fd;
38533
- try {
38534
- fd = openSync(
38535
- file2,
38536
- constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0)
38675
+ const { cfg, asked } = readConfigs(cwd, deps);
38676
+ const global2 = !missing2 && allowlisted(cwd, deps);
38677
+ if (!global2)
38678
+ for (const file2 of asked)
38679
+ once(
38680
+ deps,
38681
+ `global:${file2}`,
38682
+ `ignoring global in ${file2}: only \`npx @open-bus/cli global add\` makes a directory global`
38537
38683
  );
38538
- const st = fstatSync(fd);
38539
- if (uid !== void 0 && st.uid !== uid || st.mode & 18) {
38540
- if (!warned.has(file2)) {
38541
- warned.add(file2);
38542
- deps.log?.(
38543
- `ignoring ${file2}: not owned by you or writable by others`
38544
- );
38545
- }
38546
- } else if (st.isFile()) text3 = readFileSync5(fd, "utf8");
38547
- } catch {
38548
- } finally {
38549
- if (fd !== void 0) closeSync(fd);
38550
- }
38551
- if (text3 !== void 0) {
38552
- let parsed;
38553
- try {
38554
- parsed = OpenBusConfigSchema.safeParse(JSON.parse(text3));
38555
- } catch {
38556
- }
38557
- if (parsed?.success) configs.push(parsed.data);
38558
- else deps.log?.(`ignoring invalid ${file2}`);
38559
- }
38560
- if (dirname3(dir) === dir) break;
38561
- }
38562
- const cfg = mergeConfigs(configs);
38563
- const global = cfg.global === true;
38564
38684
  if (cfg.namespace)
38565
- return { namespace: cfg.namespace, global, source: "config" };
38685
+ return { namespace: cfg.namespace, global: global2, source: "config" };
38566
38686
  const remoteUrl = (deps.gitRemote ?? gitRemote)(cwd);
38567
38687
  const root = (deps.gitRoot ?? gitRoot)(cwd);
38568
38688
  const namespace = namespaceFrom({
@@ -38571,7 +38691,62 @@ function resolveNamespace(start, deps = {}) {
38571
38691
  cwd
38572
38692
  });
38573
38693
  const source = remoteUrl && normalizeRemote(remoteUrl) ? "git" : root ? "dir" : "cwd";
38574
- return { namespace, global, source };
38694
+ return { namespace, global: global2, source };
38695
+ }
38696
+ function allowlisted(cwd, deps) {
38697
+ const file2 = deps.globalFile ?? globalFile();
38698
+ const list = readGlobalDirs(file2);
38699
+ if (list.error)
38700
+ once(
38701
+ deps,
38702
+ `allowlist:${file2}:${list.error}`,
38703
+ `${file2} ${list.error}: no directory is global`
38704
+ );
38705
+ if (list.dirs.length === 0) return false;
38706
+ try {
38707
+ return isGlobalDir(
38708
+ cwd,
38709
+ list.dirs,
38710
+ (entry) => once(
38711
+ deps,
38712
+ `stale:${file2}:${entry}`,
38713
+ `ignoring ${entry} in ${file2}: its path is no longer real (a symlink now stands in it)`
38714
+ )
38715
+ );
38716
+ } catch {
38717
+ return false;
38718
+ }
38719
+ }
38720
+ function readConfigs(cwd, deps) {
38721
+ const uid = deps.uid ?? process.getuid?.();
38722
+ const configs = [];
38723
+ const asked = [];
38724
+ for (let dir = cwd; ; dir = dirname4(dir)) {
38725
+ const file2 = join7(dir, CONFIG_FILE);
38726
+ const own2 = readOwnFile(file2, uid);
38727
+ if (own2.state === "unsafe")
38728
+ once(deps, file2, `ignoring ${file2}: it ${own2.why}`);
38729
+ if (own2.state === "ok") {
38730
+ let parsed;
38731
+ try {
38732
+ parsed = OpenBusConfigSchema.safeParse(JSON.parse(own2.text));
38733
+ } catch {
38734
+ }
38735
+ if (parsed?.success) {
38736
+ configs.push(parsed.data);
38737
+ if (parsed.data.global === true) asked.push(file2);
38738
+ } else deps.log?.(`ignoring invalid ${file2}`);
38739
+ }
38740
+ if (dirname4(dir) === dir) break;
38741
+ }
38742
+ return { cfg: mergeConfigs(configs), asked };
38743
+ }
38744
+ function nearestConfig(dir, deps = {}) {
38745
+ try {
38746
+ return readConfigs(realpathSync3(dir), deps).cfg;
38747
+ } catch {
38748
+ return {};
38749
+ }
38575
38750
  }
38576
38751
  var git = (cwd, args) => {
38577
38752
  try {
@@ -38961,9 +39136,9 @@ function routeLocal(frame, hello, reply, ctx) {
38961
39136
  init_src();
38962
39137
  init_dist();
38963
39138
  import {
38964
- chmodSync as chmodSync3,
39139
+ chmodSync as chmodSync4,
38965
39140
  readFileSync as readFileSync6,
38966
- renameSync as renameSync2,
39141
+ renameSync as renameSync3,
38967
39142
  rmSync as rmSync2,
38968
39143
  writeFileSync
38969
39144
  } from "node:fs";
@@ -39143,7 +39318,7 @@ var SentStore = class {
39143
39318
  outcome,
39144
39319
  delivered,
39145
39320
  late: late2,
39146
- shown,
39321
+ shown: shown2,
39147
39322
  native
39148
39323
  } = e;
39149
39324
  this.#all.set(id, {
@@ -39161,7 +39336,7 @@ var SentStore = class {
39161
39336
  } : {},
39162
39337
  ...delivered ? { delivered } : {},
39163
39338
  ...delivered && late2 ? { late: late2 } : {},
39164
- ...delivered && late2 && shown ? { shown } : {},
39339
+ ...delivered && late2 && shown2 ? { shown: shown2 } : {},
39165
39340
  ...native ? { native } : {}
39166
39341
  });
39167
39342
  }
@@ -39187,8 +39362,8 @@ var SentStore = class {
39187
39362
  mode: 384,
39188
39363
  flag: "wx"
39189
39364
  });
39190
- chmodSync3(tmp, 384);
39191
- renameSync2(tmp, this.file);
39365
+ chmodSync4(tmp, 384);
39366
+ renameSync3(tmp, this.file);
39192
39367
  } catch (e) {
39193
39368
  this.#log?.(
39194
39369
  `sent file write failed: ${e instanceof Error ? e.message : String(e)}`
@@ -39303,12 +39478,12 @@ var Receipts = class {
39303
39478
  this.#waiting.delete(msgId);
39304
39479
  return Promise.resolve(w.final);
39305
39480
  }
39306
- return new Promise((resolve6) => {
39481
+ return new Promise((resolve7) => {
39307
39482
  const cancel = this.#after(ms, () => w.done?.(void 0));
39308
39483
  w.done = (f) => {
39309
39484
  cancel();
39310
39485
  this.#waiting.delete(msgId);
39311
- resolve6(f);
39486
+ resolve7(f);
39312
39487
  };
39313
39488
  });
39314
39489
  }
@@ -39363,13 +39538,13 @@ var Receipts = class {
39363
39538
  init_src2();
39364
39539
  init_dist();
39365
39540
  import { randomUUID } from "node:crypto";
39366
- import { chmodSync as chmodSync5, lstatSync as lstatSync3, mkdirSync as mkdirSync4, rmSync as rmSync3 } from "node:fs";
39541
+ import { chmodSync as chmodSync6, lstatSync as lstatSync4, mkdirSync as mkdirSync5, rmSync as rmSync3 } from "node:fs";
39367
39542
  import { createServer as createServer2 } from "node:net";
39368
- import { dirname as dirname4, join as join7 } from "node:path";
39543
+ import { dirname as dirname5, join as join8 } from "node:path";
39369
39544
  import { createInterface } from "node:readline";
39370
39545
 
39371
39546
  // ../daemon/src/transports/held.ts
39372
- import { chmodSync as chmodSync4, readFileSync as readFileSync7, renameSync as renameSync3, writeFileSync as writeFileSync2 } from "node:fs";
39547
+ import { chmodSync as chmodSync5, readFileSync as readFileSync7, renameSync as renameSync4, writeFileSync as writeFileSync2 } from "node:fs";
39373
39548
  var HeldStore = class {
39374
39549
  constructor(file2, opts = {}) {
39375
39550
  this.file = file2;
@@ -39408,8 +39583,8 @@ var HeldStore = class {
39408
39583
  #write(all) {
39409
39584
  const tmp = `${this.file}.${process.pid}.tmp`;
39410
39585
  writeFileSync2(tmp, JSON.stringify(all), { mode: 384 });
39411
- chmodSync4(tmp, 384);
39412
- renameSync3(tmp, this.file);
39586
+ chmodSync5(tmp, 384);
39587
+ renameSync4(tmp, this.file);
39413
39588
  }
39414
39589
  };
39415
39590
 
@@ -39427,7 +39602,7 @@ function unsafeClaudeSocket(path) {
39427
39602
  const uid = process.getuid?.();
39428
39603
  let sock;
39429
39604
  try {
39430
- sock = lstatSync3(path);
39605
+ sock = lstatSync4(path);
39431
39606
  } catch (e) {
39432
39607
  if (e.code === "ENOENT") return null;
39433
39608
  return `${path} cannot be checked (${e.code ?? String(e)})`;
@@ -39435,8 +39610,8 @@ function unsafeClaudeSocket(path) {
39435
39610
  try {
39436
39611
  if (!sock.isSocket()) return `${path} is not a socket`;
39437
39612
  if (sock.uid !== uid) return `${path} belongs to another user`;
39438
- const dir = dirname4(path);
39439
- const st = lstatSync3(dir);
39613
+ const dir = dirname5(path);
39614
+ const st = lstatSync4(dir);
39440
39615
  if (!st.isDirectory()) return `${dir} is not a folder`;
39441
39616
  if (st.uid !== uid) return `${dir} belongs to another user`;
39442
39617
  if (st.mode & 18)
@@ -39455,7 +39630,7 @@ var ClaudeTransport = class {
39455
39630
  this.opts = opts;
39456
39631
  this.#held = opts.heldFile ? new HeldStore(opts.heldFile) : void 0;
39457
39632
  this.#injected = opts.heldFile ? new HeldStore(opts.heldFile.replace(/(\.json)?$/, ".injected.json")) : void 0;
39458
- const sample = join7(opts.socketsDir, "00000000.sock");
39633
+ const sample = join8(opts.socketsDir, "00000000.sock");
39459
39634
  if (Buffer.byteLength(sample) > MAX_SOCKET_PATH) {
39460
39635
  this.#disabled = `claude delivery disabled: return socket paths are too long for a unix socket (${Buffer.byteLength(sample)} > ${MAX_SOCKET_PATH} bytes under ${opts.socketsDir}); use a shorter OPENBUS_HOME`;
39461
39636
  opts.log?.(this.#disabled);
@@ -39564,22 +39739,22 @@ var ClaudeTransport = class {
39564
39739
  return { ok: false, reason: "closed", cause: st };
39565
39740
  }
39566
39741
  #waitFor(msgId, ms) {
39567
- return new Promise((resolve6) => {
39742
+ return new Promise((resolve7) => {
39568
39743
  const buffered = this.#buffered.get(msgId);
39569
39744
  if (buffered !== void 0) {
39570
39745
  this.#buffered.delete(msgId);
39571
- resolve6(buffered);
39746
+ resolve7(buffered);
39572
39747
  return;
39573
39748
  }
39574
39749
  const timer = setTimeout(() => {
39575
39750
  this.#waiting.delete(msgId);
39576
- resolve6(void 0);
39751
+ resolve7(void 0);
39577
39752
  }, ms);
39578
39753
  timer.unref();
39579
39754
  this.#waiting.set(msgId, (s) => {
39580
39755
  clearTimeout(timer);
39581
39756
  this.#waiting.delete(msgId);
39582
- resolve6(s);
39757
+ resolve7(s);
39583
39758
  });
39584
39759
  });
39585
39760
  }
@@ -39628,13 +39803,13 @@ var ClaudeTransport = class {
39628
39803
  return sink;
39629
39804
  }
39630
39805
  async #listen(key, agentRef, namespace, peerName, notice = false) {
39631
- const path = join7(this.opts.socketsDir, `${randomUUID().slice(0, 8)}.sock`);
39806
+ const path = join8(this.opts.socketsDir, `${randomUUID().slice(0, 8)}.sock`);
39632
39807
  if (this.opts.prepareDir) {
39633
39808
  const unsafe = this.opts.prepareDir(this.opts.socketsDir);
39634
39809
  if (unsafe) throw new UnsafeDir(unsafe);
39635
39810
  } else {
39636
- mkdirSync4(this.opts.socketsDir, { recursive: true, mode: 448 });
39637
- chmodSync5(this.opts.socketsDir, 448);
39811
+ mkdirSync5(this.opts.socketsDir, { recursive: true, mode: 448 });
39812
+ chmodSync6(this.opts.socketsDir, 448);
39638
39813
  }
39639
39814
  rmSync3(path, { force: true });
39640
39815
  const conns = /* @__PURE__ */ new Set();
@@ -39658,11 +39833,11 @@ var ClaudeTransport = class {
39658
39833
  );
39659
39834
  })
39660
39835
  };
39661
- await new Promise((resolve6, reject) => {
39836
+ await new Promise((resolve7, reject) => {
39662
39837
  sink.server.once("error", reject);
39663
- sink.server.listen(path, () => resolve6());
39838
+ sink.server.listen(path, () => resolve7());
39664
39839
  });
39665
- chmodSync5(path, 384);
39840
+ chmodSync6(path, 384);
39666
39841
  return sink;
39667
39842
  }
39668
39843
  /** Injects an OpenBus notice into the session, from the notice socket. */
@@ -39731,17 +39906,17 @@ async function shut(sink) {
39731
39906
  init_src();
39732
39907
  import { execFile } from "node:child_process";
39733
39908
  var START_ERRORS = /* @__PURE__ */ new Set(["ENOENT", "EACCES"]);
39734
- var execSpawn = (timeoutMs, maxBuffer = 1024 * 1024) => (cmd, args) => new Promise((resolve6, reject) => {
39909
+ var execSpawn = (timeoutMs, maxBuffer = 1024 * 1024) => (cmd, args) => new Promise((resolve7, reject) => {
39735
39910
  execFile(
39736
39911
  cmd,
39737
39912
  args,
39738
39913
  { timeout: timeoutMs, maxBuffer },
39739
39914
  (err, stdout, stderr) => {
39740
- if (!err) return resolve6({ code: 0, stdout, stderr });
39915
+ if (!err) return resolve7({ code: 0, stdout, stderr });
39741
39916
  const e = err;
39742
39917
  if (typeof e.code === "string" && START_ERRORS.has(e.code))
39743
39918
  return reject(err);
39744
- resolve6({
39919
+ resolve7({
39745
39920
  code: e.killed || typeof e.code !== "number" ? null : e.code,
39746
39921
  stdout,
39747
39922
  stderr
@@ -39856,18 +40031,18 @@ var PiTransport = class {
39856
40031
  });
39857
40032
  if (!pushed) return { ok: false, reason: "closed" };
39858
40033
  this.#forget(mail.msg_id);
39859
- return new Promise((resolve6) => {
40034
+ return new Promise((resolve7) => {
39860
40035
  const timer = setTimeout(() => {
39861
40036
  this.#waiting.delete(mail.msg_id);
39862
40037
  this.#remember(mail.msg_id, agent.ref);
39863
- resolve6({ ok: false, reason: "timeout" });
40038
+ resolve7({ ok: false, reason: "timeout" });
39864
40039
  }, this.opts.ackTimeoutMs ?? 1e4);
39865
40040
  timer.unref();
39866
40041
  this.#waiting.set(mail.msg_id, {
39867
40042
  ref: agent.ref,
39868
40043
  done: (o) => {
39869
40044
  clearTimeout(timer);
39870
- resolve6(o);
40045
+ resolve7(o);
39871
40046
  }
39872
40047
  });
39873
40048
  });
@@ -40024,7 +40199,7 @@ async function runDaemon(deps = {}) {
40024
40199
  log,
40025
40200
  promptIdSupported: () => promptIdSupported,
40026
40201
  uncertain: new HeldStore(
40027
- oc.uncertainFile ?? join8(home(), "opencode-uncertain.json")
40202
+ oc.uncertainFile ?? join9(home(), "opencode-uncertain.json")
40028
40203
  )
40029
40204
  });
40030
40205
  const pi = new PiTransport({
@@ -40036,7 +40211,7 @@ async function runDaemon(deps = {}) {
40036
40211
  },
40037
40212
  ackTimeoutMs: deps.pi?.ackTimeoutMs
40038
40213
  });
40039
- const sent = new SentStore(deps.sentFile ?? join8(home(), "sent.json"), {
40214
+ const sent = new SentStore(deps.sentFile ?? join9(home(), "sent.json"), {
40040
40215
  log
40041
40216
  });
40042
40217
  const receipts = new Receipts(sent, { after: deps.deliveredTimer });
@@ -40126,7 +40301,7 @@ async function runDaemon(deps = {}) {
40126
40301
  socketsDir: returnDir,
40127
40302
  // A deps.socketsDir is the caller's (tests); ours is re-checked before each bind.
40128
40303
  prepareDir: cl.socketsDir ? void 0 : (d) => prepareReturnDir(d),
40129
- heldFile: cl.heldFile ?? join8(home(), "claude-held.json"),
40304
+ heldFile: cl.heldFile ?? join9(home(), "claude-held.json"),
40130
40305
  statusWindowMs: cl.statusWindowMs,
40131
40306
  injectTimeoutMs: cl.injectTimeoutMs,
40132
40307
  log,
@@ -40167,7 +40342,7 @@ async function runDaemon(deps = {}) {
40167
40342
  continue;
40168
40343
  }
40169
40344
  if (prev && prev.pid === s.pid) continue;
40170
- if (!isAbsolute2(s.cwd)) continue;
40345
+ if (!isAbsolute3(s.cwd)) continue;
40171
40346
  let ns;
40172
40347
  try {
40173
40348
  ns = resolveNs(s.cwd, true);
@@ -40331,7 +40506,7 @@ async function runDaemon(deps = {}) {
40331
40506
  process.exitCode = 1;
40332
40507
  try {
40333
40508
  writeFileSync3(
40334
- deps.revokedFile ?? join8(home(), "revoked"),
40509
+ deps.revokedFile ?? join9(home(), "revoked"),
40335
40510
  revokedMarker(cfg.machine_token),
40336
40511
  { mode: 384 }
40337
40512
  );
@@ -40366,21 +40541,21 @@ async function runDaemon(deps = {}) {
40366
40541
  });
40367
40542
  const version2 = deps.version ?? process.env.OPENBUS_VERSION ?? "0.0.0";
40368
40543
  const hubRoster = (ref) => new Promise(
40369
- (resolve6) => {
40544
+ (resolve7) => {
40370
40545
  const id = pending.open(
40371
40546
  "status",
40372
- (f) => resolve6(f.type === "roster" ? f.agents : void 0)
40547
+ (f) => resolve7(f.type === "roster" ? f.agents : void 0)
40373
40548
  );
40374
40549
  const timer = setTimeout(() => {
40375
40550
  pending.cancel(id);
40376
40551
  hub.cancel(id);
40377
- resolve6(void 0);
40552
+ resolve7(void 0);
40378
40553
  }, deps.statusRosterMs ?? 1500);
40379
40554
  timer.unref();
40380
40555
  if (!hub.send({ v: 1, id, type: "list", from_ref: ref })) {
40381
40556
  clearTimeout(timer);
40382
40557
  pending.cancel(id);
40383
- resolve6(void 0);
40558
+ resolve7(void 0);
40384
40559
  }
40385
40560
  }
40386
40561
  );
@@ -40401,7 +40576,7 @@ async function runDaemon(deps = {}) {
40401
40576
  // this machine's open sessions are in (or only the cwd's).
40402
40577
  onStatus: async (req) => {
40403
40578
  let only;
40404
- if (req.cwd && isAbsolute2(req.cwd)) {
40579
+ if (req.cwd && isAbsolute3(req.cwd)) {
40405
40580
  try {
40406
40581
  only = resolveNs(req.cwd, true).namespace;
40407
40582
  } catch {
@@ -40489,7 +40664,7 @@ async function runDaemon(deps = {}) {
40489
40664
  };
40490
40665
  }
40491
40666
  const cwd = check2.cwd ?? hello.cwd;
40492
- if (!isAbsolute2(cwd)) return { error: "cwd must be absolute" };
40667
+ if (!isAbsolute3(cwd)) return { error: "cwd must be absolute" };
40493
40668
  let ns;
40494
40669
  try {
40495
40670
  ns = resolveNs(cwd, check2.cwd !== void 0);
@@ -40580,11 +40755,11 @@ async function runDaemon(deps = {}) {
40580
40755
  announceSessions();
40581
40756
  }
40582
40757
  }).catch(socketInUse);
40583
- const bound = lstatSync4(listenPath);
40758
+ const bound = lstatSync5(listenPath);
40584
40759
  const socketWatch = setInterval(() => {
40585
40760
  let now;
40586
40761
  try {
40587
- now = lstatSync4(listenPath);
40762
+ now = lstatSync5(listenPath);
40588
40763
  } catch {
40589
40764
  }
40590
40765
  if (now?.ino === bound.ino && now.dev === bound.dev) return;
@@ -40645,7 +40820,7 @@ async function runDaemon(deps = {}) {
40645
40820
  init_src2();
40646
40821
  init_src();
40647
40822
  import { execFileSync as execFileSync4, spawn as spawn2 } from "node:child_process";
40648
- import { closeSync as closeSync2, openSync as openSync2, readFileSync as readFileSync9 } from "node:fs";
40823
+ import { closeSync as closeSync3, openSync as openSync3, readFileSync as readFileSync9 } from "node:fs";
40649
40824
  import { homedir as homedir2, userInfo } from "node:os";
40650
40825
 
40651
40826
  // ../ui/src/tokens/terminal.ts
@@ -40937,18 +41112,21 @@ function copy(style) {
40937
41112
  fail(clip(message.split("\n")[0] ?? "", 3)),
40938
41113
  next("Run npx @open-bus/cli doctor to see why.")
40939
41114
  ],
40940
- // DRAFT (Design review): a SOCKET_PATH start failure, in place of `failed`.
41115
+ // A SOCKET_PATH start failure, in place of `failed`.
40941
41116
  socketPathFailed: (message) => [
40942
- fail("The daemon cannot listen on its socket"),
41117
+ fail("The daemon cannot listen on its socket."),
40943
41118
  next(p("muted", clip(message.split("\n")[0] ?? "", 3))),
40944
41119
  next("Run npx @open-bus/cli doctor to see why.")
40945
41120
  ],
40946
41121
  usage: (message) => [
40947
- fail(clip(message, 3)),
41122
+ // The parser's message, as a sentence.
41123
+ fail(clip(message.charAt(0).toUpperCase() + message.slice(1), 3)),
40948
41124
  next(
40949
41125
  "Run npx @open-bus/cli with install, login, daemon, status, logs, doctor,"
40950
41126
  ),
40951
- next("uninstall, mcp <claude|opencode|pi> or version.")
41127
+ next(
41128
+ "global add|rm|list, uninstall, mcp <claude|opencode|pi> or version."
41129
+ )
40952
41130
  ],
40953
41131
  skipped: (h, reason) => [
40954
41132
  warn(
@@ -41054,6 +41232,16 @@ function copy(style) {
41054
41232
  next(`Ask an admin to remove it (sudo rm -r ${clip(dir, 43)}),`),
41055
41233
  next("or set a shorter OPENBUS_HOME.")
41056
41234
  ],
41235
+ // global.json is malformed or not safely ours; `why` completes "It …".
41236
+ globalUnusable: (path, why) => [
41237
+ warn(`${clip(path, 45)} can't be used, so no directory is global.`),
41238
+ next(p("muted", clip(`It ${why}.`, 3))),
41239
+ next("Remove it, then run npx @open-bus/cli global add <dir> again.")
41240
+ ],
41241
+ globalAsked: () => [
41242
+ warn("This repo's .openbus.json asks for global, which is ignored here."),
41243
+ next("Allow it with npx @open-bus/cli global add .")
41244
+ ],
41057
41245
  daemonNotRunning: () => [
41058
41246
  fail("Daemon is not running"),
41059
41247
  next("Run npx @open-bus/cli to restart it.")
@@ -41124,6 +41312,31 @@ function copy(style) {
41124
41312
  ),
41125
41313
  next("To use this computer again, run npx @open-bus/cli.")
41126
41314
  ],
41315
+ // 11. global
41316
+ globalAdded: (dir) => [
41317
+ done(
41318
+ `${clip(dir, 60)} is now global. Agents started there see every namespace.`
41319
+ ),
41320
+ p("muted", " Sessions already running there change when they restart.")
41321
+ ],
41322
+ globalAlready: (dir) => done(`${clip(dir, 22)} is already global.`),
41323
+ globalNotDir: (dir) => [
41324
+ fail(`${clip(dir, 23)} is not a directory.`),
41325
+ next("Check the path, then run npx @open-bus/cli global add again.")
41326
+ ],
41327
+ globalRemoved: (dir) => [
41328
+ done(`${clip(dir, 24)} is no longer global.`),
41329
+ p("muted", " Sessions already running there change when they restart.")
41330
+ ],
41331
+ globalNotListed: (dir) => warn(`${clip(dir, 36)} was not global. Nothing changed.`),
41332
+ globalNone: () => [
41333
+ "No global directories.",
41334
+ p("muted", "Add one with npx @open-bus/cli global add <dir>.")
41335
+ ],
41336
+ globalList: (dirs) => [
41337
+ `${dirs.length} global ${dirs.length === 1 ? "directory" : "directories"}`,
41338
+ ...dirs.map((d) => ` ${clip(d, 2)}`)
41339
+ ],
41127
41340
  // logs, mcp (DRAFT)
41128
41341
  noLog: (path) => [
41129
41342
  warn(`No daemon log yet at ${clip(path, 24)}`),
@@ -41141,19 +41354,19 @@ function copy(style) {
41141
41354
  import { execFile as execFile2, spawn } from "node:child_process";
41142
41355
  import { promisify } from "node:util";
41143
41356
  var browserCommand = (platform, url2) => platform === "darwin" ? { cmd: "open", args: [url2] } : platform === "win32" ? { cmd: "rundll32", args: ["url.dll,FileProtocolHandler", url2] } : { cmd: "xdg-open", args: [url2] };
41144
- var openBrowser = (url2, launcher = browserCommand(process.platform, url2)) => new Promise((resolve6) => {
41357
+ var openBrowser = (url2, launcher = browserCommand(process.platform, url2)) => new Promise((resolve7) => {
41145
41358
  try {
41146
41359
  const child = spawn(launcher.cmd, launcher.args, {
41147
41360
  stdio: "ignore",
41148
41361
  detached: true
41149
41362
  });
41150
- child.once("error", () => resolve6(false));
41363
+ child.once("error", () => resolve7(false));
41151
41364
  child.once("spawn", () => {
41152
41365
  child.unref();
41153
- resolve6(true);
41366
+ resolve7(true);
41154
41367
  });
41155
41368
  } catch {
41156
- resolve6(false);
41369
+ resolve7(false);
41157
41370
  }
41158
41371
  });
41159
41372
  var EXEC_TIMEOUT_MS = 1e4;
@@ -41192,28 +41405,28 @@ var realDeps = {
41192
41405
  // src/steps/service.ts
41193
41406
  import { createHash as createHash4 } from "node:crypto";
41194
41407
  import {
41195
- chmodSync as chmodSync7,
41408
+ chmodSync as chmodSync8,
41196
41409
  cpSync,
41197
41410
  existsSync as existsSync2,
41198
- lstatSync as lstatSync5,
41199
- mkdirSync as mkdirSync6,
41200
- realpathSync as realpathSync3,
41201
- renameSync as renameSync5,
41411
+ lstatSync as lstatSync6,
41412
+ mkdirSync as mkdirSync7,
41413
+ realpathSync as realpathSync4,
41414
+ renameSync as renameSync6,
41202
41415
  rmSync as rmSync4,
41203
41416
  writeFileSync as writeFileSync5
41204
41417
  } from "node:fs";
41205
- import { basename as basename5, dirname as dirname6, isAbsolute as isAbsolute3, join as join9, resolve as resolve3 } from "node:path";
41418
+ import { basename as basename5, dirname as dirname7, isAbsolute as isAbsolute4, join as join10, resolve as resolve3 } from "node:path";
41206
41419
  import { fileURLToPath } from "node:url";
41207
41420
 
41208
41421
  // src/steps/step.ts
41209
41422
  import {
41210
- chmodSync as chmodSync6,
41211
- mkdirSync as mkdirSync5,
41423
+ chmodSync as chmodSync7,
41424
+ mkdirSync as mkdirSync6,
41212
41425
  readFileSync as readFileSync8,
41213
- renameSync as renameSync4,
41426
+ renameSync as renameSync5,
41214
41427
  writeFileSync as writeFileSync4
41215
41428
  } from "node:fs";
41216
- import { dirname as dirname5 } from "node:path";
41429
+ import { dirname as dirname6 } from "node:path";
41217
41430
  function readInstallFile(path) {
41218
41431
  try {
41219
41432
  const v = JSON.parse(readFileSync8(path, "utf8"));
@@ -41225,12 +41438,12 @@ function readInstallFile(path) {
41225
41438
  }
41226
41439
  function updateInstallFile(path, patch) {
41227
41440
  const next = { ...readInstallFile(path), ...patch };
41228
- mkdirSync5(dirname5(path), { recursive: true, mode: 448 });
41441
+ mkdirSync6(dirname6(path), { recursive: true, mode: 448 });
41229
41442
  const tmp = `${path}.${process.pid}.tmp`;
41230
41443
  writeFileSync4(tmp, `${JSON.stringify(next, null, 2)}
41231
41444
  `, { mode: 384 });
41232
- chmodSync6(tmp, 384);
41233
- renameSync4(tmp, path);
41445
+ chmodSync7(tmp, 384);
41446
+ renameSync5(tmp, path);
41234
41447
  }
41235
41448
  async function runSteps(steps, ctx, record4) {
41236
41449
  for (const step2 of steps) {
@@ -41326,7 +41539,7 @@ function cliSource() {
41326
41539
  jiti: import.meta.resolve("jiti")
41327
41540
  } : { kind: "bundle", file: here };
41328
41541
  }
41329
- var entryName = (src) => src.kind === "bundle" ? join9(basename5(dirname6(src.file)), basename5(src.file)) : "open-bus.js";
41542
+ var entryName = (src) => src.kind === "bundle" ? join10(basename5(dirname7(src.file)), basename5(src.file)) : "open-bus.js";
41330
41543
  var shim = (src) => `// Written by open-bus install: runs the sources it was installed from.
41331
41544
  import { createJiti } from ${JSON.stringify(src.jiti)};
41332
41545
 
@@ -41336,39 +41549,39 @@ const code = await main(process.argv.slice(2));
41336
41549
  if (code !== undefined) process.exit(code);
41337
41550
  `;
41338
41551
  function installCli(home2, src) {
41339
- const bin = join9(home2, "bin");
41552
+ const bin = join10(home2, "bin");
41340
41553
  const tmp = `${bin}.${process.pid}.tmp`;
41341
- mkdirSync6(home2, { recursive: true, mode: 448 });
41342
- chmodSync7(home2, 448);
41554
+ mkdirSync7(home2, { recursive: true, mode: 448 });
41555
+ chmodSync8(home2, 448);
41343
41556
  rmSync4(tmp, { recursive: true, force: true });
41344
- mkdirSync6(tmp);
41557
+ mkdirSync7(tmp);
41345
41558
  if (src.kind === "bundle") {
41346
- const pkg = dirname6(dirname6(src.file));
41559
+ const pkg = dirname7(dirname7(src.file));
41347
41560
  for (const name of ["dist", "assets", "package.json"])
41348
- if (existsSync2(join9(pkg, name)))
41349
- cpSync(join9(pkg, name), join9(tmp, name), { recursive: true });
41350
- } else writeFileSync5(join9(tmp, entryName(src)), shim(src));
41351
- chmodSync7(tmp, 448);
41352
- if (!existsSync2(join9(tmp, "package.json")))
41353
- writeFileSync5(join9(tmp, "package.json"), '{ "type": "module" }\n');
41561
+ if (existsSync2(join10(pkg, name)))
41562
+ cpSync(join10(pkg, name), join10(tmp, name), { recursive: true });
41563
+ } else writeFileSync5(join10(tmp, entryName(src)), shim(src));
41564
+ chmodSync8(tmp, 448);
41565
+ if (!existsSync2(join10(tmp, "package.json")))
41566
+ writeFileSync5(join10(tmp, "package.json"), '{ "type": "module" }\n');
41354
41567
  rmSync4(bin, { recursive: true, force: true });
41355
- renameSync5(tmp, bin);
41356
- return join9(bin, entryName(src));
41568
+ renameSync6(tmp, bin);
41569
+ return join10(bin, entryName(src));
41357
41570
  }
41358
41571
  var present = (path) => {
41359
41572
  try {
41360
- lstatSync5(path);
41573
+ lstatSync6(path);
41361
41574
  return true;
41362
41575
  } catch {
41363
41576
  return false;
41364
41577
  }
41365
41578
  };
41366
41579
  function writeReplacing(path, text3) {
41367
- mkdirSync6(dirname6(path), { recursive: true });
41580
+ mkdirSync7(dirname7(path), { recursive: true });
41368
41581
  const tmp = `${path}.${process.pid}.tmp`;
41369
41582
  try {
41370
41583
  writeFileSync5(tmp, text3, { mode: 420 });
41371
- renameSync5(tmp, path);
41584
+ renameSync6(tmp, path);
41372
41585
  } catch (e) {
41373
41586
  rmSync4(tmp, { force: true });
41374
41587
  throw e;
@@ -41377,13 +41590,13 @@ function writeReplacing(path, text3) {
41377
41590
  var real = (path) => {
41378
41591
  const abs = resolve3(path);
41379
41592
  try {
41380
- return realpathSync3(abs);
41593
+ return realpathSync4(abs);
41381
41594
  } catch {
41382
- const parent = dirname6(abs);
41383
- return parent === abs ? abs : join9(real(parent), basename5(abs));
41595
+ const parent = dirname7(abs);
41596
+ return parent === abs ? abs : join10(real(parent), basename5(abs));
41384
41597
  }
41385
41598
  };
41386
- var isDefaultHome = (home2, userHome) => real(home2) === real(join9(userHome, ".openbus"));
41599
+ var isDefaultHome = (home2, userHome) => real(home2) === real(join10(userHome, ".openbus"));
41387
41600
  function serviceNames(home2, userHome) {
41388
41601
  const suffix = isDefaultHome(home2, userHome) ? "" : createHash4("sha256").update(real(home2)).digest("hex").slice(0, 8);
41389
41602
  return {
@@ -41410,19 +41623,19 @@ function systemService(d) {
41410
41623
  const manager = d.platform === "darwin" ? "launchd" : d.platform === "linux" ? "systemd" : void 0;
41411
41624
  const home2 = () => resolve3(d.home());
41412
41625
  const names2 = () => serviceNames(home2(), d.userHome);
41413
- const entryOf = () => join9(home2(), "bin", entryName(d.source()));
41414
- const installFile = () => join9(home2(), "install.json");
41626
+ const entryOf = () => join10(home2(), "bin", entryName(d.source()));
41627
+ const installFile = () => join10(home2(), "install.json");
41415
41628
  const record4 = () => {
41416
41629
  const r = readInstallFile(installFile()).service;
41417
41630
  return typeof r === "object" && r !== null ? r : {};
41418
41631
  };
41419
41632
  const xdg = d.env.XDG_CONFIG_HOME;
41420
- const configHome = xdg && isAbsolute3(xdg) ? xdg : join9(d.userHome, ".config");
41633
+ const configHome = xdg && isAbsolute4(xdg) ? xdg : join10(d.userHome, ".config");
41421
41634
  const fileName = () => manager === "launchd" ? `${names2().label}.plist` : names2().unit;
41422
- const fresh = () => manager === "launchd" ? join9(d.userHome, "Library/LaunchAgents", fileName()) : join9(configHome, "systemd/user", fileName());
41635
+ const fresh = () => manager === "launchd" ? join10(d.userHome, "Library/LaunchAgents", fileName()) : join10(configHome, "systemd/user", fileName());
41423
41636
  const recorded = () => {
41424
41637
  const r = record4().unit;
41425
- return typeof r === "string" && isAbsolute3(r) && basename5(r) === fileName() ? r : void 0;
41638
+ return typeof r === "string" && isAbsolute4(r) && basename5(r) === fileName() ? r : void 0;
41426
41639
  };
41427
41640
  const file2 = () => {
41428
41641
  const r = recorded();
@@ -41484,17 +41697,17 @@ function systemService(d) {
41484
41697
  async ensure() {
41485
41698
  const h = home2();
41486
41699
  const src = d.source();
41487
- const logs2 = join9(h, "logs");
41700
+ const logs2 = join10(h, "logs");
41488
41701
  const u = {
41489
41702
  node: d.execPath,
41490
- entry: join9(h, "bin", entryName(src)),
41703
+ entry: join10(h, "bin", entryName(src)),
41491
41704
  env: {
41492
41705
  PATH: d.env.PATH ?? DEFAULT_PATH,
41493
41706
  ...isDefaultHome(h, d.userHome) ? {} : { OPENBUS_HOME: h }
41494
41707
  },
41495
41708
  // One file: the daemon logs to stderr, and `open-bus logs` tails it.
41496
- out: join9(logs2, "daemon.log"),
41497
- err: join9(logs2, "daemon.log")
41709
+ out: join10(logs2, "daemon.log"),
41710
+ err: join10(logs2, "daemon.log")
41498
41711
  };
41499
41712
  const unit = { ...u, env: { ...u.env, OPENBUS_SERVICE: "1" } };
41500
41713
  renderPlist(unit);
@@ -41505,7 +41718,7 @@ function systemService(d) {
41505
41718
  const left = await stopDaemon();
41506
41719
  if (left !== void 0) return { running: left };
41507
41720
  installCli(h, src);
41508
- mkdirSync6(logs2, { recursive: true, mode: 448 });
41721
+ mkdirSync7(logs2, { recursive: true, mode: 448 });
41509
41722
  const f = fresh();
41510
41723
  const old = recorded();
41511
41724
  if (old && old !== f) {
@@ -41565,7 +41778,7 @@ function systemService(d) {
41565
41778
  const node2 = record4().node;
41566
41779
  if (typeof node2 === "string" && !existsSync2(node2))
41567
41780
  out.push({ kind: "node-missing", node: node2 });
41568
- if (manager === "systemd" && !existsSync2(join9(d.lingerDir ?? "/var/lib/systemd/linger", d.user)))
41781
+ if (manager === "systemd" && !existsSync2(join10(d.lingerDir ?? "/var/lib/systemd/linger", d.user)))
41569
41782
  out.push({ kind: "linger-off" });
41570
41783
  return out;
41571
41784
  }
@@ -41578,7 +41791,7 @@ var noService = {
41578
41791
  remove: async () => ({}),
41579
41792
  cli: () => ["open-bus"]
41580
41793
  };
41581
- var VERSION = true ? "0.43.2" : JSON.parse(
41794
+ var VERSION = true ? "0.43.3" : JSON.parse(
41582
41795
  readFileSync9(new URL("../package.json", import.meta.url), "utf8")
41583
41796
  ).version;
41584
41797
  var which = (cmd) => {
@@ -41607,8 +41820,8 @@ function processArgs(pid, io = {
41607
41820
  }
41608
41821
  }
41609
41822
  var spawnDaemon = (cmd, args, opts) => {
41610
- const out = openSync2(opts.out, "a", 384);
41611
- const err = openSync2(opts.err, "a", 384);
41823
+ const out = openSync3(opts.out, "a", 384);
41824
+ const err = openSync3(opts.err, "a", 384);
41612
41825
  try {
41613
41826
  const child = spawn2(cmd, args, {
41614
41827
  detached: true,
@@ -41618,8 +41831,8 @@ var spawnDaemon = (cmd, args, opts) => {
41618
41831
  child.unref();
41619
41832
  return child.pid;
41620
41833
  } finally {
41621
- closeSync2(out);
41622
- closeSync2(err);
41834
+ closeSync3(out);
41835
+ closeSync3(err);
41623
41836
  }
41624
41837
  };
41625
41838
  var userName = () => {
@@ -41700,15 +41913,15 @@ var sayErr = (ctx, ...lines) => {
41700
41913
  var tilde = (ctx, path) => path === ctx.userHome ? "~" : path.startsWith(`${ctx.userHome}/`) ? `~${path.slice(ctx.userHome.length)}` : path;
41701
41914
 
41702
41915
  // src/machine.ts
41703
- import { readFileSync as readFileSync10, statSync as statSync5 } from "node:fs";
41704
- import { join as join10 } from "node:path";
41916
+ import { readFileSync as readFileSync10, statSync as statSync6 } from "node:fs";
41917
+ import { join as join11 } from "node:path";
41705
41918
  init_dist();
41706
41919
  function readMachine(home2) {
41707
- const file2 = join10(home2, "machine.json");
41920
+ const file2 = join11(home2, "machine.json");
41708
41921
  let text3;
41709
41922
  let mode;
41710
41923
  try {
41711
- mode = statSync5(file2).mode;
41924
+ mode = statSync6(file2).mode;
41712
41925
  text3 = readFileSync10(file2, "utf8");
41713
41926
  } catch (e) {
41714
41927
  return e.code === "ENOENT" ? { state: "missing" } : { state: "bad" };
@@ -41735,11 +41948,11 @@ var lasting = (e) => [...START_ERROR_CODES, "EACCES", "EPERM"].includes(
41735
41948
  );
41736
41949
  async function daemon(ctx, run4 = runDaemon, signals = process) {
41737
41950
  const m = readMachine(ctx.home);
41738
- if (existsSync3(join11(ctx.home, "revoked")) && (m.state !== "ok" || m.revoked)) {
41951
+ if (existsSync3(join12(ctx.home, "revoked")) && (m.state !== "ok" || m.revoked)) {
41739
41952
  sayErr(ctx, ctx.copy.revoked());
41740
41953
  return 0;
41741
41954
  }
41742
- return new Promise((resolve6) => {
41955
+ return new Promise((resolve7) => {
41743
41956
  let running;
41744
41957
  let ended = false;
41745
41958
  const end = (code2) => {
@@ -41747,7 +41960,7 @@ async function daemon(ctx, run4 = runDaemon, signals = process) {
41747
41960
  ended = true;
41748
41961
  signals.off("SIGINT", onSignal);
41749
41962
  signals.off("SIGTERM", onSignal);
41750
- void (running?.stop() ?? Promise.resolve()).finally(() => resolve6(code2));
41963
+ void (running?.stop() ?? Promise.resolve()).finally(() => resolve7(code2));
41751
41964
  };
41752
41965
  const onSignal = () => end(0);
41753
41966
  signals.once("SIGINT", onSignal);
@@ -41777,7 +41990,7 @@ async function daemon(ctx, run4 = runDaemon, signals = process) {
41777
41990
 
41778
41991
  // src/commands/doctor.ts
41779
41992
  import { readFileSync as readFileSync12 } from "node:fs";
41780
- import { join as join15 } from "node:path";
41993
+ import { join as join16 } from "node:path";
41781
41994
 
41782
41995
  // ../adapters/opencode/src/index.ts
41783
41996
  init_session2();
@@ -41788,20 +42001,20 @@ var OPENCODE_TUI_PLUGIN = fileURLToPath2(
41788
42001
  );
41789
42002
 
41790
42003
  // src/steps/adapters.ts
41791
- import { randomBytes } from "node:crypto";
42004
+ import { randomBytes as randomBytes2 } from "node:crypto";
41792
42005
  import {
41793
- chmodSync as chmodSync8,
42006
+ chmodSync as chmodSync9,
41794
42007
  existsSync as existsSync4,
41795
- lstatSync as lstatSync6,
41796
- mkdirSync as mkdirSync7,
42008
+ lstatSync as lstatSync7,
42009
+ mkdirSync as mkdirSync8,
41797
42010
  readFileSync as readFileSync11,
41798
42011
  readlinkSync,
41799
- renameSync as renameSync6,
42012
+ renameSync as renameSync7,
41800
42013
  rmSync as rmSync5,
41801
- statSync as statSync6,
42014
+ statSync as statSync7,
41802
42015
  writeFileSync as writeFileSync6
41803
42016
  } from "node:fs";
41804
- import { dirname as dirname7, join as join12, resolve as resolve4 } from "node:path";
42017
+ import { dirname as dirname8, join as join13, resolve as resolve4 } from "node:path";
41805
42018
  import { isDeepStrictEqual } from "node:util";
41806
42019
 
41807
42020
  // ../../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
@@ -42343,11 +42556,11 @@ function parseTree(text3, errors = [], options = ParseOptions.DEFAULT) {
42343
42556
  onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
42344
42557
  ensurePropertyComplete(offset + length);
42345
42558
  },
42346
- onSeparator: (sep, offset, length) => {
42559
+ onSeparator: (sep2, offset, length) => {
42347
42560
  if (currentParent.type === "property") {
42348
- if (sep === ":") {
42561
+ if (sep2 === ":") {
42349
42562
  currentParent.colonOffset = offset;
42350
- } else if (sep === ",") {
42563
+ } else if (sep2 === ",") {
42351
42564
  ensurePropertyComplete(offset);
42352
42565
  }
42353
42566
  }
@@ -43031,21 +43244,21 @@ var readAssets = () => ({
43031
43244
  });
43032
43245
  var paths = (deps) => {
43033
43246
  const env = deps.env ?? {};
43034
- const opencode = env.OPENCODE_CONFIG_DIR ?? join12(env.XDG_CONFIG_HOME ?? join12(deps.home, ".config"), "opencode");
43035
- const openbus = deps.openbusHome ?? join12(deps.home, ".openbus");
43247
+ const opencode = env.OPENCODE_CONFIG_DIR ?? join13(env.XDG_CONFIG_HOME ?? join13(deps.home, ".config"), "opencode");
43248
+ const openbus = deps.openbusHome ?? join13(deps.home, ".openbus");
43036
43249
  return {
43037
- claude: join12(env.CLAUDE_CONFIG_DIR ?? deps.home, ".claude.json"),
43250
+ claude: join13(env.CLAUDE_CONFIG_DIR ?? deps.home, ".claude.json"),
43038
43251
  // OpenCode reads both; edit the one the user has, else create .json.
43039
43252
  opencodeConfigs: [
43040
- join12(opencode, "opencode.json"),
43041
- join12(opencode, "opencode.jsonc")
43253
+ join13(opencode, "opencode.json"),
43254
+ join13(opencode, "opencode.jsonc")
43042
43255
  ],
43043
- opencodeCli: join12(opencode, "cli.json"),
43044
- record: join12(openbus, "install.json"),
43256
+ opencodeCli: join13(opencode, "cli.json"),
43257
+ record: join13(openbus, "install.json"),
43045
43258
  // OpenCode registers the folder that holds tui.js.
43046
- opencodePlugin: join12(openbus, "integrations/opencode", NAME),
43047
- pi: join12(
43048
- env.PI_CODING_AGENT_DIR ?? join12(deps.home, ".pi/agent"),
43259
+ opencodePlugin: join13(openbus, "integrations/opencode", NAME),
43260
+ pi: join13(
43261
+ env.PI_CODING_AGENT_DIR ?? join13(deps.home, ".pi/agent"),
43049
43262
  "extensions/openbus.ts"
43050
43263
  )
43051
43264
  };
@@ -43068,7 +43281,7 @@ function readDoc(path) {
43068
43281
  }
43069
43282
  function present2(path) {
43070
43283
  try {
43071
- lstatSync6(path);
43284
+ lstatSync7(path);
43072
43285
  return true;
43073
43286
  } catch {
43074
43287
  return false;
@@ -43077,31 +43290,31 @@ function present2(path) {
43077
43290
  function target(path) {
43078
43291
  let p = path;
43079
43292
  for (let hops = 0; hops < 40; hops++) {
43080
- if (!present2(p) || !lstatSync6(p).isSymbolicLink()) {
43081
- if (p !== path && !existsSync4(dirname7(p)))
43293
+ if (!present2(p) || !lstatSync7(p).isSymbolicLink()) {
43294
+ if (p !== path && !existsSync4(dirname8(p)))
43082
43295
  throw new Error(
43083
43296
  `${path} is a dangling symlink to ${p}; left it untouched`
43084
43297
  );
43085
43298
  return p;
43086
43299
  }
43087
- p = resolve4(dirname7(p), readlinkSync(p));
43300
+ p = resolve4(dirname8(p), readlinkSync(p));
43088
43301
  }
43089
43302
  throw new Error(`${path}: too many symlinks; left it untouched`);
43090
43303
  }
43091
43304
  function writeAtomic(path, data, mode) {
43092
43305
  const dest = target(path);
43093
- mkdirSync7(dirname7(dest), { recursive: true });
43306
+ mkdirSync8(dirname8(dest), { recursive: true });
43094
43307
  let m = mode ?? 420;
43095
43308
  if (mode === void 0)
43096
43309
  try {
43097
- m = statSync6(dest).mode & 511;
43310
+ m = statSync7(dest).mode & 511;
43098
43311
  } catch {
43099
43312
  }
43100
- const tmp = `${dest}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
43313
+ const tmp = `${dest}.${process.pid}.${randomBytes2(4).toString("hex")}.tmp`;
43101
43314
  try {
43102
43315
  writeFileSync6(tmp, data, { mode: m, flag: "wx" });
43103
- chmodSync8(tmp, m);
43104
- renameSync6(tmp, dest);
43316
+ chmodSync9(tmp, m);
43317
+ renameSync7(tmp, dest);
43105
43318
  } catch (e) {
43106
43319
  rmSync5(tmp, { force: true });
43107
43320
  throw e;
@@ -43245,7 +43458,7 @@ var install = {
43245
43458
  created[p.opencodeCli] = add(p.opencodeCli, madeCli);
43246
43459
  writeRecord(p.record, record4, created);
43247
43460
  writeAtomic(
43248
- join12(p.opencodePlugin, "tui.js"),
43461
+ join13(p.opencodePlugin, "tui.js"),
43249
43462
  deps.assets.opencodePlugin,
43250
43463
  420
43251
43464
  );
@@ -43386,7 +43599,7 @@ function checkAdapters(deps) {
43386
43599
  }) && listed(
43387
43600
  parseJsonc(readFileSync11(p.opencodeCli, "utf8"), p.opencodeCli),
43388
43601
  p.opencodePlugin
43389
- ) && existsSync4(join12(p.opencodePlugin, "tui.js"))
43602
+ ) && existsSync4(join13(p.opencodePlugin, "tui.js"))
43390
43603
  ),
43391
43604
  pi: state("pi", () => existsSync4(p.pi))
43392
43605
  };
@@ -43394,19 +43607,19 @@ function checkAdapters(deps) {
43394
43607
 
43395
43608
  // src/commands/login.ts
43396
43609
  init_dist();
43397
- import { randomBytes as randomBytes2 } from "node:crypto";
43610
+ import { randomBytes as randomBytes3 } from "node:crypto";
43398
43611
  import {
43399
- chmodSync as chmodSync9,
43400
- closeSync as closeSync3,
43401
- mkdirSync as mkdirSync8,
43402
- openSync as openSync3,
43403
- renameSync as renameSync7,
43612
+ chmodSync as chmodSync10,
43613
+ closeSync as closeSync4,
43614
+ mkdirSync as mkdirSync9,
43615
+ openSync as openSync4,
43616
+ renameSync as renameSync8,
43404
43617
  rmSync as rmSync6,
43405
- unlinkSync,
43406
- writeSync
43618
+ unlinkSync as unlinkSync2,
43619
+ writeSync as writeSync2
43407
43620
  } from "node:fs";
43408
43621
  import { hostname as hostname3 } from "node:os";
43409
- import { join as join13 } from "node:path";
43622
+ import { join as join14 } from "node:path";
43410
43623
  var LoginFailed = class extends Error {
43411
43624
  constructor(kind2, message, detail = {}) {
43412
43625
  super(message);
@@ -43437,23 +43650,23 @@ function checkVerificationUri(uri, hub, userCode) {
43437
43650
  return u.href;
43438
43651
  }
43439
43652
  function writeMachineFile(home2, body) {
43440
- mkdirSync8(home2, { recursive: true, mode: 448 });
43441
- chmodSync9(home2, 448);
43442
- const tmp = join13(home2, `.machine.json.${randomBytes2(8).toString("hex")}.tmp`);
43443
- const fd = openSync3(tmp, "wx", 384);
43653
+ mkdirSync9(home2, { recursive: true, mode: 448 });
43654
+ chmodSync10(home2, 448);
43655
+ const tmp = join14(home2, `.machine.json.${randomBytes3(8).toString("hex")}.tmp`);
43656
+ const fd = openSync4(tmp, "wx", 384);
43444
43657
  try {
43445
- writeSync(fd, body);
43658
+ writeSync2(fd, body);
43446
43659
  } catch (e) {
43447
- closeSync3(fd);
43448
- unlinkSync(tmp);
43660
+ closeSync4(fd);
43661
+ unlinkSync2(tmp);
43449
43662
  throw e;
43450
43663
  }
43451
- closeSync3(fd);
43664
+ closeSync4(fd);
43452
43665
  try {
43453
- chmodSync9(tmp, 384);
43454
- renameSync7(tmp, join13(home2, "machine.json"));
43666
+ chmodSync10(tmp, 384);
43667
+ renameSync8(tmp, join14(home2, "machine.json"));
43455
43668
  } catch (e) {
43456
- unlinkSync(tmp);
43669
+ unlinkSync2(tmp);
43457
43670
  throw e;
43458
43671
  }
43459
43672
  }
@@ -43575,7 +43788,7 @@ async function login(args) {
43575
43788
  `${JSON.stringify({ hub, machine_id: poll.machine_id, label, machine_token: poll.token }, null, 2)}
43576
43789
  `
43577
43790
  );
43578
- rmSync6(join13(args.home, "revoked"), { force: true });
43791
+ rmSync6(join14(args.home, "revoked"), { force: true });
43579
43792
  if (!events?.code) print(`Approved this machine as ${label}.`);
43580
43793
  return {
43581
43794
  machineToken: poll.token,
@@ -43599,7 +43812,7 @@ init_src();
43599
43812
 
43600
43813
  // src/commands/install.ts
43601
43814
  init_src2();
43602
- import { join as join14 } from "node:path";
43815
+ import { join as join15 } from "node:path";
43603
43816
 
43604
43817
  // src/live.ts
43605
43818
  var FRAME_MS = 80;
@@ -43726,7 +43939,7 @@ async function loginStep(ctx, opts) {
43726
43939
  ctx,
43727
43940
  c.approved(result.label),
43728
43941
  c.tokenSaved(
43729
- tilde(ctx, join14(ctx.home, "machine.json")),
43942
+ tilde(ctx, join15(ctx.home, "machine.json")),
43730
43943
  result.machineToken
43731
43944
  ),
43732
43945
  ""
@@ -43786,7 +43999,7 @@ function shownSocket(ctx) {
43786
43999
  const real2 = `${canonicalHome(ctx.home)}/`;
43787
44000
  return tilde(
43788
44001
  ctx,
43789
- path.startsWith(real2) ? join14(ctx.home, path.slice(real2.length)) : path
44002
+ path.startsWith(real2) ? join15(ctx.home, path.slice(real2.length)) : path
43790
44003
  );
43791
44004
  }
43792
44005
  async function waitForDaemon(ctx) {
@@ -43903,7 +44116,7 @@ async function install2(opts, ctx) {
43903
44116
  return results.every((r) => r.state === "done") ? 0 : 1;
43904
44117
  }
43905
44118
  const ok = await runSteps(steps, ctx, {
43906
- path: join14(ctx.home, "install.json"),
44119
+ path: join15(ctx.home, "install.json"),
43907
44120
  now: ctx.now
43908
44121
  });
43909
44122
  return ok ? 0 : 1;
@@ -43982,6 +44195,10 @@ function claudeIsolates(path) {
43982
44195
  return void 0;
43983
44196
  }
43984
44197
  }
44198
+ function asksForGlobal(ctx, dirs) {
44199
+ if (nearestConfig(ctx.cwd).global !== true) return false;
44200
+ return !isGlobalDir(ctx.cwd, dirs);
44201
+ }
43985
44202
  async function doctor(ctx) {
43986
44203
  const c = ctx.copy;
43987
44204
  const n = { failed: 0, warnings: 0, passed: 0 };
@@ -44001,7 +44218,7 @@ async function doctor(ctx) {
44001
44218
  const node2 = ctx.nodeVersion.replace(/^v/, "");
44002
44219
  if (Number(node2.split(".")[0]) >= MIN_NODE) pass(c.nodeOk(node2));
44003
44220
  else fail(c.nodeOld(node2));
44004
- const machineFile = tilde(ctx, join15(ctx.home, "machine.json"));
44221
+ const machineFile = tilde(ctx, join16(ctx.home, "machine.json"));
44005
44222
  const m = readMachine(ctx.home);
44006
44223
  if (m.state !== "ok") fail(c.noCredentials(machineFile));
44007
44224
  else if (m.revoked) fail(c.revokedCheck());
@@ -44050,8 +44267,8 @@ async function doctor(ctx) {
44050
44267
  if (wiring[h] === "configured") pass(c.wired(h, version2));
44051
44268
  else fail(c.notWired(h));
44052
44269
  if (h === "claude") {
44053
- const settings = join15(
44054
- ctx.env.CLAUDE_CONFIG_DIR ?? join15(ctx.userHome, ".claude"),
44270
+ const settings = join16(
44271
+ ctx.env.CLAUDE_CONFIG_DIR ?? join16(ctx.userHome, ".claude"),
44055
44272
  "settings.json"
44056
44273
  );
44057
44274
  const isolates = claudeIsolates(settings);
@@ -44059,16 +44276,79 @@ async function doctor(ctx) {
44059
44276
  if (isolates === true) warn(c.claudeIsolates(tilde(ctx, settings)));
44060
44277
  }
44061
44278
  }
44279
+ const allow = globalFile(ctx.home);
44280
+ const list = readGlobalDirs(allow);
44281
+ if (list.error) warn(c.globalUnusable(tilde(ctx, allow), list.error));
44282
+ if (asksForGlobal(ctx, list.dirs)) warn(c.globalAsked());
44062
44283
  say(ctx, "", c.summary(n.failed, n.warnings, n.passed));
44063
44284
  return n.failed > 0 ? 1 : 0;
44064
44285
  }
44065
44286
 
44287
+ // src/commands/global.ts
44288
+ import { realpathSync as realpathSync5, statSync as statSync8 } from "node:fs";
44289
+ import { resolve as resolve5 } from "node:path";
44290
+ function shown(ctx, path) {
44291
+ const t = tilde(ctx, path);
44292
+ if (t !== path) return t;
44293
+ try {
44294
+ return tilde({ userHome: realpathSync5(ctx.userHome) }, path);
44295
+ } catch {
44296
+ return path;
44297
+ }
44298
+ }
44299
+ async function global(opts, ctx) {
44300
+ const c = ctx.copy;
44301
+ say(ctx, c.header(ctx.version), "");
44302
+ const file2 = globalFile(ctx.home);
44303
+ const { dirs, error: error62 } = readGlobalDirs(file2);
44304
+ if (error62) {
44305
+ sayErr(ctx, c.globalUnusable(tilde(ctx, file2), error62));
44306
+ return 1;
44307
+ }
44308
+ if (opts.sub === "list") {
44309
+ say(
44310
+ ctx,
44311
+ dirs.length ? c.globalList(dirs.map((d) => shown(ctx, d))) : c.globalNone()
44312
+ );
44313
+ return 0;
44314
+ }
44315
+ const given = resolve5(ctx.cwd, opts.dir);
44316
+ let real2;
44317
+ try {
44318
+ real2 = canonicalPath(given);
44319
+ } catch {
44320
+ }
44321
+ if (opts.sub === "add") {
44322
+ if (!real2 || !statSync8(real2).isDirectory()) {
44323
+ sayErr(ctx, c.globalNotDir(shown(ctx, real2 ?? given)));
44324
+ return 1;
44325
+ }
44326
+ if (isGlobalDir(real2, dirs)) {
44327
+ say(ctx, c.globalAlready(shown(ctx, real2)));
44328
+ return 0;
44329
+ }
44330
+ writeGlobalDirs([...dirs, real2], ctx.home);
44331
+ say(ctx, c.globalAdded(shown(ctx, real2)));
44332
+ return 0;
44333
+ }
44334
+ const keep = dirs.filter(
44335
+ (d) => d !== given && d !== real2 && !(real2 && sameDir(d, real2))
44336
+ );
44337
+ if (keep.length === dirs.length) {
44338
+ say(ctx, c.globalNotListed(shown(ctx, real2 ?? given)));
44339
+ return 0;
44340
+ }
44341
+ writeGlobalDirs(keep, ctx.home);
44342
+ say(ctx, c.globalRemoved(shown(ctx, real2 ?? given)));
44343
+ return 0;
44344
+ }
44345
+
44066
44346
  // src/commands/logs.ts
44067
44347
  import { readFileSync as readFileSync13 } from "node:fs";
44068
- import { join as join16 } from "node:path";
44348
+ import { join as join17 } from "node:path";
44069
44349
  var TAIL = 50;
44070
44350
  async function logs(ctx) {
44071
- const path = join16(ctx.home, "logs", "daemon.log");
44351
+ const path = join17(ctx.home, "logs", "daemon.log");
44072
44352
  let text3;
44073
44353
  try {
44074
44354
  text3 = readFileSync13(path, "utf8");
@@ -44096,12 +44376,12 @@ async function mcp(harness, ctx, load = (h) => MCP_SERVER[h]()) {
44096
44376
  }
44097
44377
 
44098
44378
  // src/commands/uninstall.ts
44099
- import { join as join18 } from "node:path";
44379
+ import { join as join19 } from "node:path";
44100
44380
 
44101
44381
  // src/steps/purge.ts
44102
44382
  init_src2();
44103
- import { lstatSync as lstatSync7, readdirSync as readdirSync3, rmdirSync, rmSync as rmSync7 } from "node:fs";
44104
- import { join as join17 } from "node:path";
44383
+ import { lstatSync as lstatSync8, readdirSync as readdirSync3, rmdirSync, rmSync as rmSync7 } from "node:fs";
44384
+ import { join as join18 } from "node:path";
44105
44385
  var FILES = [
44106
44386
  "machine.json",
44107
44387
  "install.json",
@@ -44133,7 +44413,7 @@ var FOLDERS = [
44133
44413
  ];
44134
44414
  function kind(path) {
44135
44415
  try {
44136
- const st = lstatSync7(path);
44416
+ const st = lstatSync8(path);
44137
44417
  return st.isDirectory() ? "dir" : st.isSocket() ? "socket" : "other";
44138
44418
  } catch {
44139
44419
  return void 0;
@@ -44150,14 +44430,14 @@ var rmdirIfEmpty = (path) => {
44150
44430
  };
44151
44431
  function purgeShort(dir, removed) {
44152
44432
  if (kind(dir) !== "dir" || unsafeSocketDir(dir)) return;
44153
- const ret = join17(dir, "claude-return");
44433
+ const ret = join18(dir, "claude-return");
44154
44434
  for (const [d, ours] of [
44155
44435
  [ret, (_n, p) => kind(p) === "socket"],
44156
44436
  [dir, (n) => /^daemon\.sock(\.keep-\d+)?$/.test(n)]
44157
44437
  ]) {
44158
44438
  if (kind(d) !== "dir") continue;
44159
44439
  for (const name of readdirSync3(d)) {
44160
- const path = join17(d, name);
44440
+ const path = join18(d, name);
44161
44441
  const k = kind(path);
44162
44442
  if (k === void 0 || k === "dir" || !ours(name, path)) continue;
44163
44443
  remove(path, k);
@@ -44182,21 +44462,21 @@ function purge(home2, opts) {
44182
44462
  ...FILES,
44183
44463
  ...entries.filter((n) => TEMP.some((re) => re.test(n)))
44184
44464
  ]) {
44185
- const path = join17(home2, name);
44465
+ const path = join18(home2, name);
44186
44466
  const k = kind(path);
44187
44467
  if (k === void 0 || k === "dir") continue;
44188
44468
  remove(path, k);
44189
44469
  removed.push(name);
44190
44470
  }
44191
44471
  for (const folder of FOLDERS) {
44192
- const dir = join17(home2, folder.path);
44472
+ const dir = join18(home2, folder.path);
44193
44473
  if (kind(dir) !== "dir") continue;
44194
44474
  for (const name of readdirSync3(dir)) {
44195
- const path = join17(dir, name);
44475
+ const path = join18(dir, name);
44196
44476
  const k = kind(path);
44197
44477
  if (k === void 0 || !folder.ours(name, path)) continue;
44198
44478
  remove(path, k);
44199
- removed.push(join17(folder.path, name));
44479
+ removed.push(join18(folder.path, name));
44200
44480
  }
44201
44481
  if (rmdirIfEmpty(dir)) removed.push(folder.path);
44202
44482
  }
@@ -44235,7 +44515,7 @@ async function uninstall2(opts, ctx) {
44235
44515
  r.opencodeRestarted ? c.restartedUnload() : c.opencodeNotRunningUnload()
44236
44516
  );
44237
44517
  if (!opts.purge) {
44238
- say(ctx, "", c.kept(tilde(ctx, join18(ctx.home, "machine.json"))));
44518
+ say(ctx, "", c.kept(tilde(ctx, join19(ctx.home, "machine.json"))));
44239
44519
  return 0;
44240
44520
  }
44241
44521
  const home2 = tilde(ctx, ctx.home);
@@ -44246,7 +44526,7 @@ async function uninstall2(opts, ctx) {
44246
44526
  } catch {
44247
44527
  }
44248
44528
  const out = purge(ctx.home, {
44249
- isDefault: ctx.home === join18(ctx.userHome, ".openbus")
44529
+ isDefault: ctx.home === join19(ctx.userHome, ".openbus")
44250
44530
  });
44251
44531
  if ("refused" in out) {
44252
44532
  sayErr(ctx, c.purgeRefused(home2));
@@ -44269,9 +44549,11 @@ var COMMANDS = /* @__PURE__ */ new Set([
44269
44549
  "logs",
44270
44550
  "doctor",
44271
44551
  "uninstall",
44552
+ "global",
44272
44553
  "version"
44273
44554
  ]);
44274
44555
  var HARNESSES2 = ["claude", "opencode", "pi"];
44556
+ var GLOBAL_USAGE = "usage: npx @open-bus/cli global <add|rm> <dir>, or global list";
44275
44557
  var COMMON = /* @__PURE__ */ new Set(["no-color", "version", "home"]);
44276
44558
  var FLAGS = {
44277
44559
  install: ["hub", "no-open", "yes", "check"],
@@ -44298,9 +44580,10 @@ function parse5(argv) {
44298
44580
  const [head, ...rest] = positionals;
44299
44581
  const cmd = head ?? "install";
44300
44582
  if (!COMMANDS.has(cmd)) throw new Error(`unknown command: ${cmd}`);
44301
- const takes = cmd === "mcp" ? 1 : 0;
44583
+ const takes = cmd === "mcp" ? 1 : cmd === "global" ? rest[0] === "list" ? 1 : 2 : 0;
44302
44584
  if (cmd === "mcp" && rest.length === 0)
44303
44585
  throw new Error("usage: npx @open-bus/cli mcp <claude|opencode|pi>");
44586
+ if (cmd === "global" && rest.length < takes) throw new Error(GLOBAL_USAGE);
44304
44587
  const extra = rest[takes];
44305
44588
  if (extra !== void 0) throw new Error(`unexpected argument: ${extra}`);
44306
44589
  for (const name of ["home", "hub"])
@@ -44331,6 +44614,12 @@ function route(cmd, values, positionals) {
44331
44614
  }
44332
44615
  case "uninstall":
44333
44616
  return { cmd, purge: values.purge };
44617
+ case "global": {
44618
+ const [sub, dir] = positionals;
44619
+ if (sub === "list") return { cmd, sub };
44620
+ if ((sub === "add" || sub === "rm") && dir) return { cmd, sub, dir };
44621
+ throw new Error(GLOBAL_USAGE);
44622
+ }
44334
44623
  case "install":
44335
44624
  return {
44336
44625
  cmd,
@@ -44360,7 +44649,7 @@ async function main(argv, makeCtx = realCtx) {
44360
44649
  return 2;
44361
44650
  }
44362
44651
  const ctx = makeCtx(cmd.noColor);
44363
- if (cmd.home) ctx.home = resolve5(cmd.home);
44652
+ if (cmd.home) ctx.home = resolve6(cmd.home);
44364
44653
  try {
44365
44654
  return await dispatch(cmd, ctx);
44366
44655
  } catch (e) {
@@ -44405,6 +44694,8 @@ async function dispatch(cmd, ctx) {
44405
44694
  return doctor(ctx);
44406
44695
  case "uninstall":
44407
44696
  return uninstall2({ purge: cmd.purge }, ctx);
44697
+ case "global":
44698
+ return global(cmd, ctx);
44408
44699
  case "version":
44409
44700
  say(ctx, ctx.copy.header(ctx.version));
44410
44701
  return 0;