claudemesh-cli 1.27.2 → 1.28.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.
@@ -103,7 +103,7 @@ __export(exports_urls, {
103
103
  VERSION: () => VERSION,
104
104
  URLS: () => URLS
105
105
  });
106
- var URLS, VERSION = "1.27.2", env;
106
+ var URLS, VERSION = "1.28.0", env;
107
107
  var init_urls = __esm(() => {
108
108
  URLS = {
109
109
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -150,6 +150,32 @@ function normaliseInviteUrl(input, host = "claudemesh.com") {
150
150
  return trimmed;
151
151
  }
152
152
 
153
+ // src/services/daemon/policy.ts
154
+ function readEnvDefault() {
155
+ if (process.env.CLAUDEMESH_NO_DAEMON === "1")
156
+ return { mode: "no-daemon" };
157
+ if (process.env.CLAUDEMESH_STRICT_DAEMON === "1")
158
+ return { mode: "strict" };
159
+ return { mode: "auto" };
160
+ }
161
+ function setDaemonPolicy(mode) {
162
+ policy = { mode };
163
+ }
164
+ function getDaemonPolicy() {
165
+ return policy;
166
+ }
167
+ function policyFromFlags(flags) {
168
+ if (flags["no-daemon"])
169
+ return "no-daemon";
170
+ if (flags.strict)
171
+ return "strict";
172
+ return readEnvDefault().mode;
173
+ }
174
+ var policy;
175
+ var init_policy = __esm(() => {
176
+ policy = readEnvDefault();
177
+ });
178
+
153
179
  // src/constants/paths.ts
154
180
  import { homedir as homedir2 } from "node:os";
155
181
  import { join as join2 } from "node:path";
@@ -3588,12 +3614,6 @@ var init_spinner = __esm(() => {
3588
3614
  });
3589
3615
 
3590
3616
  // src/daemon/paths.ts
3591
- var exports_paths = {};
3592
- __export(exports_paths, {
3593
- DAEMON_TCP_HOST: () => DAEMON_TCP_HOST,
3594
- DAEMON_TCP_DEFAULT_PORT: () => DAEMON_TCP_DEFAULT_PORT,
3595
- DAEMON_PATHS: () => DAEMON_PATHS
3596
- });
3597
3617
  import { join as join3 } from "node:path";
3598
3618
  var DAEMON_PATHS, DAEMON_TCP_HOST = "127.0.0.1", DAEMON_TCP_DEFAULT_PORT = 47823;
3599
3619
  var init_paths2 = __esm(() => {
@@ -3623,6 +3643,255 @@ var init_paths2 = __esm(() => {
3623
3643
  };
3624
3644
  });
3625
3645
 
3646
+ // src/daemon/local-token.ts
3647
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
3648
+ import { dirname as dirname2 } from "node:path";
3649
+ import { randomBytes as randomBytes4 } from "node:crypto";
3650
+ function readLocalToken() {
3651
+ try {
3652
+ return readFileSync4(DAEMON_PATHS.TOKEN_FILE, "utf8").trim();
3653
+ } catch {
3654
+ return null;
3655
+ }
3656
+ }
3657
+ function ensureLocalToken() {
3658
+ const existing = readLocalToken();
3659
+ if (existing)
3660
+ return existing;
3661
+ mkdirSync3(dirname2(DAEMON_PATHS.TOKEN_FILE), { recursive: true, mode: 448 });
3662
+ const tok = randomBytes4(32).toString("base64url");
3663
+ writeFileSync4(DAEMON_PATHS.TOKEN_FILE, tok + `
3664
+ `, { mode: 384 });
3665
+ return tok;
3666
+ }
3667
+ var init_local_token = __esm(() => {
3668
+ init_paths2();
3669
+ });
3670
+
3671
+ // src/daemon/ipc/client.ts
3672
+ import { request as httpRequest } from "node:http";
3673
+ async function ipc(opts) {
3674
+ const useTcp = !!opts.preferTcp;
3675
+ const headers = {
3676
+ accept: "application/json",
3677
+ host: "localhost"
3678
+ };
3679
+ let bodyBuf;
3680
+ if (opts.body !== undefined) {
3681
+ bodyBuf = Buffer.from(JSON.stringify(opts.body), "utf8");
3682
+ headers["content-type"] = "application/json";
3683
+ headers["content-length"] = String(bodyBuf.length);
3684
+ }
3685
+ if (useTcp) {
3686
+ const tok = readLocalToken();
3687
+ if (!tok)
3688
+ throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
3689
+ headers.authorization = `Bearer ${tok}`;
3690
+ }
3691
+ return new Promise((resolve, reject) => {
3692
+ const req = httpRequest(useTcp ? { host: DAEMON_TCP_HOST, port: DAEMON_TCP_DEFAULT_PORT, path: opts.path, method: opts.method ?? "GET", headers } : { socketPath: DAEMON_PATHS.SOCK_FILE, path: opts.path, method: opts.method ?? "GET", headers }, (res) => {
3693
+ const chunks = [];
3694
+ res.on("data", (c) => chunks.push(c));
3695
+ res.on("end", () => {
3696
+ const raw = Buffer.concat(chunks).toString("utf8");
3697
+ let parsed = raw;
3698
+ try {
3699
+ parsed = raw.length > 0 ? JSON.parse(raw) : null;
3700
+ } catch {}
3701
+ resolve({ status: res.statusCode ?? 0, body: parsed });
3702
+ });
3703
+ });
3704
+ req.setTimeout(opts.timeoutMs ?? 5000, () => req.destroy(new Error("ipc_timeout")));
3705
+ req.on("error", (err) => reject(err));
3706
+ if (bodyBuf)
3707
+ req.write(bodyBuf);
3708
+ req.end();
3709
+ });
3710
+ }
3711
+ var IpcError;
3712
+ var init_client3 = __esm(() => {
3713
+ init_paths2();
3714
+ init_local_token();
3715
+ IpcError = class IpcError extends Error {
3716
+ status;
3717
+ payload;
3718
+ constructor(status, payload, msg) {
3719
+ super(msg);
3720
+ this.status = status;
3721
+ this.payload = payload;
3722
+ }
3723
+ };
3724
+ });
3725
+
3726
+ // src/services/daemon/lifecycle.ts
3727
+ var exports_lifecycle = {};
3728
+ __export(exports_lifecycle, {
3729
+ ensureDaemonReady: () => ensureDaemonReady,
3730
+ _resetDaemonReadyCache: () => _resetDaemonReadyCache
3731
+ });
3732
+ import { existsSync as existsSync5, readFileSync as readFileSync5, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
3733
+ import { join as join4 } from "node:path";
3734
+ async function ensureDaemonReady(opts = {}) {
3735
+ if (lastResultThisProcess && (lastResultThisProcess.state === "up" || lastResultThisProcess.state === "started")) {
3736
+ return lastResultThisProcess;
3737
+ }
3738
+ if (process.env.CLAUDEMESH_INTERNAL_NO_AUTOSPAWN === "1") {
3739
+ opts = { ...opts, noAutoSpawn: true };
3740
+ }
3741
+ const result = await runEnsureDaemon(opts);
3742
+ lastResultThisProcess = result;
3743
+ return result;
3744
+ }
3745
+ function _resetDaemonReadyCache() {
3746
+ lastResultThisProcess = null;
3747
+ }
3748
+ async function runEnsureDaemon(opts) {
3749
+ const t0 = Date.now();
3750
+ const probe = await probeDaemon();
3751
+ if (probe === "up")
3752
+ return { state: "up", durationMs: Date.now() - t0 };
3753
+ if (probe === "stale")
3754
+ cleanupStaleFiles();
3755
+ if (opts.noAutoSpawn) {
3756
+ return { state: "down", durationMs: Date.now() - t0, reason: "auto-spawn disabled" };
3757
+ }
3758
+ if (recentSpawnFailureFresh()) {
3759
+ return {
3760
+ state: "spawn-suppressed",
3761
+ durationMs: Date.now() - t0,
3762
+ reason: `daemon failed to start within last ${Math.round(SPAWN_FAIL_TTL_MS / 1000)}s`
3763
+ };
3764
+ }
3765
+ const spawnRes = await spawnDaemon(opts);
3766
+ if (spawnRes.ok) {
3767
+ return { state: "started", durationMs: Date.now() - t0 };
3768
+ }
3769
+ markSpawnFailure();
3770
+ return { state: "spawn-failed", durationMs: Date.now() - t0, reason: spawnRes.reason };
3771
+ }
3772
+ async function probeDaemon() {
3773
+ if (!existsSync5(DAEMON_PATHS.SOCK_FILE))
3774
+ return "absent";
3775
+ try {
3776
+ const res = await ipc({ path: "/v1/version", timeoutMs: PROBE_TIMEOUT_MS });
3777
+ if (res.status === 200)
3778
+ return "up";
3779
+ return "stale";
3780
+ } catch (err) {
3781
+ if (err instanceof IpcError)
3782
+ return "stale";
3783
+ const msg = String(err);
3784
+ if (/ENOENT|ECONNREFUSED|ipc_timeout|EPIPE|ECONNRESET/.test(msg))
3785
+ return "stale";
3786
+ return "stale";
3787
+ }
3788
+ }
3789
+ function cleanupStaleFiles() {
3790
+ for (const p of [DAEMON_PATHS.SOCK_FILE, DAEMON_PATHS.PID_FILE]) {
3791
+ try {
3792
+ unlinkSync2(p);
3793
+ } catch {}
3794
+ }
3795
+ }
3796
+ function recentSpawnFailureFresh() {
3797
+ try {
3798
+ const st = statSync(SPAWN_FAIL_FILE());
3799
+ return Date.now() - st.mtimeMs < SPAWN_FAIL_TTL_MS;
3800
+ } catch {
3801
+ return false;
3802
+ }
3803
+ }
3804
+ function markSpawnFailure() {
3805
+ try {
3806
+ writeFileSync5(SPAWN_FAIL_FILE(), String(Date.now()), { mode: 384 });
3807
+ } catch {}
3808
+ }
3809
+ function clearSpawnFailure() {
3810
+ try {
3811
+ unlinkSync2(SPAWN_FAIL_FILE());
3812
+ } catch {}
3813
+ }
3814
+ async function spawnDaemon(opts) {
3815
+ const lockResult = await acquireOrShareLock(opts);
3816
+ if (lockResult === "wait-existing") {
3817
+ return await pollForSocket(opts.budgetMs ?? 3000);
3818
+ }
3819
+ try {
3820
+ const { spawn } = await import("node:child_process");
3821
+ const binary = await resolveCliBinary();
3822
+ const args = ["daemon", "up"];
3823
+ if (opts.mesh)
3824
+ args.push("--mesh", opts.mesh);
3825
+ const child = spawn(binary, args, {
3826
+ detached: true,
3827
+ stdio: "ignore",
3828
+ env: { ...process.env, CLAUDEMESH_INTERNAL_NO_AUTOSPAWN: "1" }
3829
+ });
3830
+ child.unref();
3831
+ const polled = await pollForSocket(opts.budgetMs ?? 3000);
3832
+ if (polled.ok)
3833
+ clearSpawnFailure();
3834
+ return polled;
3835
+ } catch (err) {
3836
+ return { ok: false, reason: err instanceof Error ? err.message : String(err) };
3837
+ } finally {
3838
+ releaseLock();
3839
+ }
3840
+ }
3841
+ async function acquireOrShareLock(_opts) {
3842
+ const lockPath = SPAWN_LOCK_FILE();
3843
+ if (existsSync5(lockPath)) {
3844
+ try {
3845
+ const pidStr = readFileSync5(lockPath, "utf8").trim();
3846
+ const pid = Number.parseInt(pidStr, 10);
3847
+ if (Number.isFinite(pid) && pid > 0) {
3848
+ try {
3849
+ process.kill(pid, 0);
3850
+ return "wait-existing";
3851
+ } catch {}
3852
+ }
3853
+ } catch {}
3854
+ }
3855
+ try {
3856
+ writeFileSync5(lockPath, String(process.pid), { mode: 384 });
3857
+ } catch {}
3858
+ return "acquired";
3859
+ }
3860
+ function releaseLock() {
3861
+ try {
3862
+ unlinkSync2(SPAWN_LOCK_FILE());
3863
+ } catch {}
3864
+ }
3865
+ async function pollForSocket(budgetMs) {
3866
+ const start = Date.now();
3867
+ while (Date.now() - start < budgetMs) {
3868
+ if (existsSync5(DAEMON_PATHS.SOCK_FILE)) {
3869
+ const probe = await probeDaemon();
3870
+ if (probe === "up")
3871
+ return { ok: true };
3872
+ }
3873
+ await new Promise((r) => setTimeout(r, 150));
3874
+ }
3875
+ return { ok: false, reason: `socket did not appear within ${budgetMs}ms` };
3876
+ }
3877
+ async function resolveCliBinary() {
3878
+ const argv1 = process.argv[1] ?? "claudemesh";
3879
+ if (/\.ts$/.test(argv1) || /node_modules|src\/entrypoints/.test(argv1)) {
3880
+ try {
3881
+ const { execSync } = await import("node:child_process");
3882
+ return execSync("which claudemesh", { encoding: "utf8" }).trim() || "claudemesh";
3883
+ } catch {
3884
+ return "claudemesh";
3885
+ }
3886
+ }
3887
+ return argv1;
3888
+ }
3889
+ var SPAWN_LOCK_FILE = () => join4(DAEMON_PATHS.DAEMON_DIR, ".spawn.lock"), SPAWN_FAIL_FILE = () => join4(DAEMON_PATHS.DAEMON_DIR, ".spawn-failure"), SPAWN_FAIL_TTL_MS = 30000, PROBE_TIMEOUT_MS = 800, lastResultThisProcess = null;
3890
+ var init_lifecycle = __esm(() => {
3891
+ init_client3();
3892
+ init_paths2();
3893
+ });
3894
+
3626
3895
  // src/commands/launch.ts
3627
3896
  var exports_launch = {};
3628
3897
  __export(exports_launch, {
@@ -3630,42 +3899,26 @@ __export(exports_launch, {
3630
3899
  });
3631
3900
  import { spawnSync as spawnSync2 } from "node:child_process";
3632
3901
  import { randomUUID } from "node:crypto";
3633
- import { mkdtempSync, writeFileSync as writeFileSync4, rmSync, readdirSync, statSync, existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
3902
+ import { mkdtempSync, writeFileSync as writeFileSync6, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
3634
3903
  import { tmpdir, hostname as hostname2, homedir as homedir3 } from "node:os";
3635
- import { join as join4 } from "node:path";
3904
+ import { join as join5 } from "node:path";
3636
3905
  import { createInterface as createInterface4 } from "node:readline";
3637
3906
  async function ensureDaemonRunning(meshSlug, quiet) {
3638
- const { DAEMON_PATHS: DAEMON_PATHS2 } = await Promise.resolve().then(() => (init_paths2(), exports_paths));
3639
- if (existsSync5(DAEMON_PATHS2.SOCK_FILE))
3640
- return;
3907
+ const { ensureDaemonReady: ensureDaemonReady2 } = await Promise.resolve().then(() => (init_lifecycle(), exports_lifecycle));
3641
3908
  if (!quiet)
3642
- render.info("starting claudemesh daemon…");
3643
- const { spawn } = await import("node:child_process");
3644
- const argv0 = process.argv[1] ?? "claudemesh";
3645
- let binary = argv0;
3646
- if (/\.ts$/.test(binary) || /node_modules|src\/entrypoints/.test(binary)) {
3647
- try {
3648
- const { execSync } = await import("node:child_process");
3649
- binary = execSync("which claudemesh", { encoding: "utf8" }).trim();
3650
- } catch {
3651
- binary = "claudemesh";
3652
- }
3909
+ render.info("ensuring claudemesh daemon is running…");
3910
+ const res = await ensureDaemonReady2({ budgetMs: 1e4, mesh: meshSlug });
3911
+ if (res.state === "up") {
3912
+ if (!quiet)
3913
+ render.ok("daemon already running");
3914
+ return;
3653
3915
  }
3654
- const child = spawn(binary, ["daemon", "up", "--mesh", meshSlug], {
3655
- detached: true,
3656
- stdio: "ignore"
3657
- });
3658
- child.unref();
3659
- const start = Date.now();
3660
- while (Date.now() - start < 1e4) {
3661
- if (existsSync5(DAEMON_PATHS2.SOCK_FILE)) {
3662
- if (!quiet)
3663
- render.ok("daemon ready");
3664
- return;
3665
- }
3666
- await new Promise((r) => setTimeout(r, 200));
3916
+ if (res.state === "started") {
3917
+ if (!quiet)
3918
+ render.ok(`daemon ready (${res.durationMs}ms)`);
3919
+ return;
3667
3920
  }
3668
- render.warn("daemon failed to start within 10s", "Run `claudemesh daemon up --mesh " + meshSlug + "` manually, then re-launch.");
3921
+ render.warn(`daemon ${res.state}${res.reason ? `: ${res.reason}` : ""}`, "Run `claudemesh daemon up --mesh " + meshSlug + "` manually, then re-launch.");
3669
3922
  }
3670
3923
  function parseGroupsString(raw) {
3671
3924
  return raw.split(",").map((s) => s.trim()).filter(Boolean).map((token) => {
@@ -3986,17 +4239,17 @@ async function runLaunch(flags, rawArgs) {
3986
4239
  for (const entry of readdirSync(tmpBase)) {
3987
4240
  if (!entry.startsWith("claudemesh-"))
3988
4241
  continue;
3989
- const full = join4(tmpBase, entry);
3990
- const age = Date.now() - statSync(full).mtimeMs;
4242
+ const full = join5(tmpBase, entry);
4243
+ const age = Date.now() - statSync2(full).mtimeMs;
3991
4244
  if (age > 3600000)
3992
4245
  rmSync(full, { recursive: true, force: true });
3993
4246
  }
3994
4247
  } catch {}
3995
4248
  await ensureDaemonRunning(mesh.slug, args.quiet);
3996
4249
  try {
3997
- const claudeConfigPath = join4(homedir3(), ".claude.json");
3998
- if (existsSync5(claudeConfigPath)) {
3999
- const claudeConfig = JSON.parse(readFileSync4(claudeConfigPath, "utf-8"));
4250
+ const claudeConfigPath = join5(homedir3(), ".claude.json");
4251
+ if (existsSync6(claudeConfigPath)) {
4252
+ const claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
4000
4253
  const mcpServers = claudeConfig.mcpServers ?? {};
4001
4254
  let cleaned = 0;
4002
4255
  for (const key of Object.keys(mcpServers)) {
@@ -4014,7 +4267,7 @@ async function runLaunch(flags, rawArgs) {
4014
4267
  }
4015
4268
  if (cleaned > 0) {
4016
4269
  claudeConfig.mcpServers = mcpServers;
4017
- writeFileSync4(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4270
+ writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4018
4271
  `, "utf-8");
4019
4272
  }
4020
4273
  }
@@ -4031,7 +4284,7 @@ async function runLaunch(flags, rawArgs) {
4031
4284
  console.log(" (Could not fetch service catalog — mesh services won't be natively available)");
4032
4285
  }
4033
4286
  }
4034
- const tmpDir = mkdtempSync(join4(tmpdir(), "claudemesh-"));
4287
+ const tmpDir = mkdtempSync(join5(tmpdir(), "claudemesh-"));
4035
4288
  const sessionConfig = {
4036
4289
  version: 1,
4037
4290
  meshes: [mesh],
@@ -4040,17 +4293,17 @@ async function runLaunch(flags, rawArgs) {
4040
4293
  ...parsedGroups.length > 0 ? { groups: parsedGroups } : {},
4041
4294
  messageMode
4042
4295
  };
4043
- writeFileSync4(join4(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4296
+ writeFileSync6(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4044
4297
  `, "utf-8");
4045
4298
  if (!args.quiet) {
4046
4299
  printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
4047
4300
  }
4048
4301
  const meshMcpEntries = [];
4049
4302
  if (serviceCatalog.length > 0) {
4050
- const claudeConfigPath = join4(homedir3(), ".claude.json");
4303
+ const claudeConfigPath = join5(homedir3(), ".claude.json");
4051
4304
  let claudeConfig = {};
4052
4305
  try {
4053
- claudeConfig = JSON.parse(readFileSync4(claudeConfigPath, "utf-8"));
4306
+ claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
4054
4307
  } catch {
4055
4308
  claudeConfig = {};
4056
4309
  }
@@ -4077,7 +4330,7 @@ async function runLaunch(flags, rawArgs) {
4077
4330
  meshMcpEntries.push({ key: entryKey, entry });
4078
4331
  }
4079
4332
  claudeConfig.mcpServers = mcpServers;
4080
- writeFileSync4(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4333
+ writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4081
4334
  `, "utf-8");
4082
4335
  if (!args.quiet && meshMcpEntries.length > 0) {
4083
4336
  console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
@@ -4114,12 +4367,12 @@ async function runLaunch(flags, rawArgs) {
4114
4367
  let claudeBin = "claude";
4115
4368
  if (!isWindows2) {
4116
4369
  const candidates = [
4117
- join4(homedir3(), ".local", "bin", "claude"),
4370
+ join5(homedir3(), ".local", "bin", "claude"),
4118
4371
  "/usr/local/bin/claude",
4119
- join4(homedir3(), ".claude", "bin", "claude")
4372
+ join5(homedir3(), ".claude", "bin", "claude")
4120
4373
  ];
4121
4374
  for (const c of candidates) {
4122
- if (existsSync5(c)) {
4375
+ if (existsSync6(c)) {
4123
4376
  claudeBin = c;
4124
4377
  break;
4125
4378
  }
@@ -4128,14 +4381,14 @@ async function runLaunch(flags, rawArgs) {
4128
4381
  const cleanup = () => {
4129
4382
  if (meshMcpEntries.length > 0) {
4130
4383
  try {
4131
- const claudeConfigPath = join4(homedir3(), ".claude.json");
4132
- const claudeConfig = JSON.parse(readFileSync4(claudeConfigPath, "utf-8"));
4384
+ const claudeConfigPath = join5(homedir3(), ".claude.json");
4385
+ const claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
4133
4386
  const mcpServers = claudeConfig.mcpServers ?? {};
4134
4387
  for (const { key } of meshMcpEntries) {
4135
4388
  delete mcpServers[key];
4136
4389
  }
4137
4390
  claudeConfig.mcpServers = mcpServers;
4138
- writeFileSync4(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4391
+ writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4139
4392
  `, "utf-8");
4140
4393
  } catch {}
4141
4394
  }
@@ -4832,8 +5085,8 @@ __export(exports_join, {
4832
5085
  runJoin: () => runJoin
4833
5086
  });
4834
5087
  import sodium3 from "libsodium-wrappers";
4835
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "node:fs";
4836
- import { join as join5, dirname as dirname2 } from "node:path";
5088
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync4 } from "node:fs";
5089
+ import { join as join6, dirname as dirname3 } from "node:path";
4837
5090
  import { homedir as homedir4, hostname as hostname3 } from "node:os";
4838
5091
  function deriveAppBaseUrl() {
4839
5092
  const override = process.env.CLAUDEMESH_APP_URL;
@@ -4953,11 +5206,11 @@ async function runJoin(args) {
4953
5206
  joinedAt: new Date().toISOString()
4954
5207
  });
4955
5208
  writeConfig(config);
4956
- const configDir = env.CLAUDEMESH_CONFIG_DIR ?? join5(homedir4(), ".claudemesh");
4957
- const inviteFile = join5(configDir, `invite-${payload.mesh_slug}.txt`);
5209
+ const configDir = env.CLAUDEMESH_CONFIG_DIR ?? join6(homedir4(), ".claudemesh");
5210
+ const inviteFile = join6(configDir, `invite-${payload.mesh_slug}.txt`);
4958
5211
  try {
4959
- mkdirSync3(dirname2(inviteFile), { recursive: true });
4960
- writeFileSync5(inviteFile, link, "utf-8");
5212
+ mkdirSync4(dirname3(inviteFile), { recursive: true });
5213
+ writeFileSync7(inviteFile, link, "utf-8");
4961
5214
  } catch {}
4962
5215
  console.log("");
4963
5216
  console.log(`✓ Joined "${payload.mesh_slug}" as ${displayName}${enroll.alreadyMember ? " (already a member — re-enrolled with same pubkey)" : ""}`);
@@ -6472,6 +6725,12 @@ async function pickMesh(meshes) {
6472
6725
  });
6473
6726
  }
6474
6727
  async function withMesh(opts, fn) {
6728
+ if (getDaemonPolicy().mode === "strict") {
6729
+ console.error(`
6730
+ ✘ daemon not reachable — --strict refuses cold-path fallback.
6731
+ ` + " run `claudemesh daemon up` (or `claudemesh doctor`) and retry.\n");
6732
+ process.exit(1);
6733
+ }
6475
6734
  const config = readConfig();
6476
6735
  if (config.meshes.length === 0) {
6477
6736
  console.error("No meshes joined. Run `claudemesh join <url>` first.");
@@ -6522,6 +6781,7 @@ async function withMesh(opts, fn) {
6522
6781
  var init_connect = __esm(() => {
6523
6782
  init_facade8();
6524
6783
  init_facade();
6784
+ init_policy();
6525
6785
  });
6526
6786
 
6527
6787
  // src/commands/info.ts
@@ -7158,185 +7418,43 @@ var init_ban = __esm(() => {
7158
7418
  init_exit_codes();
7159
7419
  });
7160
7420
 
7161
- // src/services/bridge/protocol.ts
7162
- import { homedir as homedir5 } from "node:os";
7163
- import { join as join6 } from "node:path";
7164
- function socketPath(meshSlug) {
7165
- return join6(homedir5(), ".claudemesh", "sockets", `${meshSlug}.sock`);
7166
- }
7167
- function frame(obj) {
7168
- return JSON.stringify(obj) + `
7169
- `;
7170
- }
7171
-
7172
- class LineParser {
7173
- buf = "";
7174
- feed(chunk) {
7175
- this.buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
7176
- const lines = [];
7177
- let nl = this.buf.indexOf(`
7421
+ // src/ui/warnings.ts
7422
+ function warnDaemonState(res, opts = {}) {
7423
+ if (alreadyWarned)
7424
+ return false;
7425
+ if (opts.quiet || opts.json)
7426
+ return false;
7427
+ if (res.state === "up")
7428
+ return false;
7429
+ if (getDaemonPolicy().mode === "strict" && res.state !== "started")
7430
+ return false;
7431
+ alreadyWarned = true;
7432
+ const tag = (label) => `[claudemesh] ${label}`;
7433
+ const hint = (s) => dim(s);
7434
+ switch (res.state) {
7435
+ case "started":
7436
+ process.stderr.write(`${tag("info")} daemon restarted automatically ${hint(`(took ${res.durationMs}ms)`)}
7178
7437
  `);
7179
- while (nl !== -1) {
7180
- lines.push(this.buf.slice(0, nl));
7181
- this.buf = this.buf.slice(nl + 1);
7182
- nl = this.buf.indexOf(`
7438
+ return true;
7439
+ case "down":
7440
+ process.stderr.write(`${tag("info")} daemon not running — using cold path ${hint("(slower; run `claudemesh daemon up` for warm path)")}
7183
7441
  `);
7184
- }
7185
- return lines;
7186
- }
7187
- }
7188
- var init_protocol = () => {};
7189
-
7190
- // src/services/bridge/client.ts
7191
- import { createConnection } from "node:net";
7192
- import { existsSync as existsSync6 } from "node:fs";
7193
- import { randomUUID as randomUUID2 } from "node:crypto";
7194
- async function tryBridge(meshSlug, verb, args = {}, timeoutMs = DEFAULT_TIMEOUT_MS) {
7195
- const path = socketPath(meshSlug);
7196
- if (!existsSync6(path))
7197
- return null;
7198
- return new Promise((resolve) => {
7199
- const id = randomUUID2();
7200
- const req = { id, verb, args };
7201
- const parser = new LineParser;
7202
- let settled = false;
7203
- const finish = (value) => {
7204
- if (settled)
7205
- return;
7206
- settled = true;
7207
- try {
7208
- socket.destroy();
7209
- } catch {}
7210
- clearTimeout(timer);
7211
- resolve(value);
7212
- };
7213
- const socket = createConnection({ path });
7214
- const timer = setTimeout(() => {
7215
- finish(null);
7216
- }, timeoutMs);
7217
- socket.on("connect", () => {
7218
- try {
7219
- socket.write(frame(req));
7220
- } catch {
7221
- finish(null);
7222
- }
7223
- });
7224
- socket.on("data", (chunk) => {
7225
- const lines = parser.feed(chunk);
7226
- for (const line of lines) {
7227
- if (!line.trim())
7228
- continue;
7229
- let res;
7230
- try {
7231
- res = JSON.parse(line);
7232
- } catch {
7233
- continue;
7234
- }
7235
- if (res.id !== id)
7236
- continue;
7237
- if (res.ok)
7238
- finish({ ok: true, result: res.result });
7239
- else
7240
- finish({ ok: false, error: res.error });
7241
- return;
7242
- }
7243
- });
7244
- socket.on("error", (err) => {
7245
- const code = err.code;
7246
- if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EPERM") {
7247
- finish(null);
7248
- } else {
7249
- finish(null);
7250
- }
7251
- });
7252
- socket.on("close", () => {
7253
- finish(null);
7254
- });
7255
- });
7256
- }
7257
- var DEFAULT_TIMEOUT_MS = 5000;
7258
- var init_client3 = __esm(() => {
7259
- init_protocol();
7260
- });
7261
-
7262
- // src/daemon/local-token.ts
7263
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync6 } from "node:fs";
7264
- import { dirname as dirname3 } from "node:path";
7265
- import { randomBytes as randomBytes4 } from "node:crypto";
7266
- function readLocalToken() {
7267
- try {
7268
- return readFileSync5(DAEMON_PATHS.TOKEN_FILE, "utf8").trim();
7269
- } catch {
7270
- return null;
7271
- }
7272
- }
7273
- function ensureLocalToken() {
7274
- const existing = readLocalToken();
7275
- if (existing)
7276
- return existing;
7277
- mkdirSync4(dirname3(DAEMON_PATHS.TOKEN_FILE), { recursive: true, mode: 448 });
7278
- const tok = randomBytes4(32).toString("base64url");
7279
- writeFileSync6(DAEMON_PATHS.TOKEN_FILE, tok + `
7280
- `, { mode: 384 });
7281
- return tok;
7282
- }
7283
- var init_local_token = __esm(() => {
7284
- init_paths2();
7285
- });
7286
-
7287
- // src/daemon/ipc/client.ts
7288
- import { request as httpRequest } from "node:http";
7289
- async function ipc(opts) {
7290
- const useTcp = !!opts.preferTcp;
7291
- const headers = {
7292
- accept: "application/json",
7293
- host: "localhost"
7294
- };
7295
- let bodyBuf;
7296
- if (opts.body !== undefined) {
7297
- bodyBuf = Buffer.from(JSON.stringify(opts.body), "utf8");
7298
- headers["content-type"] = "application/json";
7299
- headers["content-length"] = String(bodyBuf.length);
7300
- }
7301
- if (useTcp) {
7302
- const tok = readLocalToken();
7303
- if (!tok)
7304
- throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
7305
- headers.authorization = `Bearer ${tok}`;
7442
+ return true;
7443
+ case "spawn-suppressed":
7444
+ process.stderr.write(`${tag("warn")} ${res.reason ?? "daemon failed to start recently"} — using cold path ${hint("(run `claudemesh doctor`)")}
7445
+ `);
7446
+ return true;
7447
+ case "spawn-failed":
7448
+ process.stderr.write(`${tag("warn")} daemon spawn failed${res.reason ? `: ${res.reason}` : ""} — using cold path ${hint("(check ~/.claudemesh/daemon/daemon.log)")}
7449
+ `);
7450
+ return true;
7306
7451
  }
7307
- return new Promise((resolve, reject) => {
7308
- const req = httpRequest(useTcp ? { host: DAEMON_TCP_HOST, port: DAEMON_TCP_DEFAULT_PORT, path: opts.path, method: opts.method ?? "GET", headers } : { socketPath: DAEMON_PATHS.SOCK_FILE, path: opts.path, method: opts.method ?? "GET", headers }, (res) => {
7309
- const chunks = [];
7310
- res.on("data", (c) => chunks.push(c));
7311
- res.on("end", () => {
7312
- const raw = Buffer.concat(chunks).toString("utf8");
7313
- let parsed = raw;
7314
- try {
7315
- parsed = raw.length > 0 ? JSON.parse(raw) : null;
7316
- } catch {}
7317
- resolve({ status: res.statusCode ?? 0, body: parsed });
7318
- });
7319
- });
7320
- req.setTimeout(opts.timeoutMs ?? 5000, () => req.destroy(new Error("ipc_timeout")));
7321
- req.on("error", (err) => reject(err));
7322
- if (bodyBuf)
7323
- req.write(bodyBuf);
7324
- req.end();
7325
- });
7452
+ return false;
7326
7453
  }
7327
- var IpcError;
7328
- var init_client4 = __esm(() => {
7329
- init_paths2();
7330
- init_local_token();
7331
- IpcError = class IpcError extends Error {
7332
- status;
7333
- payload;
7334
- constructor(status, payload, msg) {
7335
- super(msg);
7336
- this.status = status;
7337
- this.payload = payload;
7338
- }
7339
- };
7454
+ var alreadyWarned = false;
7455
+ var init_warnings = __esm(() => {
7456
+ init_policy();
7457
+ init_styles();
7340
7458
  });
7341
7459
 
7342
7460
  // src/services/bridge/daemon-route.ts
@@ -7353,12 +7471,19 @@ __export(exports_daemon_route, {
7353
7471
  tryGetSkillViaDaemon: () => tryGetSkillViaDaemon,
7354
7472
  tryForgetViaDaemon: () => tryForgetViaDaemon
7355
7473
  });
7356
- import { existsSync as existsSync7 } from "node:fs";
7357
7474
  function meshQuery(mesh) {
7358
7475
  return mesh ? `?mesh=${encodeURIComponent(mesh)}` : "";
7359
7476
  }
7477
+ async function daemonReachable() {
7478
+ const policy2 = getDaemonPolicy();
7479
+ if (policy2.mode === "no-daemon")
7480
+ return false;
7481
+ const res = await ensureDaemonReady({ noAutoSpawn: false });
7482
+ warnDaemonState(res, {});
7483
+ return res.state === "up" || res.state === "started";
7484
+ }
7360
7485
  async function tryListPeersViaDaemon(mesh) {
7361
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7486
+ if (!await daemonReachable())
7362
7487
  return null;
7363
7488
  try {
7364
7489
  const res = await ipc({ path: `/v1/peers${meshQuery(mesh)}`, timeoutMs: 3000 });
@@ -7373,7 +7498,7 @@ async function tryListPeersViaDaemon(mesh) {
7373
7498
  }
7374
7499
  }
7375
7500
  async function tryListSkillsViaDaemon(mesh) {
7376
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7501
+ if (!await daemonReachable())
7377
7502
  return null;
7378
7503
  try {
7379
7504
  const res = await ipc({ path: `/v1/skills${meshQuery(mesh)}`, timeoutMs: 3000 });
@@ -7388,7 +7513,7 @@ async function tryListSkillsViaDaemon(mesh) {
7388
7513
  }
7389
7514
  }
7390
7515
  async function tryGetSkillViaDaemon(name, mesh) {
7391
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7516
+ if (!await daemonReachable())
7392
7517
  return null;
7393
7518
  try {
7394
7519
  const res = await ipc({
@@ -7405,7 +7530,7 @@ async function tryGetSkillViaDaemon(name, mesh) {
7405
7530
  }
7406
7531
  }
7407
7532
  async function tryGetStateViaDaemon(key, mesh) {
7408
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7533
+ if (!await daemonReachable())
7409
7534
  return null;
7410
7535
  try {
7411
7536
  const path = `/v1/state?key=${encodeURIComponent(key)}${mesh ? `&mesh=${encodeURIComponent(mesh)}` : ""}`;
@@ -7423,7 +7548,7 @@ async function tryGetStateViaDaemon(key, mesh) {
7423
7548
  }
7424
7549
  }
7425
7550
  async function tryListStateViaDaemon(mesh) {
7426
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7551
+ if (!await daemonReachable())
7427
7552
  return null;
7428
7553
  try {
7429
7554
  const res = await ipc({ path: `/v1/state${meshQuery(mesh)}`, timeoutMs: 3000 });
@@ -7438,7 +7563,7 @@ async function tryListStateViaDaemon(mesh) {
7438
7563
  }
7439
7564
  }
7440
7565
  async function trySetStateViaDaemon(key, value, mesh) {
7441
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7566
+ if (!await daemonReachable())
7442
7567
  return false;
7443
7568
  try {
7444
7569
  const res = await ipc({
@@ -7453,7 +7578,7 @@ async function trySetStateViaDaemon(key, value, mesh) {
7453
7578
  }
7454
7579
  }
7455
7580
  async function tryRememberViaDaemon(content, tags, mesh) {
7456
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7581
+ if (!await daemonReachable())
7457
7582
  return null;
7458
7583
  try {
7459
7584
  const res = await ipc({
@@ -7470,7 +7595,7 @@ async function tryRememberViaDaemon(content, tags, mesh) {
7470
7595
  }
7471
7596
  }
7472
7597
  async function tryRecallViaDaemon(query, mesh) {
7473
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7598
+ if (!await daemonReachable())
7474
7599
  return null;
7475
7600
  try {
7476
7601
  const path = `/v1/memory?q=${encodeURIComponent(query)}${mesh ? `&mesh=${encodeURIComponent(mesh)}` : ""}`;
@@ -7486,7 +7611,7 @@ async function tryRecallViaDaemon(query, mesh) {
7486
7611
  }
7487
7612
  }
7488
7613
  async function tryForgetViaDaemon(id, mesh) {
7489
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7614
+ if (!await daemonReachable())
7490
7615
  return false;
7491
7616
  try {
7492
7617
  const path = `/v1/memory/${encodeURIComponent(id)}${meshQuery(mesh)}`;
@@ -7497,7 +7622,7 @@ async function tryForgetViaDaemon(id, mesh) {
7497
7622
  }
7498
7623
  }
7499
7624
  async function trySendViaDaemon(args) {
7500
- if (!existsSync7(DAEMON_PATHS.SOCK_FILE))
7625
+ if (!await daemonReachable())
7501
7626
  return null;
7502
7627
  try {
7503
7628
  const res = await ipc({
@@ -7529,8 +7654,10 @@ async function trySendViaDaemon(args) {
7529
7654
  }
7530
7655
  }
7531
7656
  var init_daemon_route = __esm(() => {
7532
- init_client4();
7533
- init_paths2();
7657
+ init_client3();
7658
+ init_lifecycle();
7659
+ init_policy();
7660
+ init_warnings();
7534
7661
  });
7535
7662
 
7536
7663
  // src/commands/peers.ts
@@ -7557,11 +7684,6 @@ async function listPeersForMesh(slug) {
7557
7684
  return dr.map((p) => annotateSelf(p, selfMemberPubkey, null));
7558
7685
  }
7559
7686
  } catch {}
7560
- const bridged = await tryBridge(slug, "peers");
7561
- if (bridged && bridged.ok) {
7562
- const peers = bridged.result;
7563
- return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
7564
- }
7565
7687
  let result = [];
7566
7688
  await withMesh({ meshSlug: slug }, async (client) => {
7567
7689
  const all = await client.listPeers();
@@ -7631,7 +7753,6 @@ var FIELD_ALIAS;
7631
7753
  var init_peers = __esm(() => {
7632
7754
  init_connect();
7633
7755
  init_facade();
7634
- init_client3();
7635
7756
  init_render();
7636
7757
  init_styles();
7637
7758
  FIELD_ALIAS = {
@@ -7677,26 +7798,6 @@ async function runSend(flags, to, message) {
7677
7798
  process.exit(1);
7678
7799
  }
7679
7800
  }
7680
- if (meshSlug) {
7681
- const bridged = await tryBridge(meshSlug, "send", { to, message, priority });
7682
- if (bridged !== null) {
7683
- if (bridged.ok) {
7684
- const r = bridged.result;
7685
- if (flags.json) {
7686
- console.log(JSON.stringify({ ok: true, messageId: r.messageId, target: to }));
7687
- } else {
7688
- render.ok(`sent to ${to}`, r.messageId ? dim(r.messageId.slice(0, 8)) : undefined);
7689
- }
7690
- return;
7691
- }
7692
- if (flags.json) {
7693
- console.log(JSON.stringify({ ok: false, error: bridged.error }));
7694
- } else {
7695
- render.err(`send failed: ${bridged.error}`);
7696
- }
7697
- process.exit(1);
7698
- }
7699
- }
7700
7801
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
7701
7802
  let targetSpec = to;
7702
7803
  if (to.startsWith("#") && !/^#[0-9a-z_-]{20,}$/i.test(to)) {
@@ -7739,7 +7840,6 @@ async function runSend(flags, to, message) {
7739
7840
  var init_send = __esm(() => {
7740
7841
  init_connect();
7741
7842
  init_facade();
7742
- init_client3();
7743
7843
  init_daemon_route();
7744
7844
  init_render();
7745
7845
  init_styles();
@@ -8067,33 +8167,12 @@ __export(exports_broker_actions, {
8067
8167
  runForget: () => runForget,
8068
8168
  runClock: () => runClock
8069
8169
  });
8070
- function unambiguousMesh(opts) {
8071
- if (opts.mesh)
8072
- return opts.mesh;
8073
- const config = readConfig();
8074
- return config.meshes.length === 1 ? config.meshes[0].slug : null;
8075
- }
8076
8170
  async function runStatusSet(state, opts) {
8077
8171
  const valid = ["idle", "working", "dnd"];
8078
8172
  if (!valid.includes(state)) {
8079
8173
  render.err(`Invalid status: ${state}`, `must be one of: ${valid.join(", ")}`);
8080
8174
  return EXIT.INVALID_ARGS;
8081
8175
  }
8082
- const meshSlug = unambiguousMesh(opts);
8083
- if (meshSlug) {
8084
- const bridged = await tryBridge(meshSlug, "status_set", { status: state });
8085
- if (bridged !== null) {
8086
- if (bridged.ok) {
8087
- if (opts.json)
8088
- console.log(JSON.stringify({ status: state }));
8089
- else
8090
- render.ok(`status set to ${bold(state)}`);
8091
- return EXIT.SUCCESS;
8092
- }
8093
- render.err(bridged.error);
8094
- return EXIT.INTERNAL_ERROR;
8095
- }
8096
- }
8097
8176
  await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
8098
8177
  await client.setStatus(state);
8099
8178
  });
@@ -8108,21 +8187,6 @@ async function runSummary(text, opts) {
8108
8187
  render.err("Usage: claudemesh summary <text>");
8109
8188
  return EXIT.INVALID_ARGS;
8110
8189
  }
8111
- const meshSlug = unambiguousMesh(opts);
8112
- if (meshSlug) {
8113
- const bridged = await tryBridge(meshSlug, "summary", { summary: text });
8114
- if (bridged !== null) {
8115
- if (bridged.ok) {
8116
- if (opts.json)
8117
- console.log(JSON.stringify({ summary: text }));
8118
- else
8119
- render.ok("summary set", dim(text));
8120
- return EXIT.SUCCESS;
8121
- }
8122
- render.err(bridged.error);
8123
- return EXIT.INTERNAL_ERROR;
8124
- }
8125
- }
8126
8190
  await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
8127
8191
  await client.setSummary(text);
8128
8192
  });
@@ -8142,21 +8206,6 @@ async function runVisible(value, opts) {
8142
8206
  render.err("Usage: claudemesh visible <true|false>");
8143
8207
  return EXIT.INVALID_ARGS;
8144
8208
  }
8145
- const meshSlug = unambiguousMesh(opts);
8146
- if (meshSlug) {
8147
- const bridged = await tryBridge(meshSlug, "visible", { visible });
8148
- if (bridged !== null) {
8149
- if (bridged.ok) {
8150
- if (opts.json)
8151
- console.log(JSON.stringify({ visible }));
8152
- else
8153
- render.ok(visible ? "you are now visible to peers" : "you are now hidden", visible ? undefined : "direct messages still reach you");
8154
- return EXIT.SUCCESS;
8155
- }
8156
- render.err(bridged.error);
8157
- return EXIT.INTERNAL_ERROR;
8158
- }
8159
- }
8160
8209
  await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
8161
8210
  await client.setVisible(visible);
8162
8211
  });
@@ -8386,8 +8435,6 @@ async function runTaskComplete(id, result, opts) {
8386
8435
  }
8387
8436
  var init_broker_actions = __esm(() => {
8388
8437
  init_connect();
8389
- init_facade();
8390
- init_client3();
8391
8438
  init_daemon_route();
8392
8439
  init_render();
8393
8440
  init_styles();
@@ -8622,35 +8669,35 @@ var init_whoami = __esm(() => {
8622
8669
  });
8623
8670
 
8624
8671
  // src/daemon/lock.ts
8625
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "node:fs";
8672
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "node:fs";
8626
8673
  import { dirname as dirname4 } from "node:path";
8627
8674
  function acquireSingletonLock() {
8628
8675
  mkdirSync5(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
8629
- if (existsSync8(DAEMON_PATHS.PID_FILE)) {
8630
- const raw = readFileSync6(DAEMON_PATHS.PID_FILE, "utf8").trim();
8676
+ if (existsSync7(DAEMON_PATHS.PID_FILE)) {
8677
+ const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
8631
8678
  const oldPid = Number.parseInt(raw, 10);
8632
8679
  if (Number.isFinite(oldPid) && oldPid > 0 && isProcessAlive(oldPid)) {
8633
8680
  return { result: "already-running", pid: oldPid };
8634
8681
  }
8635
8682
  try {
8636
- unlinkSync2(DAEMON_PATHS.PID_FILE);
8683
+ unlinkSync3(DAEMON_PATHS.PID_FILE);
8637
8684
  } catch {}
8638
- writeFileSync7(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8685
+ writeFileSync8(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8639
8686
  return { result: "stale", pid: process.pid };
8640
8687
  }
8641
- writeFileSync7(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8688
+ writeFileSync8(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8642
8689
  return { result: "acquired", pid: process.pid };
8643
8690
  }
8644
8691
  function releaseSingletonLock() {
8645
8692
  try {
8646
- const raw = readFileSync6(DAEMON_PATHS.PID_FILE, "utf8").trim();
8693
+ const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
8647
8694
  if (Number.parseInt(raw, 10) === process.pid)
8648
- unlinkSync2(DAEMON_PATHS.PID_FILE);
8695
+ unlinkSync3(DAEMON_PATHS.PID_FILE);
8649
8696
  } catch {}
8650
8697
  }
8651
8698
  function readRunningPid() {
8652
8699
  try {
8653
- const raw = readFileSync6(DAEMON_PATHS.PID_FILE, "utf8").trim();
8700
+ const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
8654
8701
  const pid = Number.parseInt(raw, 10);
8655
8702
  if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
8656
8703
  return pid;
@@ -8886,10 +8933,10 @@ var init_fingerprint = __esm(() => {
8886
8933
  });
8887
8934
 
8888
8935
  // src/daemon/ipc/handlers/send.ts
8889
- import { randomUUID as randomUUID3 } from "node:crypto";
8936
+ import { randomUUID as randomUUID2 } from "node:crypto";
8890
8937
  function acceptSend(req, deps) {
8891
8938
  const now = (deps.now ?? Date.now)();
8892
- const newId = deps.newId ?? randomUUID3;
8939
+ const newId = deps.newId ?? randomUUID2;
8893
8940
  const clientId = req.client_message_id?.trim() || ulidLike(newId);
8894
8941
  const body = Buffer.from(req.message, "utf8");
8895
8942
  const fingerprint = computeRequestFingerprint({
@@ -9082,9 +9129,9 @@ function bindSseStream(res, bus) {
9082
9129
 
9083
9130
  // src/daemon/ipc/server.ts
9084
9131
  import { createServer as createServer2 } from "node:http";
9085
- import { chmodSync as chmodSync3, existsSync as existsSync9, unlinkSync as unlinkSync3 } from "node:fs";
9132
+ import { chmodSync as chmodSync3, existsSync as existsSync8, unlinkSync as unlinkSync4 } from "node:fs";
9086
9133
  import { timingSafeEqual } from "node:crypto";
9087
- import { randomUUID as randomUUID4 } from "node:crypto";
9134
+ import { randomUUID as randomUUID3 } from "node:crypto";
9088
9135
  function startIpcServer(opts) {
9089
9136
  const log2 = opts.log ?? defaultLogger;
9090
9137
  const handler = makeHandler({
@@ -9098,9 +9145,9 @@ function startIpcServer(opts) {
9098
9145
  meshConfigs: opts.meshConfigs,
9099
9146
  onPendingInserted: opts.onPendingInserted
9100
9147
  });
9101
- if (existsSync9(DAEMON_PATHS.SOCK_FILE)) {
9148
+ if (existsSync8(DAEMON_PATHS.SOCK_FILE)) {
9102
9149
  try {
9103
- unlinkSync3(DAEMON_PATHS.SOCK_FILE);
9150
+ unlinkSync4(DAEMON_PATHS.SOCK_FILE);
9104
9151
  } catch {}
9105
9152
  }
9106
9153
  const uds = createServer2(handler);
@@ -9136,7 +9183,7 @@ function startIpcServer(opts) {
9136
9183
  tcp ? new Promise((res) => tcp.close(() => res())) : Promise.resolve()
9137
9184
  ]);
9138
9185
  try {
9139
- unlinkSync3(DAEMON_PATHS.SOCK_FILE);
9186
+ unlinkSync4(DAEMON_PATHS.SOCK_FILE);
9140
9187
  } catch {}
9141
9188
  }
9142
9189
  };
@@ -9555,11 +9602,11 @@ function makeHandler(opts) {
9555
9602
  respond(res, 400, { error: "missing 'id'" });
9556
9603
  return;
9557
9604
  }
9558
- const newId = typeof body.new_client_message_id === "string" && body.new_client_message_id.trim() ? body.new_client_message_id.trim() : randomUUID4();
9605
+ const newId = typeof body.new_client_message_id === "string" && body.new_client_message_id.trim() ? body.new_client_message_id.trim() : randomUUID3();
9559
9606
  const result = requeueDeadOrPending(opts.outboxDb, {
9560
9607
  id: body.id,
9561
9608
  newClientMessageId: newId,
9562
- newRowId: randomUUID4(),
9609
+ newRowId: randomUUID3(),
9563
9610
  now: Date.now(),
9564
9611
  abortedBy: typeof body.aborted_by === "string" ? body.aborted_by : "operator"
9565
9612
  });
@@ -10426,7 +10473,7 @@ var POLL_INTERVAL_MS = 500, MAX_ATTEMPTS_PER_ROW = 25, BACKOFF_BASE_MS = 500, BA
10426
10473
  var init_drain = () => {};
10427
10474
 
10428
10475
  // src/daemon/inbound.ts
10429
- import { randomUUID as randomUUID5 } from "node:crypto";
10476
+ import { randomUUID as randomUUID4 } from "node:crypto";
10430
10477
  async function handleBrokerPush(msg, ctx) {
10431
10478
  if (msg.subtype === "system" && typeof msg.event === "string") {
10432
10479
  ctx.bus.publish(mapSystemEventKind(msg.event), {
@@ -10449,14 +10496,14 @@ async function handleBrokerPush(msg, ctx) {
10449
10496
  const createdAt = stringOrNull(msg.createdAt);
10450
10497
  const priority = stringOrNull(msg.priority) ?? "next";
10451
10498
  const subtype = stringOrNull(msg.subtype);
10452
- const clientMessageId = stringOrNull(msg.client_message_id) ?? brokerMessageId ?? randomUUID5();
10499
+ const clientMessageId = stringOrNull(msg.client_message_id) ?? brokerMessageId ?? randomUUID4();
10453
10500
  const body = await decryptOrFallback({
10454
10501
  ciphertext,
10455
10502
  nonce,
10456
10503
  senderPubkey,
10457
10504
  ctx
10458
10505
  });
10459
- const id = randomUUID5();
10506
+ const id = randomUUID4();
10460
10507
  const inserted = insertIfNew(ctx.db, {
10461
10508
  id,
10462
10509
  client_message_id: clientMessageId,
@@ -10533,7 +10580,7 @@ __export(exports_identity, {
10533
10580
  checkFingerprint: () => checkFingerprint,
10534
10581
  acceptCurrentHost: () => acceptCurrentHost
10535
10582
  });
10536
- import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "node:fs";
10583
+ import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "node:fs";
10537
10584
  import { join as join7 } from "node:path";
10538
10585
  import { createHash as createHash2 } from "node:crypto";
10539
10586
  import { networkInterfaces } from "node:os";
@@ -10554,13 +10601,13 @@ function computeCurrentFingerprint() {
10554
10601
  }
10555
10602
  function checkFingerprint() {
10556
10603
  const current = computeCurrentFingerprint();
10557
- if (!existsSync10(path())) {
10558
- writeFileSync8(path(), JSON.stringify(current, null, 2), { mode: 384 });
10604
+ if (!existsSync9(path())) {
10605
+ writeFileSync9(path(), JSON.stringify(current, null, 2), { mode: 384 });
10559
10606
  return { result: "first_run", current };
10560
10607
  }
10561
10608
  let stored;
10562
10609
  try {
10563
- stored = JSON.parse(readFileSync7(path(), "utf8"));
10610
+ stored = JSON.parse(readFileSync8(path(), "utf8"));
10564
10611
  } catch {
10565
10612
  return { result: "unavailable", current };
10566
10613
  }
@@ -10570,14 +10617,14 @@ function checkFingerprint() {
10570
10617
  }
10571
10618
  function acceptCurrentHost() {
10572
10619
  const current = computeCurrentFingerprint();
10573
- writeFileSync8(path(), JSON.stringify(current, null, 2), { mode: 384 });
10620
+ writeFileSync9(path(), JSON.stringify(current, null, 2), { mode: 384 });
10574
10621
  return current;
10575
10622
  }
10576
10623
  function readHostId() {
10577
10624
  if (process.platform === "linux") {
10578
10625
  for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
10579
10626
  try {
10580
- const raw = readFileSync7(p, "utf8").trim();
10627
+ const raw = readFileSync8(p, "utf8").trim();
10581
10628
  if (raw)
10582
10629
  return `linux:${raw}`;
10583
10630
  } catch {}
@@ -10622,16 +10669,16 @@ var init_identity = __esm(() => {
10622
10669
  });
10623
10670
 
10624
10671
  // src/daemon/run.ts
10625
- import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync8 } from "node:fs";
10672
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync9 } from "node:fs";
10626
10673
  function detectContainer() {
10627
10674
  if (process.env.KUBERNETES_SERVICE_HOST)
10628
10675
  return true;
10629
10676
  if (process.env.CONTAINER === "1")
10630
10677
  return true;
10631
10678
  try {
10632
- if (existsSync11("/.dockerenv"))
10679
+ if (existsSync10("/.dockerenv"))
10633
10680
  return true;
10634
- const cg = readFileSync8("/proc/1/cgroup", "utf8");
10681
+ const cg = readFileSync9("/proc/1/cgroup", "utf8");
10635
10682
  if (/(docker|kubepods|containerd)/.test(cg))
10636
10683
  return true;
10637
10684
  } catch {}
@@ -10650,10 +10697,10 @@ async function runDaemon(opts = {}) {
10650
10697
  `);
10651
10698
  }
10652
10699
  const fpCheck = checkFingerprint();
10653
- const policy = opts.clonePolicy ?? "refuse";
10700
+ const policy2 = opts.clonePolicy ?? "refuse";
10654
10701
  if (fpCheck.result === "mismatch") {
10655
10702
  const msg = `host_fingerprint mismatch: this daemon dir was started on a different host.`;
10656
- if (policy === "refuse") {
10703
+ if (policy2 === "refuse") {
10657
10704
  process.stderr.write(`${msg}
10658
10705
  `);
10659
10706
  process.stderr.write(` stored host_id: ${fpCheck.stored?.host_id}
@@ -10667,7 +10714,7 @@ async function runDaemon(opts = {}) {
10667
10714
  releaseSingletonLock();
10668
10715
  return 4;
10669
10716
  }
10670
- if (policy === "warn") {
10717
+ if (policy2 === "warn") {
10671
10718
  process.stderr.write(`WARN: ${msg} (continuing per [clone] policy=warn)
10672
10719
  `);
10673
10720
  }
@@ -10832,9 +10879,9 @@ __export(exports_service_install, {
10832
10879
  installService: () => installService,
10833
10880
  detectPlatform: () => detectPlatform
10834
10881
  });
10835
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync9, unlinkSync as unlinkSync4, readFileSync as readFileSync9 } from "node:fs";
10882
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10, unlinkSync as unlinkSync5, readFileSync as readFileSync10 } from "node:fs";
10836
10883
  import { execSync as execSync2 } from "node:child_process";
10837
- import { homedir as homedir6 } from "node:os";
10884
+ import { homedir as homedir5 } from "node:os";
10838
10885
  import { join as join8, dirname as dirname5 } from "node:path";
10839
10886
  function detectPlatform() {
10840
10887
  if (process.platform === "darwin")
@@ -10853,7 +10900,7 @@ function installService(args) {
10853
10900
  if (isCi() && !args.allowCi) {
10854
10901
  throw new Error("Refusing to install persistent service in CI; pass --allow-ci-persistent to override.");
10855
10902
  }
10856
- if (!existsSync12(args.binaryPath)) {
10903
+ if (!existsSync11(args.binaryPath)) {
10857
10904
  throw new Error(`binary not found at ${args.binaryPath}`);
10858
10905
  }
10859
10906
  mkdirSync7(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
@@ -10869,8 +10916,8 @@ function uninstallService() {
10869
10916
  try {
10870
10917
  execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL}`, { stdio: "ignore" });
10871
10918
  } catch {}
10872
- if (existsSync12(p)) {
10873
- unlinkSync4(p);
10919
+ if (existsSync11(p)) {
10920
+ unlinkSync5(p);
10874
10921
  removed.push(p);
10875
10922
  }
10876
10923
  } else if (platform5 === "linux") {
@@ -10878,15 +10925,15 @@ function uninstallService() {
10878
10925
  try {
10879
10926
  execSync2(`systemctl --user disable --now ${SYSTEMD_UNIT}`, { stdio: "ignore" });
10880
10927
  } catch {}
10881
- if (existsSync12(p)) {
10882
- unlinkSync4(p);
10928
+ if (existsSync11(p)) {
10929
+ unlinkSync5(p);
10883
10930
  removed.push(p);
10884
10931
  }
10885
10932
  }
10886
10933
  return { platform: platform5, removed };
10887
10934
  }
10888
10935
  function darwinPlistPath() {
10889
- return join8(homedir6(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
10936
+ return join8(homedir5(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
10890
10937
  }
10891
10938
  function installDarwin(args) {
10892
10939
  const plist = darwinPlistPath();
@@ -10920,18 +10967,18 @@ function installDarwin(args) {
10920
10967
  <key>StandardErrorPath</key>
10921
10968
  <string>${escapeXml(log2)}</string>
10922
10969
  <key>WorkingDirectory</key>
10923
- <string>${escapeXml(homedir6())}</string>
10970
+ <string>${escapeXml(homedir5())}</string>
10924
10971
  <key>EnvironmentVariables</key>
10925
10972
  <dict>
10926
10973
  <key>HOME</key>
10927
- <string>${escapeXml(homedir6())}</string>
10974
+ <string>${escapeXml(homedir5())}</string>
10928
10975
  <key>PATH</key>
10929
10976
  <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
10930
10977
  </dict>
10931
10978
  </dict>
10932
10979
  </plist>
10933
10980
  `;
10934
- writeFileSync9(plist, xml, { mode: 420 });
10981
+ writeFileSync10(plist, xml, { mode: 420 });
10935
10982
  return {
10936
10983
  platform: "darwin",
10937
10984
  unitPath: plist,
@@ -10939,7 +10986,7 @@ function installDarwin(args) {
10939
10986
  };
10940
10987
  }
10941
10988
  function linuxUnitPath() {
10942
- return join8(homedir6(), ".config", "systemd", "user", SYSTEMD_UNIT);
10989
+ return join8(homedir5(), ".config", "systemd", "user", SYSTEMD_UNIT);
10943
10990
  }
10944
10991
  function installLinux(args) {
10945
10992
  const unit = linuxUnitPath();
@@ -10968,7 +11015,7 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
10968
11015
  [Install]
10969
11016
  WantedBy=default.target
10970
11017
  `;
10971
- writeFileSync9(unit, content, { mode: 420 });
11018
+ writeFileSync10(unit, content, { mode: 420 });
10972
11019
  return {
10973
11020
  platform: "linux",
10974
11021
  unitPath: unit,
@@ -10988,10 +11035,10 @@ function readInstalledUnit() {
10988
11035
  if (!platform5)
10989
11036
  return { platform: null, path: null, content: null };
10990
11037
  const path2 = platform5 === "darwin" ? darwinPlistPath() : linuxUnitPath();
10991
- if (!existsSync12(path2))
11038
+ if (!existsSync11(path2))
10992
11039
  return { platform: platform5, path: null, content: null };
10993
11040
  try {
10994
- return { platform: platform5, path: path2, content: readFileSync9(path2, "utf8") };
11041
+ return { platform: platform5, path: path2, content: readFileSync10(path2, "utf8") };
10995
11042
  } catch {
10996
11043
  return { platform: platform5, path: path2, content: null };
10997
11044
  }
@@ -11319,7 +11366,7 @@ async function runStop(opts) {
11319
11366
  }
11320
11367
  var init_daemon = __esm(() => {
11321
11368
  init_run();
11322
- init_client4();
11369
+ init_client3();
11323
11370
  init_lock();
11324
11371
  init_paths2();
11325
11372
  });
@@ -11333,19 +11380,19 @@ __export(exports_install, {
11333
11380
  import {
11334
11381
  chmodSync as chmodSync4,
11335
11382
  copyFileSync,
11336
- existsSync as existsSync13,
11383
+ existsSync as existsSync12,
11337
11384
  mkdirSync as mkdirSync8,
11338
- readFileSync as readFileSync10,
11339
- writeFileSync as writeFileSync10
11385
+ readFileSync as readFileSync11,
11386
+ writeFileSync as writeFileSync11
11340
11387
  } from "node:fs";
11341
- import { homedir as homedir7, platform as platform5 } from "node:os";
11388
+ import { homedir as homedir6, platform as platform5 } from "node:os";
11342
11389
  import { dirname as dirname6, join as join9, resolve } from "node:path";
11343
11390
  import { fileURLToPath } from "node:url";
11344
11391
  import { spawnSync as spawnSync3 } from "node:child_process";
11345
11392
  function readClaudeConfig() {
11346
- if (!existsSync13(CLAUDE_CONFIG))
11393
+ if (!existsSync12(CLAUDE_CONFIG))
11347
11394
  return {};
11348
- const text = readFileSync10(CLAUDE_CONFIG, "utf-8").trim();
11395
+ const text = readFileSync11(CLAUDE_CONFIG, "utf-8").trim();
11349
11396
  if (!text)
11350
11397
  return {};
11351
11398
  try {
@@ -11355,7 +11402,7 @@ function readClaudeConfig() {
11355
11402
  }
11356
11403
  }
11357
11404
  function backupClaudeConfig() {
11358
- if (!existsSync13(CLAUDE_CONFIG))
11405
+ if (!existsSync12(CLAUDE_CONFIG))
11359
11406
  return;
11360
11407
  const backupDir = join9(dirname6(CLAUDE_CONFIG), ".claude", "backups");
11361
11408
  mkdirSync8(backupDir, { recursive: true });
@@ -11384,7 +11431,7 @@ function patchMcpServer(entry) {
11384
11431
  return action;
11385
11432
  }
11386
11433
  function removeMcpServer() {
11387
- if (!existsSync13(CLAUDE_CONFIG))
11434
+ if (!existsSync12(CLAUDE_CONFIG))
11388
11435
  return false;
11389
11436
  backupClaudeConfig();
11390
11437
  const cfg = readClaudeConfig();
@@ -11398,7 +11445,7 @@ function removeMcpServer() {
11398
11445
  }
11399
11446
  function flushClaudeConfig(obj) {
11400
11447
  mkdirSync8(dirname6(CLAUDE_CONFIG), { recursive: true });
11401
- writeFileSync10(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
11448
+ writeFileSync11(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
11402
11449
  `, "utf-8");
11403
11450
  try {
11404
11451
  chmodSync4(CLAUDE_CONFIG, 384);
@@ -11421,7 +11468,7 @@ function resolveBundledSkillsDir() {
11421
11468
  const here = fileURLToPath(import.meta.url);
11422
11469
  const pkgRoot = resolve(dirname6(here), "..", "..");
11423
11470
  const skillsDir = join9(pkgRoot, "skills");
11424
- if (existsSync13(skillsDir))
11471
+ if (existsSync12(skillsDir))
11425
11472
  return skillsDir;
11426
11473
  return null;
11427
11474
  }
@@ -11456,7 +11503,7 @@ function uninstallSkills() {
11456
11503
  if (!entry.isDirectory())
11457
11504
  continue;
11458
11505
  const dstDir = join9(CLAUDE_SKILLS_ROOT, entry.name);
11459
- if (existsSync13(dstDir)) {
11506
+ if (existsSync12(dstDir)) {
11460
11507
  try {
11461
11508
  fs.rmSync(dstDir, { recursive: true, force: true });
11462
11509
  removed.push(entry.name);
@@ -11481,9 +11528,9 @@ function entriesEqual(a, b) {
11481
11528
  return a.command === b.command && JSON.stringify(a.args ?? []) === JSON.stringify(b.args ?? []);
11482
11529
  }
11483
11530
  function readClaudeSettings() {
11484
- if (!existsSync13(CLAUDE_SETTINGS))
11531
+ if (!existsSync12(CLAUDE_SETTINGS))
11485
11532
  return {};
11486
- const text = readFileSync10(CLAUDE_SETTINGS, "utf-8").trim();
11533
+ const text = readFileSync11(CLAUDE_SETTINGS, "utf-8").trim();
11487
11534
  if (!text)
11488
11535
  return {};
11489
11536
  try {
@@ -11494,7 +11541,7 @@ function readClaudeSettings() {
11494
11541
  }
11495
11542
  function writeClaudeSettings(obj) {
11496
11543
  mkdirSync8(dirname6(CLAUDE_SETTINGS), { recursive: true });
11497
- writeFileSync10(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
11544
+ writeFileSync11(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
11498
11545
  `, "utf-8");
11499
11546
  }
11500
11547
  function installAllowedTools() {
@@ -11508,7 +11555,7 @@ function installAllowedTools() {
11508
11555
  return { added: toAdd, unchanged: CLAUDEMESH_TOOLS.length - toAdd.length };
11509
11556
  }
11510
11557
  function uninstallAllowedTools() {
11511
- if (!existsSync13(CLAUDE_SETTINGS))
11558
+ if (!existsSync12(CLAUDE_SETTINGS))
11512
11559
  return 0;
11513
11560
  const settings = readClaudeSettings();
11514
11561
  const existing = settings.allowedTools ?? [];
@@ -11543,7 +11590,7 @@ function installHooks() {
11543
11590
  return { added, unchanged };
11544
11591
  }
11545
11592
  function uninstallHooks() {
11546
- if (!existsSync13(CLAUDE_SETTINGS))
11593
+ if (!existsSync12(CLAUDE_SETTINGS))
11547
11594
  return 0;
11548
11595
  const settings = readClaudeSettings();
11549
11596
  const hooks = settings.hooks;
@@ -11593,7 +11640,7 @@ function runInstall(args = []) {
11593
11640
  render.err("`bun` is not on PATH.", "Install Bun first: https://bun.com");
11594
11641
  process.exit(1);
11595
11642
  }
11596
- if (!existsSync13(entry)) {
11643
+ if (!existsSync12(entry)) {
11597
11644
  render.err(`MCP entry not found at ${entry}`);
11598
11645
  process.exit(1);
11599
11646
  }
@@ -11781,9 +11828,9 @@ var init_install = __esm(() => {
11781
11828
  init_facade();
11782
11829
  init_render();
11783
11830
  init_styles();
11784
- CLAUDE_CONFIG = join9(homedir7(), ".claude.json");
11785
- CLAUDE_SETTINGS = join9(homedir7(), ".claude", "settings.json");
11786
- CLAUDE_SKILLS_ROOT = join9(homedir7(), ".claude", "skills");
11831
+ CLAUDE_CONFIG = join9(homedir6(), ".claude.json");
11832
+ CLAUDE_SETTINGS = join9(homedir6(), ".claude", "settings.json");
11833
+ CLAUDE_SKILLS_ROOT = join9(homedir6(), ".claude", "skills");
11787
11834
  CLAUDEMESH_TOOLS = [
11788
11835
  "mcp__claudemesh__cancel_scheduled",
11789
11836
  "mcp__claudemesh__check_messages",
@@ -11838,35 +11885,35 @@ var exports_uninstall = {};
11838
11885
  __export(exports_uninstall, {
11839
11886
  uninstall: () => uninstall
11840
11887
  });
11841
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync11, existsSync as existsSync14, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
11888
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync12, existsSync as existsSync13, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
11842
11889
  import { join as join10, dirname as dirname7 } from "node:path";
11843
- import { homedir as homedir8 } from "node:os";
11890
+ import { homedir as homedir7 } from "node:os";
11844
11891
  import { fileURLToPath as fileURLToPath2 } from "node:url";
11845
11892
  function bundledSkillsDir() {
11846
11893
  const here = fileURLToPath2(import.meta.url);
11847
11894
  const pkgRoot = join10(dirname7(here), "..", "..");
11848
11895
  const skillsDir = join10(pkgRoot, "skills");
11849
- return existsSync14(skillsDir) ? skillsDir : null;
11896
+ return existsSync13(skillsDir) ? skillsDir : null;
11850
11897
  }
11851
11898
  async function uninstall() {
11852
11899
  let removed = 0;
11853
- if (existsSync14(PATHS.CLAUDE_JSON)) {
11900
+ if (existsSync13(PATHS.CLAUDE_JSON)) {
11854
11901
  try {
11855
- const raw = readFileSync11(PATHS.CLAUDE_JSON, "utf-8");
11902
+ const raw = readFileSync12(PATHS.CLAUDE_JSON, "utf-8");
11856
11903
  const config = JSON.parse(raw);
11857
11904
  const servers = config.mcpServers;
11858
11905
  if (servers && "claudemesh" in servers) {
11859
11906
  delete servers.claudemesh;
11860
- writeFileSync11(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
11907
+ writeFileSync12(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
11861
11908
  `, "utf-8");
11862
11909
  render.ok("removed MCP server", dim("~/.claude.json"));
11863
11910
  removed++;
11864
11911
  }
11865
11912
  } catch {}
11866
11913
  }
11867
- if (existsSync14(PATHS.CLAUDE_SETTINGS)) {
11914
+ if (existsSync13(PATHS.CLAUDE_SETTINGS)) {
11868
11915
  try {
11869
- const raw = readFileSync11(PATHS.CLAUDE_SETTINGS, "utf-8");
11916
+ const raw = readFileSync12(PATHS.CLAUDE_SETTINGS, "utf-8");
11870
11917
  const config = JSON.parse(raw);
11871
11918
  const hooks = config.hooks;
11872
11919
  if (hooks) {
@@ -11887,7 +11934,7 @@ async function uninstall() {
11887
11934
  }
11888
11935
  }
11889
11936
  if (removedHooks > 0) {
11890
- writeFileSync11(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
11937
+ writeFileSync12(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
11891
11938
  `, "utf-8");
11892
11939
  render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
11893
11940
  removed++;
@@ -11903,7 +11950,7 @@ async function uninstall() {
11903
11950
  if (!entry.isDirectory())
11904
11951
  continue;
11905
11952
  const dst = join10(CLAUDE_SKILLS_ROOT2, entry.name);
11906
- if (existsSync14(dst)) {
11953
+ if (existsSync13(dst)) {
11907
11954
  try {
11908
11955
  rmSync2(dst, { recursive: true, force: true });
11909
11956
  removedSkills.push(entry.name);
@@ -11927,7 +11974,7 @@ var init_uninstall = __esm(() => {
11927
11974
  init_render();
11928
11975
  init_styles();
11929
11976
  init_exit_codes();
11930
- CLAUDE_SKILLS_ROOT2 = join10(homedir8(), ".claude", "skills");
11977
+ CLAUDE_SKILLS_ROOT2 = join10(homedir7(), ".claude", "skills");
11931
11978
  });
11932
11979
 
11933
11980
  // src/commands/doctor.ts
@@ -11935,8 +11982,8 @@ var exports_doctor = {};
11935
11982
  __export(exports_doctor, {
11936
11983
  runDoctor: () => runDoctor
11937
11984
  });
11938
- import { existsSync as existsSync15, readFileSync as readFileSync12, statSync as statSync2 } from "node:fs";
11939
- import { homedir as homedir9, platform as platform6 } from "node:os";
11985
+ import { existsSync as existsSync14, readFileSync as readFileSync13, statSync as statSync3 } from "node:fs";
11986
+ import { homedir as homedir8, platform as platform6 } from "node:os";
11940
11987
  import { join as join11 } from "node:path";
11941
11988
  import { spawnSync as spawnSync4 } from "node:child_process";
11942
11989
  function checkNode() {
@@ -11961,8 +12008,8 @@ function checkClaudeOnPath() {
11961
12008
  };
11962
12009
  }
11963
12010
  function checkMcpRegistered() {
11964
- const claudeConfig = join11(homedir9(), ".claude.json");
11965
- if (!existsSync15(claudeConfig)) {
12011
+ const claudeConfig = join11(homedir8(), ".claude.json");
12012
+ if (!existsSync14(claudeConfig)) {
11966
12013
  return {
11967
12014
  name: "claudemesh MCP registered in ~/.claude.json",
11968
12015
  pass: false,
@@ -11970,7 +12017,7 @@ function checkMcpRegistered() {
11970
12017
  };
11971
12018
  }
11972
12019
  try {
11973
- const cfg = JSON.parse(readFileSync12(claudeConfig, "utf-8"));
12020
+ const cfg = JSON.parse(readFileSync13(claudeConfig, "utf-8"));
11974
12021
  const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
11975
12022
  return {
11976
12023
  name: "claudemesh MCP registered in ~/.claude.json",
@@ -11987,8 +12034,8 @@ function checkMcpRegistered() {
11987
12034
  }
11988
12035
  }
11989
12036
  function checkHooksRegistered() {
11990
- const settings = join11(homedir9(), ".claude", "settings.json");
11991
- if (!existsSync15(settings)) {
12037
+ const settings = join11(homedir8(), ".claude", "settings.json");
12038
+ if (!existsSync14(settings)) {
11992
12039
  return {
11993
12040
  name: "Status hooks registered in ~/.claude/settings.json",
11994
12041
  pass: false,
@@ -11996,7 +12043,7 @@ function checkHooksRegistered() {
11996
12043
  };
11997
12044
  }
11998
12045
  try {
11999
- const raw = readFileSync12(settings, "utf-8");
12046
+ const raw = readFileSync13(settings, "utf-8");
12000
12047
  const has = raw.includes("claudemesh hook ");
12001
12048
  return {
12002
12049
  name: "Status hooks registered in ~/.claude/settings.json",
@@ -12013,7 +12060,7 @@ function checkHooksRegistered() {
12013
12060
  }
12014
12061
  function checkConfigFile() {
12015
12062
  const path2 = getConfigPath();
12016
- if (!existsSync15(path2)) {
12063
+ if (!existsSync14(path2)) {
12017
12064
  return {
12018
12065
  name: "~/.claudemesh/config.json exists and parses",
12019
12066
  pass: true,
@@ -12022,7 +12069,7 @@ function checkConfigFile() {
12022
12069
  }
12023
12070
  try {
12024
12071
  readConfig();
12025
- const st = statSync2(path2);
12072
+ const st = statSync3(path2);
12026
12073
  const mode = (st.mode & 511).toString(8);
12027
12074
  const secure = platform6() === "win32" || mode === "600";
12028
12075
  return {
@@ -12196,7 +12243,7 @@ var exports_status = {};
12196
12243
  __export(exports_status, {
12197
12244
  runStatus: () => runStatus2
12198
12245
  });
12199
- import { statSync as statSync3, existsSync as existsSync16 } from "node:fs";
12246
+ import { statSync as statSync4, existsSync as existsSync15 } from "node:fs";
12200
12247
  import WebSocket3 from "ws";
12201
12248
  async function probeBroker(url, timeoutMs = 4000) {
12202
12249
  return new Promise((resolve2) => {
@@ -12226,8 +12273,8 @@ async function runStatus2() {
12226
12273
  render.section(`status (v${VERSION})`);
12227
12274
  const configPath = getConfigPath();
12228
12275
  let configPermsNote = "missing";
12229
- if (existsSync16(configPath)) {
12230
- const mode = (statSync3(configPath).mode & 511).toString(8).padStart(4, "0");
12276
+ if (existsSync15(configPath)) {
12277
+ const mode = (statSync4(configPath).mode & 511).toString(8).padStart(4, "0");
12231
12278
  configPermsNote = mode === "0600" ? `${mode}` : `${mode} — expected 0600`;
12232
12279
  }
12233
12280
  render.kv([["config", configPath], ["perms", configPermsNote]]);
@@ -12372,13 +12419,13 @@ var init_check_claude_binary = __esm(() => {
12372
12419
  });
12373
12420
 
12374
12421
  // src/services/health/check-mcp-registered.ts
12375
- import { existsSync as existsSync17, readFileSync as readFileSync13 } from "node:fs";
12422
+ import { existsSync as existsSync16, readFileSync as readFileSync14 } from "node:fs";
12376
12423
  function checkMcpRegistered2() {
12377
12424
  try {
12378
- if (!existsSync17(PATHS.CLAUDE_JSON)) {
12425
+ if (!existsSync16(PATHS.CLAUDE_JSON)) {
12379
12426
  return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
12380
12427
  }
12381
- const raw = readFileSync13(PATHS.CLAUDE_JSON, "utf-8");
12428
+ const raw = readFileSync14(PATHS.CLAUDE_JSON, "utf-8");
12382
12429
  const config = JSON.parse(raw);
12383
12430
  if (config.mcpServers && "claudemesh" in config.mcpServers) {
12384
12431
  return { name: "mcp-registered", ok: true, message: "MCP server registered" };
@@ -12393,13 +12440,13 @@ var init_check_mcp_registered = __esm(() => {
12393
12440
  });
12394
12441
 
12395
12442
  // src/services/health/check-hooks-registered.ts
12396
- import { existsSync as existsSync18, readFileSync as readFileSync14 } from "node:fs";
12443
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
12397
12444
  function checkHooksRegistered2() {
12398
12445
  try {
12399
- if (!existsSync18(PATHS.CLAUDE_SETTINGS)) {
12446
+ if (!existsSync17(PATHS.CLAUDE_SETTINGS)) {
12400
12447
  return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
12401
12448
  }
12402
- const raw = readFileSync14(PATHS.CLAUDE_SETTINGS, "utf-8");
12449
+ const raw = readFileSync15(PATHS.CLAUDE_SETTINGS, "utf-8");
12403
12450
  const config = JSON.parse(raw);
12404
12451
  if (config.hooks) {
12405
12452
  return { name: "hooks-registered", ok: true, message: "Hooks configured" };
@@ -12414,14 +12461,14 @@ var init_check_hooks_registered = __esm(() => {
12414
12461
  });
12415
12462
 
12416
12463
  // src/services/health/check-config-perms.ts
12417
- import { existsSync as existsSync19, statSync as statSync4 } from "node:fs";
12464
+ import { existsSync as existsSync18, statSync as statSync5 } from "node:fs";
12418
12465
  function checkConfigPerms() {
12419
12466
  const configFile = PATHS.CONFIG_FILE;
12420
- if (!existsSync19(configFile)) {
12467
+ if (!existsSync18(configFile)) {
12421
12468
  return { name: "config-perms", ok: true, message: "No config file yet (first run)" };
12422
12469
  }
12423
12470
  try {
12424
- const mode = statSync4(configFile).mode & 511;
12471
+ const mode = statSync5(configFile).mode & 511;
12425
12472
  if (mode <= 384) {
12426
12473
  return { name: "config-perms", ok: true, message: `config.json mode ${mode.toString(8)}` };
12427
12474
  }
@@ -12435,13 +12482,13 @@ var init_check_config_perms = __esm(() => {
12435
12482
  });
12436
12483
 
12437
12484
  // src/services/health/check-keypairs-valid.ts
12438
- import { existsSync as existsSync20, readFileSync as readFileSync15 } from "node:fs";
12485
+ import { existsSync as existsSync19, readFileSync as readFileSync16 } from "node:fs";
12439
12486
  function checkKeypairsValid() {
12440
- if (!existsSync20(PATHS.CONFIG_FILE)) {
12487
+ if (!existsSync19(PATHS.CONFIG_FILE)) {
12441
12488
  return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
12442
12489
  }
12443
12490
  try {
12444
- const raw = readFileSync15(PATHS.CONFIG_FILE, "utf-8");
12491
+ const raw = readFileSync16(PATHS.CONFIG_FILE, "utf-8");
12445
12492
  const config = JSON.parse(raw);
12446
12493
  const meshes = config.meshes ?? [];
12447
12494
  if (meshes.length === 0) {
@@ -12921,8 +12968,8 @@ var exports_url_handler = {};
12921
12968
  __export(exports_url_handler, {
12922
12969
  runUrlHandler: () => runUrlHandler
12923
12970
  });
12924
- import { platform as platform7, homedir as homedir10 } from "node:os";
12925
- import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync12, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
12971
+ import { platform as platform7, homedir as homedir9 } from "node:os";
12972
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync13, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
12926
12973
  import { join as join12 } from "node:path";
12927
12974
  import { spawnSync as spawnSync5 } from "node:child_process";
12928
12975
  function resolveClaudemeshBin() {
@@ -12930,7 +12977,7 @@ function resolveClaudemeshBin() {
12930
12977
  }
12931
12978
  function installDarwin2() {
12932
12979
  const binPath = resolveClaudemeshBin();
12933
- const appDir = join12(homedir10(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
12980
+ const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
12934
12981
  const contents = join12(appDir, "Contents");
12935
12982
  const macOS = join12(contents, "MacOS");
12936
12983
  mkdirSync9(macOS, { recursive: true });
@@ -12956,7 +13003,7 @@ function installDarwin2() {
12956
13003
  </array>
12957
13004
  </dict>
12958
13005
  </plist>`;
12959
- writeFileSync12(join12(contents, "Info.plist"), plist);
13006
+ writeFileSync13(join12(contents, "Info.plist"), plist);
12960
13007
  const shim = `#!/bin/sh
12961
13008
  URL="$1"
12962
13009
  CODE=\${URL#claudemesh://}
@@ -12971,7 +13018,7 @@ end tell
12971
13018
  EOF
12972
13019
  `;
12973
13020
  const shimPath = join12(macOS, "open-url");
12974
- writeFileSync12(shimPath, shim);
13021
+ writeFileSync13(shimPath, shim);
12975
13022
  chmodSync5(shimPath, 493);
12976
13023
  const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
12977
13024
  if (lsreg.status !== 0) {
@@ -12982,7 +13029,7 @@ EOF
12982
13029
  }
12983
13030
  function installLinux2() {
12984
13031
  const binPath = resolveClaudemeshBin();
12985
- const appsDir = join12(homedir10(), ".local", "share", "applications");
13032
+ const appsDir = join12(homedir9(), ".local", "share", "applications");
12986
13033
  mkdirSync9(appsDir, { recursive: true });
12987
13034
  const desktop = `[Desktop Entry]
12988
13035
  Type=Application
@@ -12995,7 +13042,7 @@ MimeType=x-scheme-handler/claudemesh;
12995
13042
  NoDisplay=true
12996
13043
  `;
12997
13044
  const desktopPath = join12(appsDir, "claudemesh.desktop");
12998
- writeFileSync12(desktopPath, desktop);
13045
+ writeFileSync13(desktopPath, desktop);
12999
13046
  const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
13000
13047
  if (xdg1.status !== 0) {
13001
13048
  render.warn("xdg-mime not available — skipped mime default registration");
@@ -13017,8 +13064,8 @@ function installWindows() {
13017
13064
  `[HKEY_CURRENT_USER\\Software\\Classes\\claudemesh\\shell\\open\\command]`,
13018
13065
  `@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
13019
13066
  ];
13020
- const regPath = join12(homedir10(), "claudemesh-handler.reg");
13021
- writeFileSync12(regPath, lines.join(`\r
13067
+ const regPath = join12(homedir9(), "claudemesh-handler.reg");
13068
+ writeFileSync13(regPath, lines.join(`\r
13022
13069
  `));
13023
13070
  const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
13024
13071
  if (res.status !== 0) {
@@ -13029,15 +13076,15 @@ function installWindows() {
13029
13076
  return EXIT.SUCCESS;
13030
13077
  }
13031
13078
  function uninstallDarwin() {
13032
- const appDir = join12(homedir10(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
13033
- if (existsSync21(appDir))
13079
+ const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
13080
+ if (existsSync20(appDir))
13034
13081
  rmSync3(appDir, { recursive: true, force: true });
13035
13082
  render.ok("removed claudemesh:// handler on macOS");
13036
13083
  return EXIT.SUCCESS;
13037
13084
  }
13038
13085
  function uninstallLinux() {
13039
- const desktopPath = join12(homedir10(), ".local", "share", "applications", "claudemesh.desktop");
13040
- if (existsSync21(desktopPath))
13086
+ const desktopPath = join12(homedir9(), ".local", "share", "applications", "claudemesh.desktop");
13087
+ if (existsSync20(desktopPath))
13041
13088
  rmSync3(desktopPath, { force: true });
13042
13089
  render.ok("removed claudemesh:// handler on Linux");
13043
13090
  return EXIT.SUCCESS;
@@ -13082,9 +13129,9 @@ var exports_status_line = {};
13082
13129
  __export(exports_status_line, {
13083
13130
  runStatusLine: () => runStatusLine
13084
13131
  });
13085
- import { existsSync as existsSync22, readFileSync as readFileSync16 } from "node:fs";
13132
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "node:fs";
13086
13133
  import { join as join13 } from "node:path";
13087
- import { homedir as homedir11 } from "node:os";
13134
+ import { homedir as homedir10 } from "node:os";
13088
13135
  async function runStatusLine() {
13089
13136
  try {
13090
13137
  const config = readConfig();
@@ -13092,11 +13139,11 @@ async function runStatusLine() {
13092
13139
  process.stdout.write("◇ claudemesh (not joined)");
13093
13140
  return EXIT.SUCCESS;
13094
13141
  }
13095
- const cachePath = join13(homedir11(), ".claudemesh", "peer-cache.json");
13142
+ const cachePath = join13(homedir10(), ".claudemesh", "peer-cache.json");
13096
13143
  let cache = {};
13097
- if (existsSync22(cachePath)) {
13144
+ if (existsSync21(cachePath)) {
13098
13145
  try {
13099
- cache = JSON.parse(readFileSync16(cachePath, "utf-8"));
13146
+ cache = JSON.parse(readFileSync17(cachePath, "utf-8"));
13100
13147
  } catch {}
13101
13148
  }
13102
13149
  const pick = config.meshes[0];
@@ -13127,7 +13174,7 @@ __export(exports_backup, {
13127
13174
  runRestore: () => runRestore,
13128
13175
  runBackup: () => runBackup
13129
13176
  });
13130
- import { readFileSync as readFileSync17, writeFileSync as writeFileSync13, existsSync as existsSync23 } from "node:fs";
13177
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, existsSync as existsSync22 } from "node:fs";
13131
13178
  import { createInterface as createInterface11 } from "node:readline";
13132
13179
  function readHidden(prompt5) {
13133
13180
  return new Promise((resolve2) => {
@@ -13169,11 +13216,11 @@ async function deriveKey(pass, salt, s) {
13169
13216
  }
13170
13217
  async function runBackup(outPath) {
13171
13218
  const configPath = getConfigPath();
13172
- if (!existsSync23(configPath)) {
13219
+ if (!existsSync22(configPath)) {
13173
13220
  console.error(" No config found — nothing to back up. Join a mesh first.");
13174
13221
  return EXIT.NOT_FOUND;
13175
13222
  }
13176
- const plaintext = readFileSync17(configPath);
13223
+ const plaintext = readFileSync18(configPath);
13177
13224
  const pass = await readHidden(" Passphrase (min 12 chars): ");
13178
13225
  if (pass.length < 12) {
13179
13226
  console.error(" ✗ Passphrase too short.");
@@ -13191,7 +13238,7 @@ async function runBackup(outPath) {
13191
13238
  const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
13192
13239
  const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
13193
13240
  const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
13194
- writeFileSync13(file, blob, { mode: 384 });
13241
+ writeFileSync14(file, blob, { mode: 384 });
13195
13242
  console.log(`
13196
13243
  ✓ Backup saved: ${file}`);
13197
13244
  console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
@@ -13203,11 +13250,11 @@ async function runRestore(inPath) {
13203
13250
  console.error(" Usage: claudemesh restore <backup-file>");
13204
13251
  return EXIT.INVALID_ARGS;
13205
13252
  }
13206
- if (!existsSync23(inPath)) {
13253
+ if (!existsSync22(inPath)) {
13207
13254
  console.error(` ✗ File not found: ${inPath}`);
13208
13255
  return EXIT.NOT_FOUND;
13209
13256
  }
13210
- const blob = readFileSync17(inPath);
13257
+ const blob = readFileSync18(inPath);
13211
13258
  if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
13212
13259
  console.error(" ✗ Not a claudemesh backup file (bad magic).");
13213
13260
  return EXIT.INVALID_ARGS;
@@ -13226,12 +13273,12 @@ async function runRestore(inPath) {
13226
13273
  return EXIT.INTERNAL_ERROR;
13227
13274
  }
13228
13275
  const configPath = getConfigPath();
13229
- if (existsSync23(configPath)) {
13276
+ if (existsSync22(configPath)) {
13230
13277
  const backupOld = `${configPath}.before-restore.${Date.now()}`;
13231
- writeFileSync13(backupOld, readFileSync17(configPath), { mode: 384 });
13278
+ writeFileSync14(backupOld, readFileSync18(configPath), { mode: 384 });
13232
13279
  console.log(` ↻ Existing config saved to ${backupOld}`);
13233
13280
  }
13234
- writeFileSync13(configPath, Buffer.from(plaintext), { mode: 384 });
13281
+ writeFileSync14(configPath, Buffer.from(plaintext), { mode: 384 });
13235
13282
  console.log(`
13236
13283
  ✓ Config restored to ${configPath}`);
13237
13284
  console.log(" Run `claudemesh list` to verify your meshes.\n");
@@ -13251,7 +13298,7 @@ __export(exports_upgrade, {
13251
13298
  runUpgrade: () => runUpgrade
13252
13299
  });
13253
13300
  import { spawnSync as spawnSync6 } from "node:child_process";
13254
- import { existsSync as existsSync24 } from "node:fs";
13301
+ import { existsSync as existsSync23 } from "node:fs";
13255
13302
  import { dirname as dirname8, join as join14, resolve as resolve2 } from "node:path";
13256
13303
  async function latestVersion() {
13257
13304
  try {
@@ -13266,14 +13313,14 @@ async function latestVersion() {
13266
13313
  }
13267
13314
  function findNpm() {
13268
13315
  const portable = join14(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
13269
- if (existsSync24(portable)) {
13316
+ if (existsSync23(portable)) {
13270
13317
  return { npm: portable, prefix: join14(process.env.HOME ?? "", ".claudemesh") };
13271
13318
  }
13272
13319
  let cur = resolve2(process.argv[1] ?? ".");
13273
13320
  for (let i = 0;i < 6; i++) {
13274
13321
  cur = dirname8(cur);
13275
13322
  const candidate = join14(cur, "bin", "npm");
13276
- if (existsSync24(candidate))
13323
+ if (existsSync23(candidate))
13277
13324
  return { npm: candidate };
13278
13325
  }
13279
13326
  return { npm: "npm" };
@@ -13335,8 +13382,8 @@ __export(exports_grants, {
13335
13382
  runBlock: () => runBlock,
13336
13383
  isAllowed: () => isAllowed
13337
13384
  });
13338
- import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync18, writeFileSync as writeFileSync14 } from "node:fs";
13339
- import { homedir as homedir12 } from "node:os";
13385
+ import { existsSync as existsSync24, mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync15 } from "node:fs";
13386
+ import { homedir as homedir11 } from "node:os";
13340
13387
  import { join as join15 } from "node:path";
13341
13388
  async function syncToBroker(meshSlug, grants) {
13342
13389
  const auth = getStoredToken();
@@ -13355,19 +13402,19 @@ async function syncToBroker(meshSlug, grants) {
13355
13402
  }
13356
13403
  }
13357
13404
  function readGrants() {
13358
- if (!existsSync25(GRANT_FILE))
13405
+ if (!existsSync24(GRANT_FILE))
13359
13406
  return {};
13360
13407
  try {
13361
- return JSON.parse(readFileSync18(GRANT_FILE, "utf-8"));
13408
+ return JSON.parse(readFileSync19(GRANT_FILE, "utf-8"));
13362
13409
  } catch {
13363
13410
  return {};
13364
13411
  }
13365
13412
  }
13366
13413
  function writeGrants(g) {
13367
- const dir = join15(homedir12(), ".claudemesh");
13368
- if (!existsSync25(dir))
13414
+ const dir = join15(homedir11(), ".claudemesh");
13415
+ if (!existsSync24(dir))
13369
13416
  mkdirSync10(dir, { recursive: true });
13370
- writeFileSync14(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
13417
+ writeFileSync15(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
13371
13418
  }
13372
13419
  function resolveCaps(input) {
13373
13420
  if (input.includes("all"))
@@ -13523,7 +13570,7 @@ var init_grants = __esm(() => {
13523
13570
  BROKER_HTTP7 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
13524
13571
  ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
13525
13572
  DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
13526
- GRANT_FILE = join15(homedir12(), ".claudemesh", "grants.json");
13573
+ GRANT_FILE = join15(homedir11(), ".claudemesh", "grants.json");
13527
13574
  });
13528
13575
 
13529
13576
  // src/commands/profile.ts
@@ -15205,7 +15252,7 @@ __export(exports_file, {
15205
15252
  });
15206
15253
  import { hostname as osHostname } from "node:os";
15207
15254
  import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
15208
- import { statSync as statSync6, existsSync as existsSync26, writeFileSync as writeFileSync15, mkdirSync as mkdirSync11 } from "node:fs";
15255
+ import { statSync as statSync7, existsSync as existsSync25, writeFileSync as writeFileSync16, mkdirSync as mkdirSync11 } from "node:fs";
15209
15256
  function emitJson2(data) {
15210
15257
  console.log(JSON.stringify(data, null, 2));
15211
15258
  }
@@ -15222,11 +15269,11 @@ async function runFileShare(filePath, opts) {
15222
15269
  return EXIT.INVALID_ARGS;
15223
15270
  }
15224
15271
  const absPath = resolvePath(filePath);
15225
- if (!existsSync26(absPath)) {
15272
+ if (!existsSync25(absPath)) {
15226
15273
  render.err(`File not found: ${absPath}`);
15227
15274
  return EXIT.INVALID_ARGS;
15228
15275
  }
15229
- const stat = statSync6(absPath);
15276
+ const stat = statSync7(absPath);
15230
15277
  if (!stat.isFile()) {
15231
15278
  render.err(`Not a regular file: ${absPath}`);
15232
15279
  return EXIT.INVALID_ARGS;
@@ -15302,7 +15349,7 @@ async function runFileGet(fileId, opts) {
15302
15349
  const buf = Buffer.from(await res.arrayBuffer());
15303
15350
  const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
15304
15351
  mkdirSync11(dirname9(outPath), { recursive: true });
15305
- writeFileSync15(outPath, buf);
15352
+ writeFileSync16(outPath, buf);
15306
15353
  if (opts.json) {
15307
15354
  emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
15308
15355
  } else {
@@ -15912,7 +15959,7 @@ __export(exports_bridge, {
15912
15959
  runBridge: () => runBridge,
15913
15960
  bridgeConfigTemplate: () => bridgeConfigTemplate
15914
15961
  });
15915
- import { readFileSync as readFileSync19, existsSync as existsSync27 } from "node:fs";
15962
+ import { readFileSync as readFileSync20, existsSync as existsSync26 } from "node:fs";
15916
15963
  function parseConfig(text) {
15917
15964
  const trimmed = text.trim();
15918
15965
  if (trimmed.startsWith("{"))
@@ -15956,13 +16003,13 @@ async function runBridge(configPath) {
15956
16003
  render.err("Usage: claudemesh bridge run <config.yaml>");
15957
16004
  return EXIT.INVALID_ARGS;
15958
16005
  }
15959
- if (!existsSync27(configPath)) {
16006
+ if (!existsSync26(configPath)) {
15960
16007
  render.err(`config file not found: ${configPath}`);
15961
16008
  return EXIT.NOT_FOUND;
15962
16009
  }
15963
16010
  let cfg;
15964
16011
  try {
15965
- cfg = parseConfig(readFileSync19(configPath, "utf-8"));
16012
+ cfg = parseConfig(readFileSync20(configPath, "utf-8"));
15966
16013
  } catch (e) {
15967
16014
  render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
15968
16015
  return EXIT.INVALID_ARGS;
@@ -16936,11 +16983,11 @@ import {
16936
16983
  ListResourcesRequestSchema,
16937
16984
  ReadResourceRequestSchema
16938
16985
  } from "@modelcontextprotocol/sdk/types.js";
16939
- import { existsSync as existsSync28 } from "node:fs";
16986
+ import { existsSync as existsSync27 } from "node:fs";
16940
16987
  import { request as httpRequest2 } from "node:http";
16941
16988
  async function daemonReady() {
16942
16989
  for (let i = 0;i < DAEMON_BOOT_RETRIES; i++) {
16943
- if (existsSync28(DAEMON_PATHS.SOCK_FILE))
16990
+ if (existsSync27(DAEMON_PATHS.SOCK_FILE))
16944
16991
  return true;
16945
16992
  await new Promise((r) => setTimeout(r, DAEMON_BOOT_RETRY_MS));
16946
16993
  }
@@ -18017,10 +18064,12 @@ async function gate(ctx, opts) {
18017
18064
  }
18018
18065
 
18019
18066
  // src/entrypoints/cli.ts
18067
+ init_policy();
18020
18068
  init_styles();
18021
18069
  installSignalHandlers();
18022
18070
  installErrorHandlers();
18023
18071
  var { command, positionals, flags } = parseArgv(process.argv);
18072
+ setDaemonPolicy(policyFromFlags(flags));
18024
18073
  function resolveApprovalMode() {
18025
18074
  const raw = flags["approval-mode"] ?? process.env.CLAUDEMESH_APPROVAL_MODE ?? null;
18026
18075
  if (raw === "plan" || raw === "read-only" || raw === "write" || raw === "yolo")
@@ -18197,6 +18246,8 @@ Flags
18197
18246
  --policy <path> override policy file
18198
18247
  -y, --yes skip confirmations (= --approval-mode yolo)
18199
18248
  -q, --quiet suppress non-essential output
18249
+ --strict require daemon for broker-touching verbs (no cold-path fallback)
18250
+ --no-daemon skip daemon entirely; open broker WS directly (CI / sandboxed scripts)
18200
18251
  `;
18201
18252
  function colorizeHelp(raw) {
18202
18253
  const lines = raw.split(`
@@ -19238,4 +19289,4 @@ main().catch((err) => {
19238
19289
  process.exit(EXIT.INTERNAL_ERROR);
19239
19290
  });
19240
19291
 
19241
- //# debugId=856EC7628E8E9AE364756E2164756E21
19292
+ //# debugId=04E4A5313AE4F0EA64756E2164756E21