@snowyroad/braid 0.79.4 → 0.80.0

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.
@@ -374,7 +374,7 @@ var InviteExpiredError = class extends Error {
374
374
  }
375
375
  };
376
376
  async function redeemInvite(relayHttpUrl, code) {
377
- const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-U5DXUIMM.js");
377
+ const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-JUDUFIOQ.js");
378
378
  const r = await boundedJsonFetch2(`${relayHttpUrl.replace(/\/$/, "")}/invites/redeem`, {
379
379
  method: "POST",
380
380
  headers: { "content-type": "application/json" },
@@ -463,7 +463,7 @@ function validateReplacementToken(newToken, currentToken, nowMs = Date.now()) {
463
463
  return { ok: true };
464
464
  }
465
465
  async function mintAccessToken(relayHttpUrl, agentKey, fetchFn = fetch, dpopProof) {
466
- const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-U5DXUIMM.js");
466
+ const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-JUDUFIOQ.js");
467
467
  const r = await boundedJsonFetch2(`${relayHttpUrl.replace(/\/$/, "")}/agents/token`, {
468
468
  method: "POST",
469
469
  headers: {
@@ -971,14 +971,13 @@ function sanitizeForTty(s) {
971
971
  return s.replace(ANSI_RE, "").replace(CTRL_RE, "");
972
972
  }
973
973
  var ESC = String.fromCharCode(27);
974
- function restoreTerminal() {
975
- const out = process.stdout;
974
+ function restoreTerminal(out = process.stdout, stdin = process.stdin) {
976
975
  if (!out.isTTY) return;
977
976
  out.write(
978
- `${ESC}[?1l${ESC}>${ESC}[?25h${ESC}[?1049l${ESC}[?2004l${ESC}[?1000l${ESC}[?1002l${ESC}[?1003l${ESC}[?1006l`
977
+ `${ESC}[?1l${ESC}>${ESC}[?25h${ESC}[?1049l${ESC}[?2004l${ESC}[>4;0m${ESC}[?1000l${ESC}[?1002l${ESC}[?1003l${ESC}[?1006l`
979
978
  );
980
979
  try {
981
- if (process.stdin.isTTY) process.stdin.setRawMode(false);
980
+ if (stdin.isTTY) stdin.setRawMode?.(false);
982
981
  } catch {
983
982
  }
984
983
  }
@@ -2235,11 +2234,23 @@ function redactConfig(cfg) {
2235
2234
  }
2236
2235
  return { ...cfg, token: "<redacted>", model };
2237
2236
  }
2237
+ function buildVersion() {
2238
+ try {
2239
+ const pkg = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
2240
+ return String(pkg.version ?? "");
2241
+ } catch {
2242
+ return "";
2243
+ }
2244
+ }
2238
2245
  function startingLines(cfg) {
2239
2246
  const row = (label, value) => `${label.padEnd(8)} : ${value}`;
2240
2247
  const anthropicCredential = cfg.agentMode !== "acp" || cfg.agent === "claude-code";
2241
2248
  const catchUpHours = cfg.catchUpTtlMs % 36e5 === 0 ? `${cfg.catchUpTtlMs / 36e5}h` : `${Math.round(cfg.catchUpTtlMs / 6e4)}min`;
2242
2249
  return [
2250
+ // The running braid version — the fastest way to confirm which build a live bridge
2251
+ // is (BL-229). Sourced from the runtimeVersion threaded onto config; an honest
2252
+ // placeholder shows when it could not be read, never a blank row.
2253
+ row("version", cfg.runtimeVersion ? sanitizeForTty(cfg.runtimeVersion) : "(unknown)"),
2243
2254
  row("agent", sanitizeForTty(cfg.agentName)),
2244
2255
  row("relay", sanitizeForTty(cfg.relayWsUrl)),
2245
2256
  row("provider", cfg.agentMode === "acp" ? cfg.agent : "bundled SDK (generic mode)"),
@@ -2492,5 +2503,6 @@ export {
2492
2503
  validateRelayWsUrl,
2493
2504
  wsToHttp,
2494
2505
  resolveConfig,
2506
+ buildVersion,
2495
2507
  startingLines
2496
2508
  };
package/dist/cli.js CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  acquireAgentLock,
27
27
  assertKeystorePerms,
28
28
  boundedJsonFetch,
29
+ buildVersion,
29
30
  classifyFatal,
30
31
  cleanContent,
31
32
  configDir,
@@ -66,7 +67,7 @@ import {
66
67
  validateReplacementToken,
67
68
  verifyCardSignature,
68
69
  wsToHttp
69
- } from "./chunk-SKUYOAV5.js";
70
+ } from "./chunk-M5WUSDQN.js";
70
71
 
71
72
  // src/health.ts
72
73
  var CEILING_STRIKES_TO_DEAD = 3;
@@ -6958,6 +6959,7 @@ function startUpdateNotifier(opts) {
6958
6959
 
6959
6960
  // src/cli.ts
6960
6961
  import { readFileSync as readFileSync9 } from "fs";
6962
+ import { fileURLToPath as fileURLToPath3 } from "url";
6961
6963
 
6962
6964
  // src/cliArgs.ts
6963
6965
  var USAGE = `Usage: braid <command>
@@ -7188,10 +7190,42 @@ function parseCliArgs(argv) {
7188
7190
  if (!parsed.ok) return { kind: "usage", error: parsed.error };
7189
7191
  return { kind: "run", argv };
7190
7192
  }
7191
- if (first === void 0) return { kind: "usage" };
7193
+ if (first === "tui") {
7194
+ return { kind: "tui", bare: false, args: argv.slice(1) };
7195
+ }
7196
+ if (first === void 0) return { kind: "tui", bare: true, args: [] };
7192
7197
  return { kind: "usage", error: `Unknown command: ${first}` };
7193
7198
  }
7194
7199
 
7200
+ // src/launchTui.ts
7201
+ import { spawn as spawn2 } from "child_process";
7202
+ import { createRequire } from "module";
7203
+ import { dirname as dirname6, join as join8 } from "path";
7204
+ function resolveTuiEntry() {
7205
+ try {
7206
+ const require2 = createRequire(import.meta.url);
7207
+ const pkgPath = require2.resolve("arp-tui/package.json");
7208
+ const pkg = require2("arp-tui/package.json");
7209
+ const rel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.["arp-tui"];
7210
+ return rel ? join8(dirname6(pkgPath), rel) : null;
7211
+ } catch {
7212
+ return null;
7213
+ }
7214
+ }
7215
+ function runTui(args, env, selfCliPath) {
7216
+ const entry = resolveTuiEntry();
7217
+ if (!entry) {
7218
+ console.error("[braid] the interactive UI is not installed \u2014 reinstall @snowyroad/braid");
7219
+ return Promise.resolve(1);
7220
+ }
7221
+ const childEnv = { ...env, ARP_TUI_BRIDGE_CMD: `${process.execPath} ${selfCliPath}` };
7222
+ return new Promise((resolve2) => {
7223
+ const child = spawn2(process.execPath, [entry, ...args], { stdio: "inherit", env: childEnv });
7224
+ child.on("error", () => resolve2(1));
7225
+ child.on("close", (code) => resolve2(code ?? 1));
7226
+ });
7227
+ }
7228
+
7195
7229
  // src/enroll.ts
7196
7230
  var ENROLL_STDIN_MAX_BYTES = 16 * 1024;
7197
7231
  function readBoundedStdin(stream, maxBytes) {
@@ -7705,6 +7739,7 @@ async function runHandoff(opts) {
7705
7739
  });
7706
7740
  });
7707
7741
  } finally {
7742
+ restoreTerminal();
7708
7743
  await session.handoffResume();
7709
7744
  out.write(`
7710
7745
  [handoff] resumed driving ${label}
@@ -7762,7 +7797,7 @@ async function runHandoffCommand(opts) {
7762
7797
  const socket = connectFn(sockPath);
7763
7798
  const lc = lineClient(socket);
7764
7799
  try {
7765
- return opts.recover ? await runRecover(lc, { write, promptFn, token, name: safeName }) : await runTakeover(lc, { write, promptFn, token, name: safeName, env, spawnFn, channel: opts.channel });
7800
+ return opts.recover ? await runRecover(lc, { write, promptFn, token, name: safeName }) : await runTakeover(lc, { write, promptFn, token, name: safeName, env, spawnFn, channel: opts.channel, stdin, stdout });
7766
7801
  } catch (err) {
7767
7802
  write(`[handoff] control socket error: ${sanitizeForTty(String(err?.message ?? err))}
7768
7803
  `);
@@ -7775,7 +7810,7 @@ async function runHandoffCommand(opts) {
7775
7810
  }
7776
7811
  }
7777
7812
  async function runTakeover(lc, ctx) {
7778
- const { write, promptFn, token, name, env, spawnFn, channel } = ctx;
7813
+ const { write, promptFn, token, name, env, spawnFn, channel, stdin, stdout } = ctx;
7779
7814
  lc.send({ verb: "handoff", ...token ? { token } : {} });
7780
7815
  const first = await lc.next();
7781
7816
  if (typeof first["error"] === "string") return reportError(write, first["error"], name);
@@ -7830,6 +7865,7 @@ async function runTakeover(lc, ctx) {
7830
7865
  settle({ error: e });
7831
7866
  }
7832
7867
  });
7868
+ restoreTerminal(stdout, stdin);
7833
7869
  await sendDone();
7834
7870
  if (outcome.error) {
7835
7871
  write(`[handoff] failed to open the session: ${sanitizeForTty(String(outcome.error.message ?? outcome.error))}
@@ -8474,7 +8510,7 @@ import { homedir as homedir6 } from "os";
8474
8510
 
8475
8511
  // src/service/manager.ts
8476
8512
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, rmSync as rmSync2, existsSync as existsSync6 } from "fs";
8477
- import { join as join9 } from "path";
8513
+ import { join as join10 } from "path";
8478
8514
 
8479
8515
  // src/service/templates.ts
8480
8516
  function escapeXml(s) {
@@ -8646,17 +8682,17 @@ function schtasksXml(p) {
8646
8682
 
8647
8683
  // src/service/win32.ts
8648
8684
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync4, readFileSync as readFileSync7, unlinkSync as unlinkSync3 } from "fs";
8649
- import { join as join8 } from "path";
8685
+ import { join as join9 } from "path";
8650
8686
  function win32LogDir(homeDir) {
8651
- return join8(homeDir, "AppData", "Local", "braid", "logs");
8687
+ return join9(homeDir, "AppData", "Local", "braid", "logs");
8652
8688
  }
8653
8689
  function win32Manager(ctx) {
8654
- const serviceDir = join8(ctx.braidDir, "service");
8690
+ const serviceDir = join9(ctx.braidDir, "service");
8655
8691
  const task = (name) => schtasksLabel(name);
8656
8692
  const legacyTask = (name) => legacySchtasksLabel(name);
8657
- const xmlPath = (name) => join8(serviceDir, `${task(name)}.xml`);
8658
- const wrapperPath = (name) => join8(serviceDir, `${task(name)}.cmd`);
8659
- const launcherPath = (name) => join8(serviceDir, `${task(name)}.vbs`);
8693
+ const xmlPath = (name) => join9(serviceDir, `${task(name)}.xml`);
8694
+ const wrapperPath = (name) => join9(serviceDir, `${task(name)}.cmd`);
8695
+ const launcherPath = (name) => join9(serviceDir, `${task(name)}.vbs`);
8660
8696
  const st = (...args) => ctx.exec("schtasks", args);
8661
8697
  const stx = async (...args) => {
8662
8698
  const res = await st(...args);
@@ -8667,18 +8703,18 @@ function win32Manager(ctx) {
8667
8703
  };
8668
8704
  const killBridgeProcess = async (name) => {
8669
8705
  const legacyAgents = legacyTwinPath(ctx.braidDir, ["agents"]);
8670
- const agentDirs = [join8(ctx.braidDir, "agents"), ...legacyAgents ? [legacyAgents] : []];
8706
+ const agentDirs = [join9(ctx.braidDir, "agents"), ...legacyAgents ? [legacyAgents] : []];
8671
8707
  const hostDirs = [];
8672
8708
  for (const agentsDir of agentDirs) {
8673
8709
  try {
8674
- for (const host of readdirSync4(agentsDir)) hostDirs.push(join8(agentsDir, host));
8710
+ for (const host of readdirSync4(agentsDir)) hostDirs.push(join9(agentsDir, host));
8675
8711
  } catch {
8676
8712
  }
8677
8713
  }
8678
8714
  for (const hostDir of hostDirs) {
8679
8715
  let pid = NaN;
8680
8716
  try {
8681
- pid = Number(readFileSync7(join8(hostDir, `${name}.json.lock`), "utf8").trim());
8717
+ pid = Number(readFileSync7(join9(hostDir, `${name}.json.lock`), "utf8").trim());
8682
8718
  } catch {
8683
8719
  continue;
8684
8720
  }
@@ -8722,7 +8758,7 @@ function win32Manager(ctx) {
8722
8758
  await st("/delete", "/tn", task(name), "/f");
8723
8759
  await st("/delete", "/tn", legacyTask(name), "/f");
8724
8760
  try {
8725
- unlinkSync3(join8(runDir(ctx.braidDir), `${name}.token`));
8761
+ unlinkSync3(join9(runDir(ctx.braidDir), `${name}.token`));
8726
8762
  } catch {
8727
8763
  }
8728
8764
  const legacyToken = legacyTwinPath(ctx.braidDir, ["run", `${name}.token`]);
@@ -8760,7 +8796,7 @@ function win32Manager(ctx) {
8760
8796
  return { installed, loaded, running };
8761
8797
  },
8762
8798
  logsPath(name) {
8763
- return join8(win32LogDir(ctx.homeDir), `${name}.err.log`);
8799
+ return join9(win32LogDir(ctx.homeDir), `${name}.err.log`);
8764
8800
  }
8765
8801
  };
8766
8802
  }
@@ -8774,7 +8810,7 @@ var NotSupportedError = class extends Error {
8774
8810
  };
8775
8811
  function makeServiceManager(platform, exec, deps = {}) {
8776
8812
  const homeDir = deps.homeDir ?? process.env.HOME ?? "";
8777
- const braidDir = deps.braidDir ?? join9(homeDir, ".braid");
8813
+ const braidDir = deps.braidDir ?? join10(homeDir, ".braid");
8778
8814
  const uid = deps.uid ?? (typeof process.getuid === "function" ? process.getuid() : 0);
8779
8815
  const nodePath = deps.nodePath ?? process.execPath;
8780
8816
  const entryPath = pinnedEntryPath({ braidDir });
@@ -8799,11 +8835,11 @@ function notSupportedManager(platform) {
8799
8835
  };
8800
8836
  }
8801
8837
  function darwinManager(ctx) {
8802
- const launchAgentsDir = join9(ctx.homeDir, "Library", "LaunchAgents");
8803
- const logDir = join9(ctx.homeDir, "Library", "Logs", "braid");
8804
- const legacyLogDir = join9(ctx.homeDir, "Library", "Logs", "arp-bridge");
8805
- const plistPath = (name) => join9(launchAgentsDir, `${launchdLabel(name)}.plist`);
8806
- const legacyPlistPath = (name) => join9(launchAgentsDir, `${legacyLaunchdLabel(name)}.plist`);
8838
+ const launchAgentsDir = join10(ctx.homeDir, "Library", "LaunchAgents");
8839
+ const logDir = join10(ctx.homeDir, "Library", "Logs", "braid");
8840
+ const legacyLogDir = join10(ctx.homeDir, "Library", "Logs", "arp-bridge");
8841
+ const plistPath = (name) => join10(launchAgentsDir, `${launchdLabel(name)}.plist`);
8842
+ const legacyPlistPath = (name) => join10(launchAgentsDir, `${legacyLaunchdLabel(name)}.plist`);
8807
8843
  const legacyInstalled = (name) => !existsSync6(plistPath(name)) && existsSync6(legacyPlistPath(name));
8808
8844
  const domainTarget = `gui/${ctx.uid}`;
8809
8845
  const serviceTarget = (name) => `${domainTarget}/${legacyInstalled(name) ? legacyLaunchdLabel(name) : launchdLabel(name)}`;
@@ -8868,16 +8904,16 @@ function darwinManager(ctx) {
8868
8904
  };
8869
8905
  },
8870
8906
  logsPath(name) {
8871
- return join9(legacyInstalled(name) ? legacyLogDir : logDir, `${name}.err.log`);
8907
+ return join10(legacyInstalled(name) ? legacyLogDir : logDir, `${name}.err.log`);
8872
8908
  }
8873
8909
  };
8874
8910
  }
8875
8911
  function linuxManager(ctx) {
8876
- const unitDir = join9(ctx.homeDir, ".config", "systemd", "user");
8912
+ const unitDir = join10(ctx.homeDir, ".config", "systemd", "user");
8877
8913
  const newUnitName = (name) => `braid-${name}.service`;
8878
8914
  const legacyUnitName = (name) => `arp-bridge-${name}.service`;
8879
- const newUnitPath = (name) => join9(unitDir, newUnitName(name));
8880
- const legacyUnitPath = (name) => join9(unitDir, legacyUnitName(name));
8915
+ const newUnitPath = (name) => join10(unitDir, newUnitName(name));
8916
+ const legacyUnitPath = (name) => join10(unitDir, legacyUnitName(name));
8881
8917
  const legacyInstalled = (name) => !existsSync6(newUnitPath(name)) && existsSync6(legacyUnitPath(name));
8882
8918
  const unitName = (name) => legacyInstalled(name) ? legacyUnitName(name) : newUnitName(name);
8883
8919
  const unitPath = (name) => legacyInstalled(name) ? legacyUnitPath(name) : newUnitPath(name);
@@ -9159,7 +9195,7 @@ function printStatusHuman(name, st, logsPath) {
9159
9195
 
9160
9196
  // src/service/serviceLog.ts
9161
9197
  import { createWriteStream, mkdirSync as mkdirSync8 } from "fs";
9162
- import { dirname as dirname6, join as join10 } from "path";
9198
+ import { dirname as dirname7, join as join11 } from "path";
9163
9199
 
9164
9200
  // src/service/logRotation.ts
9165
9201
  import {
@@ -9212,16 +9248,16 @@ function rotateLogFileIfNeeded(logPath, opts = {}) {
9212
9248
 
9213
9249
  // src/service/serviceLog.ts
9214
9250
  function darwinLogDir(homeDir) {
9215
- return join10(homeDir, "Library", "Logs", "braid");
9251
+ return join11(homeDir, "Library", "Logs", "braid");
9216
9252
  }
9217
9253
  function serviceLogTargets(name, platform, homeDir) {
9218
9254
  if (platform === "darwin") {
9219
9255
  const d = darwinLogDir(homeDir);
9220
- return [join10(d, `${name}.out.log`), join10(d, `${name}.err.log`)];
9256
+ return [join11(d, `${name}.out.log`), join11(d, `${name}.err.log`)];
9221
9257
  }
9222
9258
  if (platform === "win32") {
9223
9259
  const d = win32LogDir(homeDir);
9224
- return [join10(d, `${name}.out.log`), join10(d, `${name}.err.log`)];
9260
+ return [join11(d, `${name}.out.log`), join11(d, `${name}.err.log`)];
9225
9261
  }
9226
9262
  return [];
9227
9263
  }
@@ -9271,7 +9307,7 @@ function initServiceLogging(opts) {
9271
9307
  };
9272
9308
  }
9273
9309
  function defaultTeeStream(path4) {
9274
- mkdirSync8(dirname6(path4), { recursive: true });
9310
+ mkdirSync8(dirname7(path4), { recursive: true });
9275
9311
  const stream = createWriteStream(path4, { flags: "a" });
9276
9312
  stream.on("error", () => {
9277
9313
  });
@@ -9483,18 +9519,21 @@ async function main() {
9483
9519
  applyEnvAliases();
9484
9520
  installCrashGuard();
9485
9521
  const invocation = parseCliArgs(process.argv.slice(2));
9522
+ if (invocation.kind === "tui") {
9523
+ if (invocation.bare && !process.stdout.isTTY) {
9524
+ console.error(USAGE);
9525
+ process.exit(1);
9526
+ }
9527
+ const selfCli = fileURLToPath3(import.meta.url);
9528
+ process.exit(await runTui(invocation.args, process.env, selfCli));
9529
+ }
9486
9530
  if (invocation.kind === "usage") {
9487
9531
  if (invocation.error) console.error(`[braid] ${invocation.error}`);
9488
9532
  console.error(USAGE);
9489
9533
  process.exit(1);
9490
9534
  }
9491
9535
  if (invocation.kind === "version") {
9492
- try {
9493
- const pkg = JSON.parse(readFileSync9(new URL("../package.json", import.meta.url), "utf8"));
9494
- console.log(String(pkg.version ?? "unknown"));
9495
- } catch {
9496
- console.log("unknown");
9497
- }
9536
+ console.log(buildVersion() || "unknown");
9498
9537
  return;
9499
9538
  }
9500
9539
  if (invocation.kind === "list") {
@@ -9569,11 +9608,7 @@ async function main() {
9569
9608
  homeDir: process.env.HOME ?? homedir7()
9570
9609
  });
9571
9610
  }
9572
- try {
9573
- const pkg = JSON.parse(readFileSync9(new URL("../package.json", import.meta.url), "utf8"));
9574
- cfg.runtimeVersion = String(pkg.version ?? "");
9575
- } catch {
9576
- }
9611
+ cfg.runtimeVersion = buildVersion();
9577
9612
  {
9578
9613
  const dir = configDir(process.env);
9579
9614
  let file = "";
@@ -4,7 +4,7 @@ import {
4
4
  boundedJsonFetch,
5
5
  resetHttpMetricsForTest,
6
6
  snapshotHttpMetrics
7
- } from "./chunk-SKUYOAV5.js";
7
+ } from "./chunk-M5WUSDQN.js";
8
8
  export {
9
9
  assertHttpEndpoint,
10
10
  boundedJsonFetch,