@snowyroad/braid 0.74.0 → 0.76.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.
package/dist/cli.js CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  InviteExpiredError,
23
23
  KeystorePermsError,
24
24
  RebootstrapError,
25
+ STRICT_IPC_ENV_STRIP,
25
26
  acquireAgentLock,
26
27
  assertKeystorePerms,
27
28
  boundedJsonFetch,
@@ -46,16 +47,18 @@ import {
46
47
  pickRejectOptionId,
47
48
  pinEndpoint,
48
49
  readPathWithFallback,
49
- redactConfig,
50
50
  redeemInvite,
51
51
  relayHostSegment,
52
52
  resolveAgentSelection,
53
53
  resolveConfig,
54
+ resolveIpcProfile,
54
55
  resolveKnobs,
56
+ resolveScope,
55
57
  restoreTerminal,
56
58
  sanitizeForTty,
57
59
  saveAgent,
58
60
  snapshotHttpMetrics,
61
+ startingLines,
59
62
  takeDenialHint,
60
63
  toolModeLabel,
61
64
  toolStatusLine,
@@ -63,7 +66,7 @@ import {
63
66
  validateReplacementToken,
64
67
  verifyCardSignature,
65
68
  wsToHttp
66
- } from "./chunk-IARPNMQJ.js";
69
+ } from "./chunk-IBUDDALN.js";
67
70
 
68
71
  // src/health.ts
69
72
  var CEILING_STRIKES_TO_DEAD = 3;
@@ -2786,7 +2789,7 @@ var ActivityBeacon = class {
2786
2789
  // src/adapter.ts
2787
2790
  import { query } from "@anthropic-ai/claude-agent-sdk";
2788
2791
  import { accessSync, constants, existsSync, statSync } from "fs";
2789
- import { delimiter, dirname as dirname2, join as join3, resolve } from "path";
2792
+ import { delimiter, dirname as dirname2, join as join2, resolve } from "path";
2790
2793
  import { homedir } from "os";
2791
2794
 
2792
2795
  // src/acp/client.ts
@@ -3529,323 +3532,9 @@ function modelLaunchFor(agent, model) {
3529
3532
  // src/scope/sandbox.ts
3530
3533
  import { SandboxManager, SandboxRuntimeConfigSchema, installWindowsSandbox, getSrtWinPath } from "@anthropic-ai/sandbox-runtime";
3531
3534
  import path2 from "path";
3532
- import { realpathSync as realpathSync2 } from "fs";
3535
+ import { realpathSync } from "fs";
3533
3536
  import { spawnSync as nodeSpawnSync } from "child_process";
3534
3537
 
3535
- // src/scope/scopeConfig.ts
3536
- import { realpathSync, readdirSync, lstatSync } from "fs";
3537
- import { execSync } from "child_process";
3538
- import { join as join2 } from "path";
3539
- function resolveIpcProfile(scope, flagValue) {
3540
- if (flagValue !== void 0) return flagValue;
3541
- if (scope?.ipcProfile !== void 0) return scope.ipcProfile;
3542
- return "compat";
3543
- }
3544
- var STRICT_IPC_ENV_STRIP = [
3545
- "SSH_AUTH_SOCK",
3546
- "DOCKER_HOST",
3547
- "DBUS_SESSION_BUS_ADDRESS",
3548
- "DBUS_SYSTEM_BUS_ADDRESS",
3549
- "GPG_AGENT_INFO",
3550
- "DISPLAY",
3551
- "WAYLAND_DISPLAY"
3552
- ];
3553
- function strictIpcDenyRead(env, lstatFn = lstatSync) {
3554
- const base = ["/run", "/var/run", "/tmp/.X11-unix"];
3555
- const xdg = env["XDG_RUNTIME_DIR"];
3556
- const candidates = xdg ? (() => {
3557
- const segments = xdg.split("/").filter((s) => s.length > 0);
3558
- if (!xdg.startsWith("/") || segments.length < 2) {
3559
- console.warn(
3560
- `[braid] warn: XDG_RUNTIME_DIR="${xdg}" failed the sanity gate (must be absolute, not "/", and have \u22652 path segments) \u2014 skipping from strict IPC denyRead shroud`
3561
- );
3562
- return base;
3563
- }
3564
- return [...base, xdg];
3565
- })() : base;
3566
- return candidates.filter((p) => {
3567
- try {
3568
- return !lstatFn(p).isSymbolicLink();
3569
- } catch {
3570
- return true;
3571
- }
3572
- });
3573
- }
3574
- var DEFAULT_ALLOWED_DOMAINS = [
3575
- // Anthropic / Claude
3576
- "api.anthropic.com",
3577
- "*.anthropic.com",
3578
- // OpenAI / Codex
3579
- "api.openai.com",
3580
- // Google / Gemini
3581
- "generativelanguage.googleapis.com",
3582
- "*.googleapis.com",
3583
- // xAI / Grok
3584
- "api.x.ai",
3585
- // Cursor
3586
- "api.cursor.sh",
3587
- // opencode (BL-169): its serve process fetches the models.dev registry AT BOOT;
3588
- // without it opencode dies inside the jail (`ServeError` / ACP connection closed
3589
- // on every connect). `models.dev` is repro-CONFIRMED (blocked → 403, allowed →
3590
- // 200 through the srt proxy). `opencode.ai` (opencode's own service) and the
3591
- // ChatGPT-sign-in OAuth hosts are opencode's documented auth/boot endpoints
3592
- // (from the 2026-07-02 dry-run that hard-failed opencode). claude-code was
3593
- // unaffected because all its hosts were already listed above.
3594
- "models.dev",
3595
- "opencode.ai",
3596
- "*.opencode.ai",
3597
- "auth.openai.com",
3598
- "chatgpt.com",
3599
- // npm
3600
- "registry.npmjs.org",
3601
- "*.npmjs.org",
3602
- // PyPI
3603
- "pypi.org",
3604
- "files.pythonhosted.org",
3605
- // Go modules
3606
- "proxy.golang.org",
3607
- // Crates.io
3608
- "crates.io",
3609
- "static.crates.io",
3610
- // Source hosts
3611
- "github.com",
3612
- "*.github.com",
3613
- "*.githubusercontent.com",
3614
- "gitlab.com",
3615
- "bitbucket.org"
3616
- ];
3617
- var PROVIDER_PATHS = {
3618
- "claude-code": ["~/.claude", "~/.claude.json"],
3619
- codex: ["~/.codex"],
3620
- gemini: ["~/.gemini"],
3621
- grok: ["~/.grok"],
3622
- cursor: ["~/.cursor"],
3623
- opencode: ["~/.local/share/opencode", "~/.config/opencode"],
3624
- goose: ["~/.config/goose"],
3625
- cline: ["~/.cline"],
3626
- copilot: ["~/.copilot"],
3627
- qwen: ["~/.qwen"]
3628
- };
3629
- function expandHome(p, home) {
3630
- if (p.startsWith("~/")) return `${home}${p.slice(1)}`;
3631
- if (p === "~") return home;
3632
- return p;
3633
- }
3634
- function canonicalize(p) {
3635
- try {
3636
- return realpathSync(p);
3637
- } catch {
3638
- return p;
3639
- }
3640
- }
3641
- function parseEnvList(val) {
3642
- if (!val) return [];
3643
- return val.split(/[,:]/).map((s) => s.trim()).filter((s) => s.length > 0);
3644
- }
3645
- function dedup(arr) {
3646
- return [...new Set(arr)];
3647
- }
3648
- function darwinMdsCacheDir() {
3649
- try {
3650
- const cacheRoot = execSync("/usr/bin/getconf DARWIN_USER_CACHE_DIR", {
3651
- encoding: "utf8"
3652
- }).trim();
3653
- if (!cacheRoot) return [];
3654
- return [`${cacheRoot.replace(/\/+$/, "")}/mds`];
3655
- } catch {
3656
- return [];
3657
- }
3658
- }
3659
- function resolvePaths(paths, home) {
3660
- return dedup(paths.map((p) => canonicalize(expandHome(p, home))));
3661
- }
3662
- function foldCase(p, platform) {
3663
- return platform === "darwin" || platform === "win32" ? p.toLowerCase() : p;
3664
- }
3665
- function checkGrantsAgainstReservations(grants, reservations, platform) {
3666
- const sep2 = platform === "win32" ? "\\" : "/";
3667
- const out = [];
3668
- for (const g of grants) {
3669
- const gf = foldCase(g.path, platform);
3670
- for (const r of reservations) {
3671
- const rf = foldCase(r, platform);
3672
- if (gf === rf) {
3673
- out.push({ grant: g.path, source: g.source, reservation: r, relation: "equal" });
3674
- } else if (gf.startsWith(rf + sep2)) {
3675
- out.push({ grant: g.path, source: g.source, reservation: r, relation: "descendant" });
3676
- }
3677
- }
3678
- }
3679
- return out;
3680
- }
3681
- function resolveScope(cfg, provider, env, platform = process.platform) {
3682
- const scope = cfg.scope ?? {};
3683
- const home = env["HOME"] ?? "";
3684
- const cwd = env["PWD"] ?? process.cwd();
3685
- const tmpDir = env["TMPDIR"] ?? "/tmp";
3686
- const braidConfigDir = env["BRAID_CONFIG_DIR"]?.trim() || expandHome("~/.braid", home);
3687
- const legacyArpConfigDir = expandHome("~/.arp", home);
3688
- const protectedConfigDirs = braidConfigDir === legacyArpConfigDir ? [braidConfigDir] : [braidConfigDir, legacyArpConfigDir];
3689
- const flagOverride = cfg.scopeFlags?.scopeOverride;
3690
- const disabled = flagOverride !== void 0 ? flagOverride === "off" : scope.disabled === true || env["BRAID_SCOPE"] === "off";
3691
- const secretDirs = [
3692
- "~/.ssh",
3693
- "~/.aws",
3694
- "~/.gnupg",
3695
- "~/.kube/config"
3696
- ].map((p) => expandHome(p, home));
3697
- const protectedConfigDirEntries = protectedConfigDirs.flatMap((configDirPath) => {
3698
- if (platform !== "win32") return [configDirPath];
3699
- try {
3700
- const children = readdirSync(configDirPath, { withFileTypes: true });
3701
- const denied = children.filter((entry) => entry.name !== "runtime").map((entry) => canonicalize(join2(configDirPath, entry.name)));
3702
- if (denied.length === 0) return [configDirPath];
3703
- return denied;
3704
- } catch {
3705
- return [configDirPath];
3706
- }
3707
- });
3708
- const providerPaths = PROVIDER_PATHS[provider].map((p) => expandHome(p, home));
3709
- const uid = process.getuid?.();
3710
- const claudeTmpRoot = provider === "claude-code" && uid !== void 0 ? [`${canonicalize("/tmp")}/claude-${uid}`, `${canonicalize("/tmp")}/claude-*-cwd`] : [];
3711
- const mdsCacheDir = platform === "darwin" ? darwinMdsCacheDir() : [];
3712
- const opAllowWrite = (scope.allowWrite ?? []).map((p) => expandHome(p, home));
3713
- const envAllowWrite = parseEnvList(env["BRAID_SCOPE_ALLOW_WRITE"]).map((p) => expandHome(p, home));
3714
- const flagAllowWrite = (cfg.scopeFlags?.allowWrite ?? []).map((p) => expandHome(p, home));
3715
- const rawAllowWrite = [
3716
- cwd,
3717
- ...providerPaths,
3718
- ...claudeTmpRoot,
3719
- ...mdsCacheDir,
3720
- expandHome("~/.npm", home),
3721
- tmpDir,
3722
- ...opAllowWrite,
3723
- ...envAllowWrite,
3724
- ...flagAllowWrite
3725
- ];
3726
- const allowWrite = resolvePaths(rawAllowWrite, home);
3727
- const rawDenyWrite = [
3728
- ...secretDirs,
3729
- ...protectedConfigDirEntries,
3730
- ...(scope.denyWrite ?? []).map((p) => expandHome(p, home)),
3731
- ...parseEnvList(env["BRAID_SCOPE_DENY_WRITE"]).map((p) => expandHome(p, home))
3732
- ];
3733
- const denyWrite = resolvePaths(rawDenyWrite, home);
3734
- const ipcProfile = resolveIpcProfile(scope, cfg.scopeFlags?.ipcProfile);
3735
- const rawDenyRead = [
3736
- ...secretDirs,
3737
- ...protectedConfigDirEntries,
3738
- ...(scope.denyRead ?? []).map((p) => expandHome(p, home)),
3739
- ...parseEnvList(env["BRAID_SCOPE_DENY_READ"]).map((p) => expandHome(p, home))
3740
- ];
3741
- const denyRead = dedup([
3742
- ...resolvePaths(rawDenyRead, home),
3743
- ...ipcProfile === "strict" && platform === "linux" ? strictIpcDenyRead(env) : []
3744
- ]);
3745
- const opAllowRead = (scope.allowRead ?? []).map((p) => expandHome(p, home));
3746
- const envAllowRead = parseEnvList(env["BRAID_SCOPE_ALLOW_READ"]).map((p) => expandHome(p, home));
3747
- const flagAllowRead = (cfg.scopeFlags?.allowRead ?? []).map((p) => expandHome(p, home));
3748
- const rawAllowRead = [
3749
- ...opAllowRead,
3750
- ...envAllowRead,
3751
- ...flagAllowRead
3752
- ];
3753
- const allowRead = resolvePaths(rawAllowRead, home);
3754
- if (!disabled) {
3755
- const reservations = resolvePaths([...secretDirs, ...protectedConfigDirs], home);
3756
- const labelled = (paths, source) => resolvePaths(paths, home).map((p) => ({ path: p, source }));
3757
- const grants = [
3758
- ...labelled([cwd], "launch directory (cwd)"),
3759
- ...labelled(providerPaths, "provider default paths"),
3760
- ...labelled(opAllowWrite, "scope.allowWrite"),
3761
- ...labelled(envAllowWrite, "BRAID_SCOPE_ALLOW_WRITE"),
3762
- ...labelled(flagAllowWrite, "--allow-write"),
3763
- ...labelled(opAllowRead, "scope.allowRead"),
3764
- ...labelled(envAllowRead, "BRAID_SCOPE_ALLOW_READ"),
3765
- ...labelled(flagAllowRead, "--allow-read")
3766
- ];
3767
- const conflicts = checkGrantsAgainstReservations(grants, reservations, platform);
3768
- if (conflicts.length > 0) {
3769
- const detail = conflicts.map((c) => ` - ${c.source}: "${c.grant}" is ${c.relation === "equal" ? "" : "inside "}the protected path "${c.reservation}"`).join("\n");
3770
- throw new Error(
3771
- `[braid] SCOPE ERROR: a grant covers a protected credential/secret path and was refused:
3772
- ${detail}
3773
- Protected paths (never grantable): ${reservations.join(", ")}
3774
- Narrow the grant to a path outside the protected set. (Ancestor grants like "~" are fine \u2014 the protected dirs are carved back out automatically.)`
3775
- );
3776
- }
3777
- const writableDefaults = resolvePaths(
3778
- [...providerPaths, expandHome("~/.npm", home), tmpDir],
3779
- home
3780
- );
3781
- const resolvedConfigDir = canonicalize(braidConfigDir);
3782
- const placement = checkGrantsAgainstReservations(
3783
- [{ path: resolvedConfigDir, source: "BRAID_CONFIG_DIR" }],
3784
- writableDefaults,
3785
- platform
3786
- );
3787
- if (placement.length > 0) {
3788
- const c = placement[0];
3789
- throw new Error(
3790
- `[braid] SCOPE ERROR: BRAID_CONFIG_DIR ("${c.grant}") is ${c.relation === "equal" ? "" : "inside "}a default provider-writable location ("${c.reservation}"). The bridge credential store must live outside provider/tmp/npm paths. Move it (default: ~/.braid) or unset BRAID_CONFIG_DIR.`
3791
- );
3792
- }
3793
- }
3794
- const allowedDomains = dedup([
3795
- ...DEFAULT_ALLOWED_DOMAINS,
3796
- ...scope.network?.allowedDomains ?? [],
3797
- ...cfg.derivedAllowedDomains ?? [],
3798
- ...parseEnvList(env["BRAID_SCOPE_ALLOW_DOMAINS"]),
3799
- ...cfg.scopeFlags?.allowDomains ?? []
3800
- ]);
3801
- const deniedDomains = dedup([
3802
- ...scope.network?.deniedDomains ?? [],
3803
- ...parseEnvList(env["BRAID_SCOPE_DENY_DOMAINS"])
3804
- ]);
3805
- function describe() {
3806
- const lines = [];
3807
- if (disabled) {
3808
- lines.push("[scope] SANDBOX DISABLED (BRAID_SCOPE=off or scope.disabled:true) \u2014 agent runs unconfined");
3809
- return lines;
3810
- }
3811
- lines.push("[scope] Agent sandbox is ACTIVE");
3812
- lines.push(
3813
- `[scope] protected (never readable/writable by the agent): ${resolvePaths([...secretDirs, ...protectedConfigDirs], home).join(", ")}`
3814
- );
3815
- lines.push(`[scope] cwd (writable): ${cwd}`);
3816
- if (providerPaths.length > 0) {
3817
- lines.push(`[scope] provider paths (writable): ${providerPaths.join(", ")}`);
3818
- }
3819
- lines.push(`[scope] allowed domains (${allowedDomains.length}): ${allowedDomains.slice(0, 5).join(", ")}${allowedDomains.length > 5 ? " ..." : ""}`);
3820
- if ((cfg.derivedAllowedDomains ?? []).length > 0) {
3821
- lines.push(`[scope] model endpoints (derived): ${(cfg.derivedAllowedDomains ?? []).join(", ")}`);
3822
- }
3823
- lines.push(`[scope] denied read: ${denyRead.join(", ")}`);
3824
- if (denyWrite.length > 0) {
3825
- lines.push(`[scope] denied write: ${denyWrite.join(", ")}`);
3826
- }
3827
- if (deniedDomains.length > 0) {
3828
- lines.push(`[scope] denied domains: ${deniedDomains.join(", ")}`);
3829
- }
3830
- if (ipcProfile === "compat") {
3831
- lines.push("[scope] ipc profile: compat \u2014 all unix sockets reachable inside the jail (Linux seccomp constraint)");
3832
- } else {
3833
- lines.push("[scope] ipc profile: strict \u2014 /run, /var/run, XDG_RUNTIME_DIR, /tmp/.X11-unix hidden; socket env vars stripped");
3834
- }
3835
- lines.push("[scope] To widen: add paths to scope.allowWrite/allowRead in agent config, or BRAID_SCOPE_ALLOW_WRITE/BRAID_SCOPE=off env.");
3836
- return lines;
3837
- }
3838
- return {
3839
- runtimeConfig: {
3840
- filesystem: { allowWrite, denyWrite, allowRead, denyRead },
3841
- network: { allowedDomains, deniedDomains }
3842
- },
3843
- disabled,
3844
- ipcProfile,
3845
- describe
3846
- };
3847
- }
3848
-
3849
3538
  // src/mcp/broker.ts
3850
3539
  import http from "http";
3851
3540
  import os from "os";
@@ -4201,7 +3890,7 @@ function brokerSocketNetworkExtras() {
4201
3890
  const dir = brokerSocketDir();
4202
3891
  const subpaths = [dir];
4203
3892
  try {
4204
- const resolved = path2.join(realpathSync2(path2.dirname(dir)), path2.basename(dir));
3893
+ const resolved = path2.join(realpathSync(path2.dirname(dir)), path2.basename(dir));
4205
3894
  if (resolved !== dir) subpaths.push(resolved);
4206
3895
  } catch {
4207
3896
  }
@@ -4397,13 +4086,13 @@ function pinned(pkg) {
4397
4086
  function computeNpxLaunch(platform, execPath, exists) {
4398
4087
  const nodeDir = dirname2(execPath);
4399
4088
  if (platform === "win32") {
4400
- const npxCliJs = join3(nodeDir, "node_modules", "npm", "bin", "npx-cli.js");
4089
+ const npxCliJs = join2(nodeDir, "node_modules", "npm", "bin", "npx-cli.js");
4401
4090
  if (exists(npxCliJs)) {
4402
4091
  return { command: execPath, argsPrefix: [npxCliJs] };
4403
4092
  }
4404
4093
  }
4405
4094
  for (const name of ["npx", "npx.cmd"]) {
4406
- const candidate = join3(nodeDir, name);
4095
+ const candidate = join2(nodeDir, name);
4407
4096
  if (exists(candidate)) {
4408
4097
  return { command: candidate, argsPrefix: [] };
4409
4098
  }
@@ -4426,7 +4115,7 @@ function which(cmd, pathEnv = process.env.PATH ?? "", platform = process.platfor
4426
4115
  const name = platform === "win32" && !cmd.toLowerCase().endsWith(".exe") ? `${cmd}.exe` : cmd;
4427
4116
  for (const dir of pathEnv.split(delimiter)) {
4428
4117
  if (!dir) continue;
4429
- const candidate = join3(dir, name);
4118
+ const candidate = join2(dir, name);
4430
4119
  try {
4431
4120
  accessSync(candidate, constants.X_OK);
4432
4121
  if (statSync(candidate).isFile()) return resolve(candidate);
@@ -4554,8 +4243,8 @@ function launchSpecFor(agent) {
4554
4243
  }
4555
4244
  }
4556
4245
  function handoffFallbackDirs(name, home) {
4557
- const dirs = [join3(home, ".local", "bin")];
4558
- if (name === "claude") dirs.push(join3(home, ".claude", "local"));
4246
+ const dirs = [join2(home, ".local", "bin")];
4247
+ if (name === "claude") dirs.push(join2(home, ".claude", "local"));
4559
4248
  return dirs;
4560
4249
  }
4561
4250
  function findHandoffBinary(name, pathEnv = process.env.PATH ?? "", home = homedir(), platform = process.platform) {
@@ -5171,8 +4860,8 @@ function withTimeout(p, ms) {
5171
4860
  }
5172
4861
 
5173
4862
  // src/cardFromDisk.ts
5174
- import { readdirSync as readdirSync2, readFileSync as readFileSync2, lstatSync as lstatSync2 } from "fs";
5175
- import { join as join4, relative, sep } from "path";
4863
+ import { readdirSync, readFileSync as readFileSync2, lstatSync } from "fs";
4864
+ import { join as join3, relative, sep } from "path";
5176
4865
  import { homedir as homedir2 } from "os";
5177
4866
 
5178
4867
  // src/skillMd.ts
@@ -5226,22 +4915,22 @@ function parseSkillFrontmatter(raw) {
5226
4915
  var MAX_DESC = 500;
5227
4916
  var MAX_NAME = 100;
5228
4917
  var MAX_SKILLS = 200;
5229
- var skillsRoot = () => process.env.BRAID_SKILLS_DIR ?? join4(homedir2(), ".claude", "skills");
5230
- var pluginsRoot = () => process.env.BRAID_PLUGINS_DIR ?? join4(homedir2(), ".claude", "plugins");
4918
+ var skillsRoot = () => process.env.BRAID_SKILLS_DIR ?? join3(homedir2(), ".claude", "skills");
4919
+ var pluginsRoot = () => process.env.BRAID_PLUGINS_DIR ?? join3(homedir2(), ".claude", "plugins");
5231
4920
  function collectSkillMd(root) {
5232
4921
  const out = [];
5233
4922
  const walk = (dir) => {
5234
4923
  let entries;
5235
4924
  try {
5236
- entries = readdirSync2(dir);
4925
+ entries = readdirSync(dir);
5237
4926
  } catch {
5238
4927
  return;
5239
4928
  }
5240
4929
  for (const name of entries) {
5241
- const full = join4(dir, name);
4930
+ const full = join3(dir, name);
5242
4931
  let st;
5243
4932
  try {
5244
- st = lstatSync2(full);
4933
+ st = lstatSync(full);
5245
4934
  } catch {
5246
4935
  continue;
5247
4936
  }
@@ -5329,20 +5018,20 @@ import {
5329
5018
  writeFileSync as writeFileSync2,
5330
5019
  renameSync as renameSync2,
5331
5020
  chmodSync as chmodSync2,
5332
- readdirSync as readdirSync3,
5021
+ readdirSync as readdirSync2,
5333
5022
  statSync as statSync2,
5334
5023
  existsSync as existsSync2
5335
5024
  } from "fs";
5336
5025
  import { createHash } from "crypto";
5337
5026
  import { homedir as homedir3 } from "os";
5338
- import { join as join5, dirname as dirname3 } from "path";
5027
+ import { join as join4, dirname as dirname3 } from "path";
5339
5028
  function safe2(s) {
5340
5029
  return s.replace(/[^a-zA-Z0-9._-]/g, "_");
5341
5030
  }
5342
5031
  function cardCacheFilePath(cfg) {
5343
5032
  const dir = configDir(process.env);
5344
5033
  const safeName = safe2(cfg.agentName);
5345
- return join5(dir, "card-cache", relayHostSegment(cfg.relayWsUrl), `${safeName}.json`);
5034
+ return join4(dir, "card-cache", relayHostSegment(cfg.relayWsUrl), `${safeName}.json`);
5346
5035
  }
5347
5036
  function cardCacheReadPath(cfg) {
5348
5037
  return readPathWithFallback(
@@ -5356,12 +5045,12 @@ function collectSkillMdPaths(root) {
5356
5045
  function walk(dir) {
5357
5046
  let entries;
5358
5047
  try {
5359
- entries = readdirSync3(dir);
5048
+ entries = readdirSync2(dir);
5360
5049
  } catch {
5361
5050
  return;
5362
5051
  }
5363
5052
  for (const entry of entries) {
5364
- const full = join5(dir, entry);
5053
+ const full = join4(dir, entry);
5365
5054
  let st;
5366
5055
  try {
5367
5056
  st = statSync2(full);
@@ -5378,7 +5067,7 @@ function collectSkillMdPaths(root) {
5378
5067
  walk(root);
5379
5068
  return out;
5380
5069
  }
5381
- function computeCapabilityFingerprint(cfg, skillsDir = process.env.BRAID_SKILLS_DIR ?? join5(homedir3(), ".claude", "skills"), pluginsDir = process.env.BRAID_PLUGINS_DIR ?? join5(homedir3(), ".claude", "plugins")) {
5070
+ function computeCapabilityFingerprint(cfg, skillsDir = process.env.BRAID_SKILLS_DIR ?? join4(homedir3(), ".claude", "skills"), pluginsDir = process.env.BRAID_PLUGINS_DIR ?? join4(homedir3(), ".claude", "plugins")) {
5382
5071
  const paths1 = collectSkillMdPaths(skillsDir);
5383
5072
  const paths2 = collectSkillMdPaths(pluginsDir);
5384
5073
  const allPaths = [...paths1, ...paths2].sort();
@@ -5517,11 +5206,11 @@ function installCrashGuard() {
5517
5206
 
5518
5207
  // src/service/needsHumanMarker.ts
5519
5208
  import { mkdirSync as mkdirSync5, chmodSync as chmodSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync6, existsSync as existsSync6, unlinkSync as unlinkSync2 } from "fs";
5520
- import { join as join8 } from "path";
5209
+ import { join as join7 } from "path";
5521
5210
 
5522
5211
  // src/service/install.ts
5523
- import { existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync5 } from "fs";
5524
- import { join as join7 } from "path";
5212
+ import { existsSync as existsSync5, readdirSync as readdirSync4, readFileSync as readFileSync5 } from "fs";
5213
+ import { join as join6 } from "path";
5525
5214
 
5526
5215
  // src/service/runtime.ts
5527
5216
  import {
@@ -5529,30 +5218,30 @@ import {
5529
5218
  mkdirSync as mkdirSync3,
5530
5219
  readFileSync as readFileSync4,
5531
5220
  writeFileSync as writeFileSync3,
5532
- readdirSync as readdirSync4,
5221
+ readdirSync as readdirSync3,
5533
5222
  renameSync as renameSync3,
5534
5223
  rmSync,
5535
5224
  symlinkSync,
5536
5225
  readlinkSync,
5537
- lstatSync as lstatSync3,
5226
+ lstatSync as lstatSync2,
5538
5227
  existsSync as existsSync3
5539
5228
  } from "fs";
5540
5229
  import { execFileSync } from "child_process";
5541
5230
  import { createHash as createHash2 } from "crypto";
5542
- import { dirname as dirname4, join as join6 } from "path";
5231
+ import { dirname as dirname4, join as join5 } from "path";
5543
5232
  import { homedir as homedir4 } from "os";
5544
5233
  import { fileURLToPath } from "url";
5545
5234
  function defaultBraidDir() {
5546
5235
  const override = process.env.BRAID_CONFIG_DIR?.trim();
5547
- return override && override !== "" ? override : join6(homedir4(), ".braid");
5236
+ return override && override !== "" ? override : join5(homedir4(), ".braid");
5548
5237
  }
5549
5238
  function runtimeRootForRead(braidDir, platform) {
5550
- const primary = join6(braidDir, "runtime");
5551
- const markerOf = (root) => platform === "win32" ? currentTxtPath(root) : join6(root, "current");
5239
+ const primary = join5(braidDir, "runtime");
5240
+ const markerOf = (root) => platform === "win32" ? currentTxtPath(root) : join5(root, "current");
5552
5241
  if (existsSync3(markerOf(primary))) return primary;
5553
5242
  const override = process.env.BRAID_CONFIG_DIR?.trim();
5554
- if (!override && braidDir === join6(homedir4(), ".braid")) {
5555
- const legacy = join6(homedir4(), ".arp", "runtime");
5243
+ if (!override && braidDir === join5(homedir4(), ".braid")) {
5244
+ const legacy = join5(homedir4(), ".arp", "runtime");
5556
5245
  if (existsSync3(markerOf(legacy))) return legacy;
5557
5246
  }
5558
5247
  return primary;
@@ -5560,7 +5249,7 @@ function runtimeRootForRead(braidDir, platform) {
5560
5249
  function runningPackageRoot() {
5561
5250
  let dir = dirname4(fileURLToPath(import.meta.url));
5562
5251
  for (let i = 0; i < 6; i++) {
5563
- if (existsSync3(join6(dir, "package.json")) && existsSync3(join6(dir, "dist"))) return dir;
5252
+ if (existsSync3(join5(dir, "package.json")) && existsSync3(join5(dir, "dist"))) return dir;
5564
5253
  const parent = dirname4(dir);
5565
5254
  if (parent === dir) break;
5566
5255
  dir = parent;
@@ -5568,13 +5257,13 @@ function runningPackageRoot() {
5568
5257
  return dirname4(dirname4(fileURLToPath(import.meta.url)));
5569
5258
  }
5570
5259
  function currentTxtPath(runtimeRoot) {
5571
- return join6(runtimeRoot, "current.txt");
5260
+ return join5(runtimeRoot, "current.txt");
5572
5261
  }
5573
5262
  function pinCurrentRuntime(opts = {}) {
5574
5263
  const sourceDir = opts.sourceDir ?? runningPackageRoot();
5575
5264
  const braidDir = opts.braidDir ?? defaultBraidDir();
5576
5265
  const platform = opts.platform ?? process.platform;
5577
- const pkg = JSON.parse(readFileSync4(join6(sourceDir, "package.json"), "utf8"));
5266
+ const pkg = JSON.parse(readFileSync4(join5(sourceDir, "package.json"), "utf8"));
5578
5267
  const version = String(pkg.version ?? "").trim();
5579
5268
  if (version === "") throw new Error(`cannot pin runtime: package.json at ${sourceDir} has no version`);
5580
5269
  if (!/^\d+\.\d+\.\d+$/.test(version)) {
@@ -5583,20 +5272,20 @@ function pinCurrentRuntime(opts = {}) {
5583
5272
  );
5584
5273
  }
5585
5274
  const prodDeps = Object.keys(pkg.dependencies ?? {});
5586
- const runtimeRoot = join6(braidDir, "runtime");
5587
- const versionDir = join6(runtimeRoot, version);
5275
+ const runtimeRoot = join5(braidDir, "runtime");
5276
+ const versionDir = join5(runtimeRoot, version);
5588
5277
  mkdirSync3(versionDir, { recursive: true });
5589
- cpSync(join6(sourceDir, "dist"), join6(versionDir, "dist"), { recursive: true, force: true });
5590
- cpSync(join6(sourceDir, "package.json"), join6(versionDir, "package.json"), { force: true });
5591
- const shrinkwrapSrc = join6(sourceDir, "npm-shrinkwrap.json");
5278
+ cpSync(join5(sourceDir, "dist"), join5(versionDir, "dist"), { recursive: true, force: true });
5279
+ cpSync(join5(sourceDir, "package.json"), join5(versionDir, "package.json"), { force: true });
5280
+ const shrinkwrapSrc = join5(sourceDir, "npm-shrinkwrap.json");
5592
5281
  const hasShrinkwrap = existsSync3(shrinkwrapSrc);
5593
5282
  if (hasShrinkwrap) {
5594
- cpSync(shrinkwrapSrc, join6(versionDir, "npm-shrinkwrap.json"), { force: true });
5283
+ cpSync(shrinkwrapSrc, join5(versionDir, "npm-shrinkwrap.json"), { force: true });
5595
5284
  }
5596
5285
  const method = populateNodeModules(sourceDir, versionDir, prodDeps, hasShrinkwrap, opts.exec);
5597
- const shrinkwrapSha256 = hasShrinkwrap ? createHash2("sha256").update(readFileSync4(join6(versionDir, "npm-shrinkwrap.json"))).digest("hex") : null;
5286
+ const shrinkwrapSha256 = hasShrinkwrap ? createHash2("sha256").update(readFileSync4(join5(versionDir, "npm-shrinkwrap.json"))).digest("hex") : null;
5598
5287
  writeFileSync3(
5599
- join6(versionDir, "closure.json"),
5288
+ join5(versionDir, "closure.json"),
5600
5289
  JSON.stringify({ method, shrinkwrapSha256 }, null, 2) + "\n"
5601
5290
  );
5602
5291
  const previousVersion = installedRuntimeVersion({ braidDir, platform });
@@ -5612,12 +5301,12 @@ function pinCurrentRuntime(opts = {}) {
5612
5301
  function populateNodeModules(sourceDir, versionDir, prodDeps, hasShrinkwrap, exec) {
5613
5302
  if (prodDeps.length === 0) return "none";
5614
5303
  const marker = prodDeps[0];
5615
- const dest = join6(versionDir, "node_modules");
5304
+ const dest = join5(versionDir, "node_modules");
5616
5305
  const plainTree = findCopyableNodeModules(sourceDir, marker);
5617
5306
  if (plainTree) {
5618
5307
  rmSync(dest, { recursive: true, force: true });
5619
5308
  cpSync(plainTree, dest, { recursive: true, force: true });
5620
- if (existsSync3(join6(dest, marker))) return "copy";
5309
+ if (existsSync3(join5(dest, marker))) return "copy";
5621
5310
  rmSync(dest, { recursive: true, force: true });
5622
5311
  }
5623
5312
  return npmInstallProdDeps(versionDir, marker, hasShrinkwrap, exec);
@@ -5625,10 +5314,10 @@ function populateNodeModules(sourceDir, versionDir, prodDeps, hasShrinkwrap, exe
5625
5314
  function findCopyableNodeModules(sourceDir, marker) {
5626
5315
  let dir = sourceDir;
5627
5316
  for (let i = 0; i < 8; i++) {
5628
- const nm = join6(dir, "node_modules");
5629
- const markerPath = join6(nm, marker);
5317
+ const nm = join5(dir, "node_modules");
5318
+ const markerPath = join5(nm, marker);
5630
5319
  if (existsSync3(markerPath)) {
5631
- if (!lstatSync3(markerPath).isSymbolicLink()) return nm;
5320
+ if (!lstatSync2(markerPath).isSymbolicLink()) return nm;
5632
5321
  return null;
5633
5322
  }
5634
5323
  const parent = dirname4(dir);
@@ -5655,7 +5344,7 @@ function npmInstallProdDeps(versionDir, marker, hasShrinkwrap, exec) {
5655
5344
  `pinned runtime at ${versionDir} could not obtain its production dependencies (\`npm ${args[0]}\` failed \u2014 npm missing, no network, or shrinkwrap/platform mismatch?). Fix and re-run, or the service will crash-loop with ERR_MODULE_NOT_FOUND. Underlying error: ${detail}`
5656
5345
  );
5657
5346
  }
5658
- if (!existsSync3(join6(versionDir, "node_modules", marker))) {
5347
+ if (!existsSync3(join5(versionDir, "node_modules", marker))) {
5659
5348
  throw new Error(
5660
5349
  `pinned runtime at ${versionDir} is missing dependency "${marker}" after \`npm ${args[0]}\`. Refusing to leave a runtime that will crash-loop with ERR_MODULE_NOT_FOUND.`
5661
5350
  );
@@ -5667,7 +5356,7 @@ function pruneOldVersions(runtimeRoot, currentVersion, previousVersion) {
5667
5356
  if (previousVersion && previousVersion !== currentVersion) keep.add(previousVersion);
5668
5357
  let entries;
5669
5358
  try {
5670
- entries = readdirSync4(runtimeRoot);
5359
+ entries = readdirSync3(runtimeRoot);
5671
5360
  } catch {
5672
5361
  return;
5673
5362
  }
@@ -5676,9 +5365,9 @@ function pruneOldVersions(runtimeRoot, currentVersion, previousVersion) {
5676
5365
  if (name === "current.txt") continue;
5677
5366
  if (name.startsWith("current.tmp.")) continue;
5678
5367
  if (keep.has(name)) continue;
5679
- const dir = join6(runtimeRoot, name);
5368
+ const dir = join5(runtimeRoot, name);
5680
5369
  try {
5681
- if (!lstatSync3(dir).isDirectory()) continue;
5370
+ if (!lstatSync2(dir).isDirectory()) continue;
5682
5371
  } catch {
5683
5372
  continue;
5684
5373
  }
@@ -5687,8 +5376,8 @@ function pruneOldVersions(runtimeRoot, currentVersion, previousVersion) {
5687
5376
  }
5688
5377
  function flipCurrentSymlink(runtimeRoot, version) {
5689
5378
  mkdirSync3(runtimeRoot, { recursive: true });
5690
- const current = join6(runtimeRoot, "current");
5691
- const tmp = join6(runtimeRoot, `current.tmp.${process.pid}.${Date.now()}`);
5379
+ const current = join5(runtimeRoot, "current");
5380
+ const tmp = join5(runtimeRoot, `current.tmp.${process.pid}.${Date.now()}`);
5692
5381
  try {
5693
5382
  rmSync(tmp, { force: true });
5694
5383
  } catch {
@@ -5708,7 +5397,7 @@ function installedRuntimeVersion(q = {}) {
5708
5397
  return null;
5709
5398
  }
5710
5399
  }
5711
- const current = join6(runtimeRoot, "current");
5400
+ const current = join5(runtimeRoot, "current");
5712
5401
  try {
5713
5402
  const target = readlinkSync(current);
5714
5403
  return target.split("/").pop() ?? null;
@@ -5721,9 +5410,9 @@ function pinnedEntryPath(q = {}) {
5721
5410
  const platform = q.platform ?? process.platform;
5722
5411
  if (platform === "win32") {
5723
5412
  const version = installedRuntimeVersion({ braidDir, platform });
5724
- if (version) return join6(braidDir, "runtime", version, "dist", "cli.js");
5413
+ if (version) return join5(braidDir, "runtime", version, "dist", "cli.js");
5725
5414
  }
5726
- return join6(braidDir, "runtime", "current", "dist", "cli.js");
5415
+ return join5(braidDir, "runtime", "current", "dist", "cli.js");
5727
5416
  }
5728
5417
  function installedClosureRecord(q = {}) {
5729
5418
  const braidDir = q.braidDir ?? defaultBraidDir();
@@ -5731,7 +5420,7 @@ function installedClosureRecord(q = {}) {
5731
5420
  const version = installedRuntimeVersion(q);
5732
5421
  if (!version) return null;
5733
5422
  try {
5734
- const raw = JSON.parse(readFileSync4(join6(runtimeRootForRead(braidDir, platform), version, "closure.json"), "utf8"));
5423
+ const raw = JSON.parse(readFileSync4(join5(runtimeRootForRead(braidDir, platform), version, "closure.json"), "utf8"));
5735
5424
  if (typeof raw.method !== "string") return null;
5736
5425
  return {
5737
5426
  method: raw.method,
@@ -6017,13 +5706,13 @@ function validateServiceKey(name) {
6017
5706
  return trimmed;
6018
5707
  }
6019
5708
  function runDir(braidDir) {
6020
- return join7(braidDir, "run");
5709
+ return join6(braidDir, "run");
6021
5710
  }
6022
5711
  function controlSocketPath(name, braidDir, platform = process.platform) {
6023
5712
  if (platform === "win32") {
6024
5713
  return `\\\\.\\pipe\\braid-${name}`;
6025
5714
  }
6026
- return join7(runDir(braidDir), `${name}.sock`);
5715
+ return join6(runDir(braidDir), `${name}.sock`);
6027
5716
  }
6028
5717
  function legacyControlSocketPath(name, platform = process.platform) {
6029
5718
  if (platform !== "win32") return null;
@@ -6047,7 +5736,7 @@ function controlSocketReadPath(name, braidDir, platform = process.platform) {
6047
5736
  }
6048
5737
  function controlTokenPath(name, braidDir, platform = process.platform) {
6049
5738
  if (platform !== "win32") return null;
6050
- return join7(runDir(braidDir), `${name}.token`);
5739
+ return join6(runDir(braidDir), `${name}.token`);
6051
5740
  }
6052
5741
  function readControlToken(name, braidDir, platform = process.platform) {
6053
5742
  let p = controlTokenPath(name, braidDir, platform);
@@ -6093,7 +5782,7 @@ function sleep(ms) {
6093
5782
  }
6094
5783
  function enumerateInstalledServices(platform, deps) {
6095
5784
  if (platform === "darwin") {
6096
- const dir = join7(deps.homeDir, "Library", "LaunchAgents");
5785
+ const dir = join6(deps.homeDir, "Library", "LaunchAgents");
6097
5786
  return dedupe([
6098
5787
  ...globNames(dir, /^com\.snowyroad\.braid\.(.+)\.plist$/),
6099
5788
  ...globNames(dir, /^dev\.arp\.bridge\.(.+)\.plist$/)
@@ -6101,7 +5790,7 @@ function enumerateInstalledServices(platform, deps) {
6101
5790
  ]);
6102
5791
  }
6103
5792
  if (platform === "linux") {
6104
- const dir = join7(deps.homeDir, ".config", "systemd", "user");
5793
+ const dir = join6(deps.homeDir, ".config", "systemd", "user");
6105
5794
  return dedupe([
6106
5795
  ...globNames(dir, /^braid-(.+)\.service$/),
6107
5796
  ...globNames(dir, /^arp-bridge-(.+)\.service$/)
@@ -6115,19 +5804,19 @@ function dedupe(names) {
6115
5804
  }
6116
5805
  function isLegacyFamilyService(platform, name, homeDir) {
6117
5806
  if (platform === "darwin") {
6118
- const dir = join7(homeDir, "Library", "LaunchAgents");
6119
- return !existsSync5(join7(dir, `com.snowyroad.braid.${name}.plist`)) && existsSync5(join7(dir, `dev.arp.bridge.${name}.plist`));
5807
+ const dir = join6(homeDir, "Library", "LaunchAgents");
5808
+ return !existsSync5(join6(dir, `com.snowyroad.braid.${name}.plist`)) && existsSync5(join6(dir, `dev.arp.bridge.${name}.plist`));
6120
5809
  }
6121
5810
  if (platform === "linux") {
6122
- const dir = join7(homeDir, ".config", "systemd", "user");
6123
- return !existsSync5(join7(dir, `braid-${name}.service`)) && existsSync5(join7(dir, `arp-bridge-${name}.service`));
5811
+ const dir = join6(homeDir, ".config", "systemd", "user");
5812
+ return !existsSync5(join6(dir, `braid-${name}.service`)) && existsSync5(join6(dir, `arp-bridge-${name}.service`));
6124
5813
  }
6125
5814
  return false;
6126
5815
  }
6127
5816
  function globNames(dir, pattern) {
6128
5817
  let entries = [];
6129
5818
  try {
6130
- entries = readdirSync5(dir);
5819
+ entries = readdirSync4(dir);
6131
5820
  } catch {
6132
5821
  return [];
6133
5822
  }
@@ -6171,7 +5860,7 @@ async function updateInstalled(opts) {
6171
5860
 
6172
5861
  // src/service/needsHumanMarker.ts
6173
5862
  function needsHumanMarkerPath(name, braidDir) {
6174
- return join8(runDir(braidDir), `${name}.needs-human`);
5863
+ return join7(runDir(braidDir), `${name}.needs-human`);
6175
5864
  }
6176
5865
  function writeNeedsHumanMarker(name, reason, braidDir) {
6177
5866
  try {
@@ -7913,7 +7602,7 @@ import { homedir as homedir6 } from "os";
7913
7602
 
7914
7603
  // src/service/manager.ts
7915
7604
  import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, rmSync as rmSync2, existsSync as existsSync7 } from "fs";
7916
- import { join as join10 } from "path";
7605
+ import { join as join9 } from "path";
7917
7606
 
7918
7607
  // src/service/templates.ts
7919
7608
  function escapeXml(s) {
@@ -8084,18 +7773,18 @@ function schtasksXml(p) {
8084
7773
  }
8085
7774
 
8086
7775
  // src/service/win32.ts
8087
- import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6, readFileSync as readFileSync7, unlinkSync as unlinkSync3 } from "fs";
8088
- import { join as join9 } from "path";
7776
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync5, readFileSync as readFileSync7, unlinkSync as unlinkSync3 } from "fs";
7777
+ import { join as join8 } from "path";
8089
7778
  function win32LogDir(homeDir) {
8090
- return join9(homeDir, "AppData", "Local", "braid", "logs");
7779
+ return join8(homeDir, "AppData", "Local", "braid", "logs");
8091
7780
  }
8092
7781
  function win32Manager(ctx) {
8093
- const serviceDir = join9(ctx.braidDir, "service");
7782
+ const serviceDir = join8(ctx.braidDir, "service");
8094
7783
  const task = (name) => schtasksLabel(name);
8095
7784
  const legacyTask = (name) => legacySchtasksLabel(name);
8096
- const xmlPath = (name) => join9(serviceDir, `${task(name)}.xml`);
8097
- const wrapperPath = (name) => join9(serviceDir, `${task(name)}.cmd`);
8098
- const launcherPath = (name) => join9(serviceDir, `${task(name)}.vbs`);
7785
+ const xmlPath = (name) => join8(serviceDir, `${task(name)}.xml`);
7786
+ const wrapperPath = (name) => join8(serviceDir, `${task(name)}.cmd`);
7787
+ const launcherPath = (name) => join8(serviceDir, `${task(name)}.vbs`);
8099
7788
  const st = (...args) => ctx.exec("schtasks", args);
8100
7789
  const stx = async (...args) => {
8101
7790
  const res = await st(...args);
@@ -8106,18 +7795,18 @@ function win32Manager(ctx) {
8106
7795
  };
8107
7796
  const killBridgeProcess = async (name) => {
8108
7797
  const legacyAgents = legacyTwinPath(ctx.braidDir, ["agents"]);
8109
- const agentDirs = [join9(ctx.braidDir, "agents"), ...legacyAgents ? [legacyAgents] : []];
7798
+ const agentDirs = [join8(ctx.braidDir, "agents"), ...legacyAgents ? [legacyAgents] : []];
8110
7799
  const hostDirs = [];
8111
7800
  for (const agentsDir of agentDirs) {
8112
7801
  try {
8113
- for (const host of readdirSync6(agentsDir)) hostDirs.push(join9(agentsDir, host));
7802
+ for (const host of readdirSync5(agentsDir)) hostDirs.push(join8(agentsDir, host));
8114
7803
  } catch {
8115
7804
  }
8116
7805
  }
8117
7806
  for (const hostDir of hostDirs) {
8118
7807
  let pid = NaN;
8119
7808
  try {
8120
- pid = Number(readFileSync7(join9(hostDir, `${name}.json.lock`), "utf8").trim());
7809
+ pid = Number(readFileSync7(join8(hostDir, `${name}.json.lock`), "utf8").trim());
8121
7810
  } catch {
8122
7811
  continue;
8123
7812
  }
@@ -8161,7 +7850,7 @@ function win32Manager(ctx) {
8161
7850
  await st("/delete", "/tn", task(name), "/f");
8162
7851
  await st("/delete", "/tn", legacyTask(name), "/f");
8163
7852
  try {
8164
- unlinkSync3(join9(runDir(ctx.braidDir), `${name}.token`));
7853
+ unlinkSync3(join8(runDir(ctx.braidDir), `${name}.token`));
8165
7854
  } catch {
8166
7855
  }
8167
7856
  const legacyToken = legacyTwinPath(ctx.braidDir, ["run", `${name}.token`]);
@@ -8199,7 +7888,7 @@ function win32Manager(ctx) {
8199
7888
  return { installed, loaded, running };
8200
7889
  },
8201
7890
  logsPath(name) {
8202
- return join9(win32LogDir(ctx.homeDir), `${name}.err.log`);
7891
+ return join8(win32LogDir(ctx.homeDir), `${name}.err.log`);
8203
7892
  }
8204
7893
  };
8205
7894
  }
@@ -8213,7 +7902,7 @@ var NotSupportedError = class extends Error {
8213
7902
  };
8214
7903
  function makeServiceManager(platform, exec, deps = {}) {
8215
7904
  const homeDir = deps.homeDir ?? process.env.HOME ?? "";
8216
- const braidDir = deps.braidDir ?? join10(homeDir, ".braid");
7905
+ const braidDir = deps.braidDir ?? join9(homeDir, ".braid");
8217
7906
  const uid = deps.uid ?? (typeof process.getuid === "function" ? process.getuid() : 0);
8218
7907
  const nodePath = deps.nodePath ?? process.execPath;
8219
7908
  const entryPath = pinnedEntryPath({ braidDir });
@@ -8238,11 +7927,11 @@ function notSupportedManager(platform) {
8238
7927
  };
8239
7928
  }
8240
7929
  function darwinManager(ctx) {
8241
- const launchAgentsDir = join10(ctx.homeDir, "Library", "LaunchAgents");
8242
- const logDir = join10(ctx.homeDir, "Library", "Logs", "braid");
8243
- const legacyLogDir = join10(ctx.homeDir, "Library", "Logs", "arp-bridge");
8244
- const plistPath = (name) => join10(launchAgentsDir, `${launchdLabel(name)}.plist`);
8245
- const legacyPlistPath = (name) => join10(launchAgentsDir, `${legacyLaunchdLabel(name)}.plist`);
7930
+ const launchAgentsDir = join9(ctx.homeDir, "Library", "LaunchAgents");
7931
+ const logDir = join9(ctx.homeDir, "Library", "Logs", "braid");
7932
+ const legacyLogDir = join9(ctx.homeDir, "Library", "Logs", "arp-bridge");
7933
+ const plistPath = (name) => join9(launchAgentsDir, `${launchdLabel(name)}.plist`);
7934
+ const legacyPlistPath = (name) => join9(launchAgentsDir, `${legacyLaunchdLabel(name)}.plist`);
8246
7935
  const legacyInstalled = (name) => !existsSync7(plistPath(name)) && existsSync7(legacyPlistPath(name));
8247
7936
  const domainTarget = `gui/${ctx.uid}`;
8248
7937
  const serviceTarget = (name) => `${domainTarget}/${legacyInstalled(name) ? legacyLaunchdLabel(name) : launchdLabel(name)}`;
@@ -8307,16 +7996,16 @@ function darwinManager(ctx) {
8307
7996
  };
8308
7997
  },
8309
7998
  logsPath(name) {
8310
- return join10(legacyInstalled(name) ? legacyLogDir : logDir, `${name}.err.log`);
7999
+ return join9(legacyInstalled(name) ? legacyLogDir : logDir, `${name}.err.log`);
8311
8000
  }
8312
8001
  };
8313
8002
  }
8314
8003
  function linuxManager(ctx) {
8315
- const unitDir = join10(ctx.homeDir, ".config", "systemd", "user");
8004
+ const unitDir = join9(ctx.homeDir, ".config", "systemd", "user");
8316
8005
  const newUnitName = (name) => `braid-${name}.service`;
8317
8006
  const legacyUnitName = (name) => `arp-bridge-${name}.service`;
8318
- const newUnitPath = (name) => join10(unitDir, newUnitName(name));
8319
- const legacyUnitPath = (name) => join10(unitDir, legacyUnitName(name));
8007
+ const newUnitPath = (name) => join9(unitDir, newUnitName(name));
8008
+ const legacyUnitPath = (name) => join9(unitDir, legacyUnitName(name));
8320
8009
  const legacyInstalled = (name) => !existsSync7(newUnitPath(name)) && existsSync7(legacyUnitPath(name));
8321
8010
  const unitName = (name) => legacyInstalled(name) ? legacyUnitName(name) : newUnitName(name);
8322
8011
  const unitPath = (name) => legacyInstalled(name) ? legacyUnitPath(name) : newUnitPath(name);
@@ -8598,7 +8287,7 @@ function printStatusHuman(name, st, logsPath) {
8598
8287
 
8599
8288
  // src/service/serviceLog.ts
8600
8289
  import { createWriteStream, mkdirSync as mkdirSync8 } from "fs";
8601
- import { dirname as dirname6, join as join11 } from "path";
8290
+ import { dirname as dirname6, join as join10 } from "path";
8602
8291
 
8603
8292
  // src/service/logRotation.ts
8604
8293
  import {
@@ -8651,16 +8340,16 @@ function rotateLogFileIfNeeded(logPath, opts = {}) {
8651
8340
 
8652
8341
  // src/service/serviceLog.ts
8653
8342
  function darwinLogDir(homeDir) {
8654
- return join11(homeDir, "Library", "Logs", "braid");
8343
+ return join10(homeDir, "Library", "Logs", "braid");
8655
8344
  }
8656
8345
  function serviceLogTargets(name, platform, homeDir) {
8657
8346
  if (platform === "darwin") {
8658
8347
  const d = darwinLogDir(homeDir);
8659
- return [join11(d, `${name}.out.log`), join11(d, `${name}.err.log`)];
8348
+ return [join10(d, `${name}.out.log`), join10(d, `${name}.err.log`)];
8660
8349
  }
8661
8350
  if (platform === "win32") {
8662
8351
  const d = win32LogDir(homeDir);
8663
- return [join11(d, `${name}.out.log`), join11(d, `${name}.err.log`)];
8352
+ return [join10(d, `${name}.out.log`), join10(d, `${name}.err.log`)];
8664
8353
  }
8665
8354
  return [];
8666
8355
  }
@@ -9026,7 +8715,7 @@ async function main() {
9026
8715
  }
9027
8716
  assertKeystorePerms(dir, file);
9028
8717
  }
9029
- console.log("[braid] starting", redactConfig(cfg));
8718
+ console.log(banner("braid", "STARTING", startingLines(cfg)));
9030
8719
  if (cfg.toolMode === "full") {
9031
8720
  console.error(
9032
8721
  "[braid] WARNING full tool access: remote channel content can drive local tool use on this machine"