claudemesh-cli 1.27.1 → 1.27.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/entrypoints/cli.js
CHANGED
|
@@ -103,7 +103,7 @@ __export(exports_urls, {
|
|
|
103
103
|
VERSION: () => VERSION,
|
|
104
104
|
URLS: () => URLS
|
|
105
105
|
});
|
|
106
|
-
var URLS, VERSION = "1.27.
|
|
106
|
+
var URLS, VERSION = "1.27.3", env;
|
|
107
107
|
var init_urls = __esm(() => {
|
|
108
108
|
URLS = {
|
|
109
109
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -3588,12 +3588,6 @@ var init_spinner = __esm(() => {
|
|
|
3588
3588
|
});
|
|
3589
3589
|
|
|
3590
3590
|
// 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
3591
|
import { join as join3 } from "node:path";
|
|
3598
3592
|
var DAEMON_PATHS, DAEMON_TCP_HOST = "127.0.0.1", DAEMON_TCP_DEFAULT_PORT = 47823;
|
|
3599
3593
|
var init_paths2 = __esm(() => {
|
|
@@ -3623,6 +3617,255 @@ var init_paths2 = __esm(() => {
|
|
|
3623
3617
|
};
|
|
3624
3618
|
});
|
|
3625
3619
|
|
|
3620
|
+
// src/daemon/local-token.ts
|
|
3621
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
3622
|
+
import { dirname as dirname2 } from "node:path";
|
|
3623
|
+
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
3624
|
+
function readLocalToken() {
|
|
3625
|
+
try {
|
|
3626
|
+
return readFileSync4(DAEMON_PATHS.TOKEN_FILE, "utf8").trim();
|
|
3627
|
+
} catch {
|
|
3628
|
+
return null;
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
function ensureLocalToken() {
|
|
3632
|
+
const existing = readLocalToken();
|
|
3633
|
+
if (existing)
|
|
3634
|
+
return existing;
|
|
3635
|
+
mkdirSync3(dirname2(DAEMON_PATHS.TOKEN_FILE), { recursive: true, mode: 448 });
|
|
3636
|
+
const tok = randomBytes4(32).toString("base64url");
|
|
3637
|
+
writeFileSync4(DAEMON_PATHS.TOKEN_FILE, tok + `
|
|
3638
|
+
`, { mode: 384 });
|
|
3639
|
+
return tok;
|
|
3640
|
+
}
|
|
3641
|
+
var init_local_token = __esm(() => {
|
|
3642
|
+
init_paths2();
|
|
3643
|
+
});
|
|
3644
|
+
|
|
3645
|
+
// src/daemon/ipc/client.ts
|
|
3646
|
+
import { request as httpRequest } from "node:http";
|
|
3647
|
+
async function ipc(opts) {
|
|
3648
|
+
const useTcp = !!opts.preferTcp;
|
|
3649
|
+
const headers = {
|
|
3650
|
+
accept: "application/json",
|
|
3651
|
+
host: "localhost"
|
|
3652
|
+
};
|
|
3653
|
+
let bodyBuf;
|
|
3654
|
+
if (opts.body !== undefined) {
|
|
3655
|
+
bodyBuf = Buffer.from(JSON.stringify(opts.body), "utf8");
|
|
3656
|
+
headers["content-type"] = "application/json";
|
|
3657
|
+
headers["content-length"] = String(bodyBuf.length);
|
|
3658
|
+
}
|
|
3659
|
+
if (useTcp) {
|
|
3660
|
+
const tok = readLocalToken();
|
|
3661
|
+
if (!tok)
|
|
3662
|
+
throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
|
|
3663
|
+
headers.authorization = `Bearer ${tok}`;
|
|
3664
|
+
}
|
|
3665
|
+
return new Promise((resolve, reject) => {
|
|
3666
|
+
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) => {
|
|
3667
|
+
const chunks = [];
|
|
3668
|
+
res.on("data", (c) => chunks.push(c));
|
|
3669
|
+
res.on("end", () => {
|
|
3670
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
3671
|
+
let parsed = raw;
|
|
3672
|
+
try {
|
|
3673
|
+
parsed = raw.length > 0 ? JSON.parse(raw) : null;
|
|
3674
|
+
} catch {}
|
|
3675
|
+
resolve({ status: res.statusCode ?? 0, body: parsed });
|
|
3676
|
+
});
|
|
3677
|
+
});
|
|
3678
|
+
req.setTimeout(opts.timeoutMs ?? 5000, () => req.destroy(new Error("ipc_timeout")));
|
|
3679
|
+
req.on("error", (err) => reject(err));
|
|
3680
|
+
if (bodyBuf)
|
|
3681
|
+
req.write(bodyBuf);
|
|
3682
|
+
req.end();
|
|
3683
|
+
});
|
|
3684
|
+
}
|
|
3685
|
+
var IpcError;
|
|
3686
|
+
var init_client3 = __esm(() => {
|
|
3687
|
+
init_paths2();
|
|
3688
|
+
init_local_token();
|
|
3689
|
+
IpcError = class IpcError extends Error {
|
|
3690
|
+
status;
|
|
3691
|
+
payload;
|
|
3692
|
+
constructor(status, payload, msg) {
|
|
3693
|
+
super(msg);
|
|
3694
|
+
this.status = status;
|
|
3695
|
+
this.payload = payload;
|
|
3696
|
+
}
|
|
3697
|
+
};
|
|
3698
|
+
});
|
|
3699
|
+
|
|
3700
|
+
// src/services/daemon/lifecycle.ts
|
|
3701
|
+
var exports_lifecycle = {};
|
|
3702
|
+
__export(exports_lifecycle, {
|
|
3703
|
+
ensureDaemonReady: () => ensureDaemonReady,
|
|
3704
|
+
_resetDaemonReadyCache: () => _resetDaemonReadyCache
|
|
3705
|
+
});
|
|
3706
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3707
|
+
import { join as join4 } from "node:path";
|
|
3708
|
+
async function ensureDaemonReady(opts = {}) {
|
|
3709
|
+
if (lastResultThisProcess && (lastResultThisProcess.state === "up" || lastResultThisProcess.state === "started")) {
|
|
3710
|
+
return lastResultThisProcess;
|
|
3711
|
+
}
|
|
3712
|
+
if (process.env.CLAUDEMESH_INTERNAL_NO_AUTOSPAWN === "1") {
|
|
3713
|
+
opts = { ...opts, noAutoSpawn: true };
|
|
3714
|
+
}
|
|
3715
|
+
const result = await runEnsureDaemon(opts);
|
|
3716
|
+
lastResultThisProcess = result;
|
|
3717
|
+
return result;
|
|
3718
|
+
}
|
|
3719
|
+
function _resetDaemonReadyCache() {
|
|
3720
|
+
lastResultThisProcess = null;
|
|
3721
|
+
}
|
|
3722
|
+
async function runEnsureDaemon(opts) {
|
|
3723
|
+
const t0 = Date.now();
|
|
3724
|
+
const probe = await probeDaemon();
|
|
3725
|
+
if (probe === "up")
|
|
3726
|
+
return { state: "up", durationMs: Date.now() - t0 };
|
|
3727
|
+
if (probe === "stale")
|
|
3728
|
+
cleanupStaleFiles();
|
|
3729
|
+
if (opts.noAutoSpawn) {
|
|
3730
|
+
return { state: "down", durationMs: Date.now() - t0, reason: "auto-spawn disabled" };
|
|
3731
|
+
}
|
|
3732
|
+
if (recentSpawnFailureFresh()) {
|
|
3733
|
+
return {
|
|
3734
|
+
state: "spawn-suppressed",
|
|
3735
|
+
durationMs: Date.now() - t0,
|
|
3736
|
+
reason: `daemon failed to start within last ${Math.round(SPAWN_FAIL_TTL_MS / 1000)}s`
|
|
3737
|
+
};
|
|
3738
|
+
}
|
|
3739
|
+
const spawnRes = await spawnDaemon(opts);
|
|
3740
|
+
if (spawnRes.ok) {
|
|
3741
|
+
return { state: "started", durationMs: Date.now() - t0 };
|
|
3742
|
+
}
|
|
3743
|
+
markSpawnFailure();
|
|
3744
|
+
return { state: "spawn-failed", durationMs: Date.now() - t0, reason: spawnRes.reason };
|
|
3745
|
+
}
|
|
3746
|
+
async function probeDaemon() {
|
|
3747
|
+
if (!existsSync5(DAEMON_PATHS.SOCK_FILE))
|
|
3748
|
+
return "absent";
|
|
3749
|
+
try {
|
|
3750
|
+
const res = await ipc({ path: "/v1/version", timeoutMs: PROBE_TIMEOUT_MS });
|
|
3751
|
+
if (res.status === 200)
|
|
3752
|
+
return "up";
|
|
3753
|
+
return "stale";
|
|
3754
|
+
} catch (err) {
|
|
3755
|
+
if (err instanceof IpcError)
|
|
3756
|
+
return "stale";
|
|
3757
|
+
const msg = String(err);
|
|
3758
|
+
if (/ENOENT|ECONNREFUSED|ipc_timeout|EPIPE|ECONNRESET/.test(msg))
|
|
3759
|
+
return "stale";
|
|
3760
|
+
return "stale";
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
function cleanupStaleFiles() {
|
|
3764
|
+
for (const p of [DAEMON_PATHS.SOCK_FILE, DAEMON_PATHS.PID_FILE]) {
|
|
3765
|
+
try {
|
|
3766
|
+
unlinkSync2(p);
|
|
3767
|
+
} catch {}
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
function recentSpawnFailureFresh() {
|
|
3771
|
+
try {
|
|
3772
|
+
const st = statSync(SPAWN_FAIL_FILE());
|
|
3773
|
+
return Date.now() - st.mtimeMs < SPAWN_FAIL_TTL_MS;
|
|
3774
|
+
} catch {
|
|
3775
|
+
return false;
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
function markSpawnFailure() {
|
|
3779
|
+
try {
|
|
3780
|
+
writeFileSync5(SPAWN_FAIL_FILE(), String(Date.now()), { mode: 384 });
|
|
3781
|
+
} catch {}
|
|
3782
|
+
}
|
|
3783
|
+
function clearSpawnFailure() {
|
|
3784
|
+
try {
|
|
3785
|
+
unlinkSync2(SPAWN_FAIL_FILE());
|
|
3786
|
+
} catch {}
|
|
3787
|
+
}
|
|
3788
|
+
async function spawnDaemon(opts) {
|
|
3789
|
+
const lockResult = await acquireOrShareLock(opts);
|
|
3790
|
+
if (lockResult === "wait-existing") {
|
|
3791
|
+
return await pollForSocket(opts.budgetMs ?? 3000);
|
|
3792
|
+
}
|
|
3793
|
+
try {
|
|
3794
|
+
const { spawn } = await import("node:child_process");
|
|
3795
|
+
const binary = await resolveCliBinary();
|
|
3796
|
+
const args = ["daemon", "up"];
|
|
3797
|
+
if (opts.mesh)
|
|
3798
|
+
args.push("--mesh", opts.mesh);
|
|
3799
|
+
const child = spawn(binary, args, {
|
|
3800
|
+
detached: true,
|
|
3801
|
+
stdio: "ignore",
|
|
3802
|
+
env: { ...process.env, CLAUDEMESH_INTERNAL_NO_AUTOSPAWN: "1" }
|
|
3803
|
+
});
|
|
3804
|
+
child.unref();
|
|
3805
|
+
const polled = await pollForSocket(opts.budgetMs ?? 3000);
|
|
3806
|
+
if (polled.ok)
|
|
3807
|
+
clearSpawnFailure();
|
|
3808
|
+
return polled;
|
|
3809
|
+
} catch (err) {
|
|
3810
|
+
return { ok: false, reason: err instanceof Error ? err.message : String(err) };
|
|
3811
|
+
} finally {
|
|
3812
|
+
releaseLock();
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
async function acquireOrShareLock(_opts) {
|
|
3816
|
+
const lockPath = SPAWN_LOCK_FILE();
|
|
3817
|
+
if (existsSync5(lockPath)) {
|
|
3818
|
+
try {
|
|
3819
|
+
const pidStr = readFileSync5(lockPath, "utf8").trim();
|
|
3820
|
+
const pid = Number.parseInt(pidStr, 10);
|
|
3821
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
3822
|
+
try {
|
|
3823
|
+
process.kill(pid, 0);
|
|
3824
|
+
return "wait-existing";
|
|
3825
|
+
} catch {}
|
|
3826
|
+
}
|
|
3827
|
+
} catch {}
|
|
3828
|
+
}
|
|
3829
|
+
try {
|
|
3830
|
+
writeFileSync5(lockPath, String(process.pid), { mode: 384 });
|
|
3831
|
+
} catch {}
|
|
3832
|
+
return "acquired";
|
|
3833
|
+
}
|
|
3834
|
+
function releaseLock() {
|
|
3835
|
+
try {
|
|
3836
|
+
unlinkSync2(SPAWN_LOCK_FILE());
|
|
3837
|
+
} catch {}
|
|
3838
|
+
}
|
|
3839
|
+
async function pollForSocket(budgetMs) {
|
|
3840
|
+
const start = Date.now();
|
|
3841
|
+
while (Date.now() - start < budgetMs) {
|
|
3842
|
+
if (existsSync5(DAEMON_PATHS.SOCK_FILE)) {
|
|
3843
|
+
const probe = await probeDaemon();
|
|
3844
|
+
if (probe === "up")
|
|
3845
|
+
return { ok: true };
|
|
3846
|
+
}
|
|
3847
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
3848
|
+
}
|
|
3849
|
+
return { ok: false, reason: `socket did not appear within ${budgetMs}ms` };
|
|
3850
|
+
}
|
|
3851
|
+
async function resolveCliBinary() {
|
|
3852
|
+
const argv1 = process.argv[1] ?? "claudemesh";
|
|
3853
|
+
if (/\.ts$/.test(argv1) || /node_modules|src\/entrypoints/.test(argv1)) {
|
|
3854
|
+
try {
|
|
3855
|
+
const { execSync } = await import("node:child_process");
|
|
3856
|
+
return execSync("which claudemesh", { encoding: "utf8" }).trim() || "claudemesh";
|
|
3857
|
+
} catch {
|
|
3858
|
+
return "claudemesh";
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
return argv1;
|
|
3862
|
+
}
|
|
3863
|
+
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;
|
|
3864
|
+
var init_lifecycle = __esm(() => {
|
|
3865
|
+
init_client3();
|
|
3866
|
+
init_paths2();
|
|
3867
|
+
});
|
|
3868
|
+
|
|
3626
3869
|
// src/commands/launch.ts
|
|
3627
3870
|
var exports_launch = {};
|
|
3628
3871
|
__export(exports_launch, {
|
|
@@ -3630,42 +3873,26 @@ __export(exports_launch, {
|
|
|
3630
3873
|
});
|
|
3631
3874
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
3632
3875
|
import { randomUUID } from "node:crypto";
|
|
3633
|
-
import { mkdtempSync, writeFileSync as
|
|
3876
|
+
import { mkdtempSync, writeFileSync as writeFileSync6, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
|
|
3634
3877
|
import { tmpdir, hostname as hostname2, homedir as homedir3 } from "node:os";
|
|
3635
|
-
import { join as
|
|
3878
|
+
import { join as join5 } from "node:path";
|
|
3636
3879
|
import { createInterface as createInterface4 } from "node:readline";
|
|
3637
3880
|
async function ensureDaemonRunning(meshSlug, quiet) {
|
|
3638
|
-
const {
|
|
3639
|
-
if (existsSync5(DAEMON_PATHS2.SOCK_FILE))
|
|
3640
|
-
return;
|
|
3881
|
+
const { ensureDaemonReady: ensureDaemonReady2 } = await Promise.resolve().then(() => (init_lifecycle(), exports_lifecycle));
|
|
3641
3882
|
if (!quiet)
|
|
3642
|
-
render.info("
|
|
3643
|
-
const
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
const { execSync } = await import("node:child_process");
|
|
3649
|
-
binary = execSync("which claudemesh", { encoding: "utf8" }).trim();
|
|
3650
|
-
} catch {
|
|
3651
|
-
binary = "claudemesh";
|
|
3652
|
-
}
|
|
3883
|
+
render.info("ensuring claudemesh daemon is running…");
|
|
3884
|
+
const res = await ensureDaemonReady2({ budgetMs: 1e4, mesh: meshSlug });
|
|
3885
|
+
if (res.state === "up") {
|
|
3886
|
+
if (!quiet)
|
|
3887
|
+
render.ok("daemon already running");
|
|
3888
|
+
return;
|
|
3653
3889
|
}
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
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));
|
|
3890
|
+
if (res.state === "started") {
|
|
3891
|
+
if (!quiet)
|
|
3892
|
+
render.ok(`daemon ready (${res.durationMs}ms)`);
|
|
3893
|
+
return;
|
|
3667
3894
|
}
|
|
3668
|
-
render.warn(
|
|
3895
|
+
render.warn(`daemon ${res.state}${res.reason ? `: ${res.reason}` : ""}`, "Run `claudemesh daemon up --mesh " + meshSlug + "` manually, then re-launch.");
|
|
3669
3896
|
}
|
|
3670
3897
|
function parseGroupsString(raw) {
|
|
3671
3898
|
return raw.split(",").map((s) => s.trim()).filter(Boolean).map((token) => {
|
|
@@ -3986,17 +4213,17 @@ async function runLaunch(flags, rawArgs) {
|
|
|
3986
4213
|
for (const entry of readdirSync(tmpBase)) {
|
|
3987
4214
|
if (!entry.startsWith("claudemesh-"))
|
|
3988
4215
|
continue;
|
|
3989
|
-
const full =
|
|
3990
|
-
const age = Date.now() -
|
|
4216
|
+
const full = join5(tmpBase, entry);
|
|
4217
|
+
const age = Date.now() - statSync2(full).mtimeMs;
|
|
3991
4218
|
if (age > 3600000)
|
|
3992
4219
|
rmSync(full, { recursive: true, force: true });
|
|
3993
4220
|
}
|
|
3994
4221
|
} catch {}
|
|
3995
4222
|
await ensureDaemonRunning(mesh.slug, args.quiet);
|
|
3996
4223
|
try {
|
|
3997
|
-
const claudeConfigPath =
|
|
3998
|
-
if (
|
|
3999
|
-
const claudeConfig = JSON.parse(
|
|
4224
|
+
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4225
|
+
if (existsSync6(claudeConfigPath)) {
|
|
4226
|
+
const claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
|
|
4000
4227
|
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
4001
4228
|
let cleaned = 0;
|
|
4002
4229
|
for (const key of Object.keys(mcpServers)) {
|
|
@@ -4014,7 +4241,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4014
4241
|
}
|
|
4015
4242
|
if (cleaned > 0) {
|
|
4016
4243
|
claudeConfig.mcpServers = mcpServers;
|
|
4017
|
-
|
|
4244
|
+
writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4018
4245
|
`, "utf-8");
|
|
4019
4246
|
}
|
|
4020
4247
|
}
|
|
@@ -4031,7 +4258,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4031
4258
|
console.log(" (Could not fetch service catalog — mesh services won't be natively available)");
|
|
4032
4259
|
}
|
|
4033
4260
|
}
|
|
4034
|
-
const tmpDir = mkdtempSync(
|
|
4261
|
+
const tmpDir = mkdtempSync(join5(tmpdir(), "claudemesh-"));
|
|
4035
4262
|
const sessionConfig = {
|
|
4036
4263
|
version: 1,
|
|
4037
4264
|
meshes: [mesh],
|
|
@@ -4040,17 +4267,17 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4040
4267
|
...parsedGroups.length > 0 ? { groups: parsedGroups } : {},
|
|
4041
4268
|
messageMode
|
|
4042
4269
|
};
|
|
4043
|
-
|
|
4270
|
+
writeFileSync6(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
|
|
4044
4271
|
`, "utf-8");
|
|
4045
4272
|
if (!args.quiet) {
|
|
4046
4273
|
printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
|
|
4047
4274
|
}
|
|
4048
4275
|
const meshMcpEntries = [];
|
|
4049
4276
|
if (serviceCatalog.length > 0) {
|
|
4050
|
-
const claudeConfigPath =
|
|
4277
|
+
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4051
4278
|
let claudeConfig = {};
|
|
4052
4279
|
try {
|
|
4053
|
-
claudeConfig = JSON.parse(
|
|
4280
|
+
claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
|
|
4054
4281
|
} catch {
|
|
4055
4282
|
claudeConfig = {};
|
|
4056
4283
|
}
|
|
@@ -4077,7 +4304,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4077
4304
|
meshMcpEntries.push({ key: entryKey, entry });
|
|
4078
4305
|
}
|
|
4079
4306
|
claudeConfig.mcpServers = mcpServers;
|
|
4080
|
-
|
|
4307
|
+
writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4081
4308
|
`, "utf-8");
|
|
4082
4309
|
if (!args.quiet && meshMcpEntries.length > 0) {
|
|
4083
4310
|
console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
|
|
@@ -4114,12 +4341,12 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4114
4341
|
let claudeBin = "claude";
|
|
4115
4342
|
if (!isWindows2) {
|
|
4116
4343
|
const candidates = [
|
|
4117
|
-
|
|
4344
|
+
join5(homedir3(), ".local", "bin", "claude"),
|
|
4118
4345
|
"/usr/local/bin/claude",
|
|
4119
|
-
|
|
4346
|
+
join5(homedir3(), ".claude", "bin", "claude")
|
|
4120
4347
|
];
|
|
4121
4348
|
for (const c of candidates) {
|
|
4122
|
-
if (
|
|
4349
|
+
if (existsSync6(c)) {
|
|
4123
4350
|
claudeBin = c;
|
|
4124
4351
|
break;
|
|
4125
4352
|
}
|
|
@@ -4128,14 +4355,14 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4128
4355
|
const cleanup = () => {
|
|
4129
4356
|
if (meshMcpEntries.length > 0) {
|
|
4130
4357
|
try {
|
|
4131
|
-
const claudeConfigPath =
|
|
4132
|
-
const claudeConfig = JSON.parse(
|
|
4358
|
+
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4359
|
+
const claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
|
|
4133
4360
|
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
4134
4361
|
for (const { key } of meshMcpEntries) {
|
|
4135
4362
|
delete mcpServers[key];
|
|
4136
4363
|
}
|
|
4137
4364
|
claudeConfig.mcpServers = mcpServers;
|
|
4138
|
-
|
|
4365
|
+
writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4139
4366
|
`, "utf-8");
|
|
4140
4367
|
} catch {}
|
|
4141
4368
|
}
|
|
@@ -4832,8 +5059,8 @@ __export(exports_join, {
|
|
|
4832
5059
|
runJoin: () => runJoin
|
|
4833
5060
|
});
|
|
4834
5061
|
import sodium3 from "libsodium-wrappers";
|
|
4835
|
-
import { writeFileSync as
|
|
4836
|
-
import { join as
|
|
5062
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync4 } from "node:fs";
|
|
5063
|
+
import { join as join6, dirname as dirname3 } from "node:path";
|
|
4837
5064
|
import { homedir as homedir4, hostname as hostname3 } from "node:os";
|
|
4838
5065
|
function deriveAppBaseUrl() {
|
|
4839
5066
|
const override = process.env.CLAUDEMESH_APP_URL;
|
|
@@ -4953,11 +5180,11 @@ async function runJoin(args) {
|
|
|
4953
5180
|
joinedAt: new Date().toISOString()
|
|
4954
5181
|
});
|
|
4955
5182
|
writeConfig(config);
|
|
4956
|
-
const configDir = env.CLAUDEMESH_CONFIG_DIR ??
|
|
4957
|
-
const inviteFile =
|
|
5183
|
+
const configDir = env.CLAUDEMESH_CONFIG_DIR ?? join6(homedir4(), ".claudemesh");
|
|
5184
|
+
const inviteFile = join6(configDir, `invite-${payload.mesh_slug}.txt`);
|
|
4958
5185
|
try {
|
|
4959
|
-
|
|
4960
|
-
|
|
5186
|
+
mkdirSync4(dirname3(inviteFile), { recursive: true });
|
|
5187
|
+
writeFileSync7(inviteFile, link, "utf-8");
|
|
4961
5188
|
} catch {}
|
|
4962
5189
|
console.log("");
|
|
4963
5190
|
console.log(`✓ Joined "${payload.mesh_slug}" as ${displayName}${enroll.alreadyMember ? " (already a member — re-enrolled with same pubkey)" : ""}`);
|
|
@@ -7160,9 +7387,9 @@ var init_ban = __esm(() => {
|
|
|
7160
7387
|
|
|
7161
7388
|
// src/services/bridge/protocol.ts
|
|
7162
7389
|
import { homedir as homedir5 } from "node:os";
|
|
7163
|
-
import { join as
|
|
7390
|
+
import { join as join7 } from "node:path";
|
|
7164
7391
|
function socketPath(meshSlug) {
|
|
7165
|
-
return
|
|
7392
|
+
return join7(homedir5(), ".claudemesh", "sockets", `${meshSlug}.sock`);
|
|
7166
7393
|
}
|
|
7167
7394
|
function frame(obj) {
|
|
7168
7395
|
return JSON.stringify(obj) + `
|
|
@@ -7189,11 +7416,11 @@ var init_protocol = () => {};
|
|
|
7189
7416
|
|
|
7190
7417
|
// src/services/bridge/client.ts
|
|
7191
7418
|
import { createConnection } from "node:net";
|
|
7192
|
-
import { existsSync as
|
|
7419
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
7193
7420
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
7194
7421
|
async function tryBridge(meshSlug, verb, args = {}, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
7195
7422
|
const path = socketPath(meshSlug);
|
|
7196
|
-
if (!
|
|
7423
|
+
if (!existsSync7(path))
|
|
7197
7424
|
return null;
|
|
7198
7425
|
return new Promise((resolve) => {
|
|
7199
7426
|
const id = randomUUID2();
|
|
@@ -7255,88 +7482,44 @@ async function tryBridge(meshSlug, verb, args = {}, timeoutMs = DEFAULT_TIMEOUT_
|
|
|
7255
7482
|
});
|
|
7256
7483
|
}
|
|
7257
7484
|
var DEFAULT_TIMEOUT_MS = 5000;
|
|
7258
|
-
var
|
|
7485
|
+
var init_client4 = __esm(() => {
|
|
7259
7486
|
init_protocol();
|
|
7260
7487
|
});
|
|
7261
7488
|
|
|
7262
|
-
// src/
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
}
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
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}`;
|
|
7489
|
+
// src/ui/warnings.ts
|
|
7490
|
+
function warnDaemonState(res, opts = {}) {
|
|
7491
|
+
if (alreadyWarned)
|
|
7492
|
+
return false;
|
|
7493
|
+
if (opts.quiet || opts.json)
|
|
7494
|
+
return false;
|
|
7495
|
+
if (res.state === "up")
|
|
7496
|
+
return false;
|
|
7497
|
+
alreadyWarned = true;
|
|
7498
|
+
const tag = (label) => `[claudemesh] ${label}`;
|
|
7499
|
+
const hint = (s) => dim(s);
|
|
7500
|
+
switch (res.state) {
|
|
7501
|
+
case "started":
|
|
7502
|
+
process.stderr.write(`${tag("info")} daemon restarted automatically ${hint(`(took ${res.durationMs}ms)`)}
|
|
7503
|
+
`);
|
|
7504
|
+
return true;
|
|
7505
|
+
case "down":
|
|
7506
|
+
process.stderr.write(`${tag("info")} daemon not running — using cold path ${hint("(slower; run `claudemesh daemon up` for warm path)")}
|
|
7507
|
+
`);
|
|
7508
|
+
return true;
|
|
7509
|
+
case "spawn-suppressed":
|
|
7510
|
+
process.stderr.write(`${tag("warn")} ${res.reason ?? "daemon failed to start recently"} — using cold path ${hint("(run `claudemesh doctor`)")}
|
|
7511
|
+
`);
|
|
7512
|
+
return true;
|
|
7513
|
+
case "spawn-failed":
|
|
7514
|
+
process.stderr.write(`${tag("warn")} daemon spawn failed${res.reason ? `: ${res.reason}` : ""} — using cold path ${hint("(check ~/.claudemesh/daemon/daemon.log)")}
|
|
7515
|
+
`);
|
|
7516
|
+
return true;
|
|
7306
7517
|
}
|
|
7307
|
-
return
|
|
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
|
-
});
|
|
7518
|
+
return false;
|
|
7326
7519
|
}
|
|
7327
|
-
var
|
|
7328
|
-
var
|
|
7329
|
-
|
|
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
|
-
};
|
|
7520
|
+
var alreadyWarned = false;
|
|
7521
|
+
var init_warnings = __esm(() => {
|
|
7522
|
+
init_styles();
|
|
7340
7523
|
});
|
|
7341
7524
|
|
|
7342
7525
|
// src/services/bridge/daemon-route.ts
|
|
@@ -7353,12 +7536,16 @@ __export(exports_daemon_route, {
|
|
|
7353
7536
|
tryGetSkillViaDaemon: () => tryGetSkillViaDaemon,
|
|
7354
7537
|
tryForgetViaDaemon: () => tryForgetViaDaemon
|
|
7355
7538
|
});
|
|
7356
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
7357
7539
|
function meshQuery(mesh) {
|
|
7358
7540
|
return mesh ? `?mesh=${encodeURIComponent(mesh)}` : "";
|
|
7359
7541
|
}
|
|
7542
|
+
async function daemonReachable() {
|
|
7543
|
+
const res = await ensureDaemonReady();
|
|
7544
|
+
warnDaemonState(res, {});
|
|
7545
|
+
return res.state === "up" || res.state === "started";
|
|
7546
|
+
}
|
|
7360
7547
|
async function tryListPeersViaDaemon(mesh) {
|
|
7361
|
-
if (!
|
|
7548
|
+
if (!await daemonReachable())
|
|
7362
7549
|
return null;
|
|
7363
7550
|
try {
|
|
7364
7551
|
const res = await ipc({ path: `/v1/peers${meshQuery(mesh)}`, timeoutMs: 3000 });
|
|
@@ -7373,7 +7560,7 @@ async function tryListPeersViaDaemon(mesh) {
|
|
|
7373
7560
|
}
|
|
7374
7561
|
}
|
|
7375
7562
|
async function tryListSkillsViaDaemon(mesh) {
|
|
7376
|
-
if (!
|
|
7563
|
+
if (!await daemonReachable())
|
|
7377
7564
|
return null;
|
|
7378
7565
|
try {
|
|
7379
7566
|
const res = await ipc({ path: `/v1/skills${meshQuery(mesh)}`, timeoutMs: 3000 });
|
|
@@ -7388,7 +7575,7 @@ async function tryListSkillsViaDaemon(mesh) {
|
|
|
7388
7575
|
}
|
|
7389
7576
|
}
|
|
7390
7577
|
async function tryGetSkillViaDaemon(name, mesh) {
|
|
7391
|
-
if (!
|
|
7578
|
+
if (!await daemonReachable())
|
|
7392
7579
|
return null;
|
|
7393
7580
|
try {
|
|
7394
7581
|
const res = await ipc({
|
|
@@ -7405,7 +7592,7 @@ async function tryGetSkillViaDaemon(name, mesh) {
|
|
|
7405
7592
|
}
|
|
7406
7593
|
}
|
|
7407
7594
|
async function tryGetStateViaDaemon(key, mesh) {
|
|
7408
|
-
if (!
|
|
7595
|
+
if (!await daemonReachable())
|
|
7409
7596
|
return null;
|
|
7410
7597
|
try {
|
|
7411
7598
|
const path = `/v1/state?key=${encodeURIComponent(key)}${mesh ? `&mesh=${encodeURIComponent(mesh)}` : ""}`;
|
|
@@ -7423,7 +7610,7 @@ async function tryGetStateViaDaemon(key, mesh) {
|
|
|
7423
7610
|
}
|
|
7424
7611
|
}
|
|
7425
7612
|
async function tryListStateViaDaemon(mesh) {
|
|
7426
|
-
if (!
|
|
7613
|
+
if (!await daemonReachable())
|
|
7427
7614
|
return null;
|
|
7428
7615
|
try {
|
|
7429
7616
|
const res = await ipc({ path: `/v1/state${meshQuery(mesh)}`, timeoutMs: 3000 });
|
|
@@ -7438,7 +7625,7 @@ async function tryListStateViaDaemon(mesh) {
|
|
|
7438
7625
|
}
|
|
7439
7626
|
}
|
|
7440
7627
|
async function trySetStateViaDaemon(key, value, mesh) {
|
|
7441
|
-
if (!
|
|
7628
|
+
if (!await daemonReachable())
|
|
7442
7629
|
return false;
|
|
7443
7630
|
try {
|
|
7444
7631
|
const res = await ipc({
|
|
@@ -7453,7 +7640,7 @@ async function trySetStateViaDaemon(key, value, mesh) {
|
|
|
7453
7640
|
}
|
|
7454
7641
|
}
|
|
7455
7642
|
async function tryRememberViaDaemon(content, tags, mesh) {
|
|
7456
|
-
if (!
|
|
7643
|
+
if (!await daemonReachable())
|
|
7457
7644
|
return null;
|
|
7458
7645
|
try {
|
|
7459
7646
|
const res = await ipc({
|
|
@@ -7470,7 +7657,7 @@ async function tryRememberViaDaemon(content, tags, mesh) {
|
|
|
7470
7657
|
}
|
|
7471
7658
|
}
|
|
7472
7659
|
async function tryRecallViaDaemon(query, mesh) {
|
|
7473
|
-
if (!
|
|
7660
|
+
if (!await daemonReachable())
|
|
7474
7661
|
return null;
|
|
7475
7662
|
try {
|
|
7476
7663
|
const path = `/v1/memory?q=${encodeURIComponent(query)}${mesh ? `&mesh=${encodeURIComponent(mesh)}` : ""}`;
|
|
@@ -7486,7 +7673,7 @@ async function tryRecallViaDaemon(query, mesh) {
|
|
|
7486
7673
|
}
|
|
7487
7674
|
}
|
|
7488
7675
|
async function tryForgetViaDaemon(id, mesh) {
|
|
7489
|
-
if (!
|
|
7676
|
+
if (!await daemonReachable())
|
|
7490
7677
|
return false;
|
|
7491
7678
|
try {
|
|
7492
7679
|
const path = `/v1/memory/${encodeURIComponent(id)}${meshQuery(mesh)}`;
|
|
@@ -7497,7 +7684,7 @@ async function tryForgetViaDaemon(id, mesh) {
|
|
|
7497
7684
|
}
|
|
7498
7685
|
}
|
|
7499
7686
|
async function trySendViaDaemon(args) {
|
|
7500
|
-
if (!
|
|
7687
|
+
if (!await daemonReachable())
|
|
7501
7688
|
return null;
|
|
7502
7689
|
try {
|
|
7503
7690
|
const res = await ipc({
|
|
@@ -7529,8 +7716,9 @@ async function trySendViaDaemon(args) {
|
|
|
7529
7716
|
}
|
|
7530
7717
|
}
|
|
7531
7718
|
var init_daemon_route = __esm(() => {
|
|
7532
|
-
|
|
7533
|
-
|
|
7719
|
+
init_client3();
|
|
7720
|
+
init_lifecycle();
|
|
7721
|
+
init_warnings();
|
|
7534
7722
|
});
|
|
7535
7723
|
|
|
7536
7724
|
// src/commands/peers.ts
|
|
@@ -7631,7 +7819,7 @@ var FIELD_ALIAS;
|
|
|
7631
7819
|
var init_peers = __esm(() => {
|
|
7632
7820
|
init_connect();
|
|
7633
7821
|
init_facade();
|
|
7634
|
-
|
|
7822
|
+
init_client4();
|
|
7635
7823
|
init_render();
|
|
7636
7824
|
init_styles();
|
|
7637
7825
|
FIELD_ALIAS = {
|
|
@@ -7739,7 +7927,7 @@ async function runSend(flags, to, message) {
|
|
|
7739
7927
|
var init_send = __esm(() => {
|
|
7740
7928
|
init_connect();
|
|
7741
7929
|
init_facade();
|
|
7742
|
-
|
|
7930
|
+
init_client4();
|
|
7743
7931
|
init_daemon_route();
|
|
7744
7932
|
init_render();
|
|
7745
7933
|
init_styles();
|
|
@@ -8387,7 +8575,7 @@ async function runTaskComplete(id, result, opts) {
|
|
|
8387
8575
|
var init_broker_actions = __esm(() => {
|
|
8388
8576
|
init_connect();
|
|
8389
8577
|
init_facade();
|
|
8390
|
-
|
|
8578
|
+
init_client4();
|
|
8391
8579
|
init_daemon_route();
|
|
8392
8580
|
init_render();
|
|
8393
8581
|
init_styles();
|
|
@@ -8622,35 +8810,35 @@ var init_whoami = __esm(() => {
|
|
|
8622
8810
|
});
|
|
8623
8811
|
|
|
8624
8812
|
// src/daemon/lock.ts
|
|
8625
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as
|
|
8813
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
8626
8814
|
import { dirname as dirname4 } from "node:path";
|
|
8627
8815
|
function acquireSingletonLock() {
|
|
8628
8816
|
mkdirSync5(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
|
|
8629
8817
|
if (existsSync8(DAEMON_PATHS.PID_FILE)) {
|
|
8630
|
-
const raw =
|
|
8818
|
+
const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8631
8819
|
const oldPid = Number.parseInt(raw, 10);
|
|
8632
8820
|
if (Number.isFinite(oldPid) && oldPid > 0 && isProcessAlive(oldPid)) {
|
|
8633
8821
|
return { result: "already-running", pid: oldPid };
|
|
8634
8822
|
}
|
|
8635
8823
|
try {
|
|
8636
|
-
|
|
8824
|
+
unlinkSync3(DAEMON_PATHS.PID_FILE);
|
|
8637
8825
|
} catch {}
|
|
8638
|
-
|
|
8826
|
+
writeFileSync8(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
|
|
8639
8827
|
return { result: "stale", pid: process.pid };
|
|
8640
8828
|
}
|
|
8641
|
-
|
|
8829
|
+
writeFileSync8(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
|
|
8642
8830
|
return { result: "acquired", pid: process.pid };
|
|
8643
8831
|
}
|
|
8644
8832
|
function releaseSingletonLock() {
|
|
8645
8833
|
try {
|
|
8646
|
-
const raw =
|
|
8834
|
+
const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8647
8835
|
if (Number.parseInt(raw, 10) === process.pid)
|
|
8648
|
-
|
|
8836
|
+
unlinkSync3(DAEMON_PATHS.PID_FILE);
|
|
8649
8837
|
} catch {}
|
|
8650
8838
|
}
|
|
8651
8839
|
function readRunningPid() {
|
|
8652
8840
|
try {
|
|
8653
|
-
const raw =
|
|
8841
|
+
const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8654
8842
|
const pid = Number.parseInt(raw, 10);
|
|
8655
8843
|
if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
|
|
8656
8844
|
return pid;
|
|
@@ -9082,7 +9270,7 @@ function bindSseStream(res, bus) {
|
|
|
9082
9270
|
|
|
9083
9271
|
// src/daemon/ipc/server.ts
|
|
9084
9272
|
import { createServer as createServer2 } from "node:http";
|
|
9085
|
-
import { chmodSync as chmodSync3, existsSync as existsSync9, unlinkSync as
|
|
9273
|
+
import { chmodSync as chmodSync3, existsSync as existsSync9, unlinkSync as unlinkSync4 } from "node:fs";
|
|
9086
9274
|
import { timingSafeEqual } from "node:crypto";
|
|
9087
9275
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9088
9276
|
function startIpcServer(opts) {
|
|
@@ -9100,7 +9288,7 @@ function startIpcServer(opts) {
|
|
|
9100
9288
|
});
|
|
9101
9289
|
if (existsSync9(DAEMON_PATHS.SOCK_FILE)) {
|
|
9102
9290
|
try {
|
|
9103
|
-
|
|
9291
|
+
unlinkSync4(DAEMON_PATHS.SOCK_FILE);
|
|
9104
9292
|
} catch {}
|
|
9105
9293
|
}
|
|
9106
9294
|
const uds = createServer2(handler);
|
|
@@ -9136,7 +9324,7 @@ function startIpcServer(opts) {
|
|
|
9136
9324
|
tcp ? new Promise((res) => tcp.close(() => res())) : Promise.resolve()
|
|
9137
9325
|
]);
|
|
9138
9326
|
try {
|
|
9139
|
-
|
|
9327
|
+
unlinkSync4(DAEMON_PATHS.SOCK_FILE);
|
|
9140
9328
|
} catch {}
|
|
9141
9329
|
}
|
|
9142
9330
|
};
|
|
@@ -10533,12 +10721,12 @@ __export(exports_identity, {
|
|
|
10533
10721
|
checkFingerprint: () => checkFingerprint,
|
|
10534
10722
|
acceptCurrentHost: () => acceptCurrentHost
|
|
10535
10723
|
});
|
|
10536
|
-
import { existsSync as existsSync10, readFileSync as
|
|
10537
|
-
import { join as
|
|
10724
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "node:fs";
|
|
10725
|
+
import { join as join8 } from "node:path";
|
|
10538
10726
|
import { createHash as createHash2 } from "node:crypto";
|
|
10539
10727
|
import { networkInterfaces } from "node:os";
|
|
10540
10728
|
function path() {
|
|
10541
|
-
return
|
|
10729
|
+
return join8(DAEMON_PATHS.DAEMON_DIR, FILE_NAME);
|
|
10542
10730
|
}
|
|
10543
10731
|
function computeCurrentFingerprint() {
|
|
10544
10732
|
const host_id = readHostId() ?? "";
|
|
@@ -10555,12 +10743,12 @@ function computeCurrentFingerprint() {
|
|
|
10555
10743
|
function checkFingerprint() {
|
|
10556
10744
|
const current = computeCurrentFingerprint();
|
|
10557
10745
|
if (!existsSync10(path())) {
|
|
10558
|
-
|
|
10746
|
+
writeFileSync9(path(), JSON.stringify(current, null, 2), { mode: 384 });
|
|
10559
10747
|
return { result: "first_run", current };
|
|
10560
10748
|
}
|
|
10561
10749
|
let stored;
|
|
10562
10750
|
try {
|
|
10563
|
-
stored = JSON.parse(
|
|
10751
|
+
stored = JSON.parse(readFileSync8(path(), "utf8"));
|
|
10564
10752
|
} catch {
|
|
10565
10753
|
return { result: "unavailable", current };
|
|
10566
10754
|
}
|
|
@@ -10570,14 +10758,14 @@ function checkFingerprint() {
|
|
|
10570
10758
|
}
|
|
10571
10759
|
function acceptCurrentHost() {
|
|
10572
10760
|
const current = computeCurrentFingerprint();
|
|
10573
|
-
|
|
10761
|
+
writeFileSync9(path(), JSON.stringify(current, null, 2), { mode: 384 });
|
|
10574
10762
|
return current;
|
|
10575
10763
|
}
|
|
10576
10764
|
function readHostId() {
|
|
10577
10765
|
if (process.platform === "linux") {
|
|
10578
10766
|
for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
10579
10767
|
try {
|
|
10580
|
-
const raw =
|
|
10768
|
+
const raw = readFileSync8(p, "utf8").trim();
|
|
10581
10769
|
if (raw)
|
|
10582
10770
|
return `linux:${raw}`;
|
|
10583
10771
|
} catch {}
|
|
@@ -10622,7 +10810,7 @@ var init_identity = __esm(() => {
|
|
|
10622
10810
|
});
|
|
10623
10811
|
|
|
10624
10812
|
// src/daemon/run.ts
|
|
10625
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as
|
|
10813
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9 } from "node:fs";
|
|
10626
10814
|
function detectContainer() {
|
|
10627
10815
|
if (process.env.KUBERNETES_SERVICE_HOST)
|
|
10628
10816
|
return true;
|
|
@@ -10631,7 +10819,7 @@ function detectContainer() {
|
|
|
10631
10819
|
try {
|
|
10632
10820
|
if (existsSync11("/.dockerenv"))
|
|
10633
10821
|
return true;
|
|
10634
|
-
const cg =
|
|
10822
|
+
const cg = readFileSync9("/proc/1/cgroup", "utf8");
|
|
10635
10823
|
if (/(docker|kubepods|containerd)/.test(cg))
|
|
10636
10824
|
return true;
|
|
10637
10825
|
} catch {}
|
|
@@ -10832,10 +11020,10 @@ __export(exports_service_install, {
|
|
|
10832
11020
|
installService: () => installService,
|
|
10833
11021
|
detectPlatform: () => detectPlatform
|
|
10834
11022
|
});
|
|
10835
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as
|
|
11023
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10, unlinkSync as unlinkSync5, readFileSync as readFileSync10 } from "node:fs";
|
|
10836
11024
|
import { execSync as execSync2 } from "node:child_process";
|
|
10837
11025
|
import { homedir as homedir6 } from "node:os";
|
|
10838
|
-
import { join as
|
|
11026
|
+
import { join as join9, dirname as dirname5 } from "node:path";
|
|
10839
11027
|
function detectPlatform() {
|
|
10840
11028
|
if (process.platform === "darwin")
|
|
10841
11029
|
return "darwin";
|
|
@@ -10870,7 +11058,7 @@ function uninstallService() {
|
|
|
10870
11058
|
execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL}`, { stdio: "ignore" });
|
|
10871
11059
|
} catch {}
|
|
10872
11060
|
if (existsSync12(p)) {
|
|
10873
|
-
|
|
11061
|
+
unlinkSync5(p);
|
|
10874
11062
|
removed.push(p);
|
|
10875
11063
|
}
|
|
10876
11064
|
} else if (platform5 === "linux") {
|
|
@@ -10879,14 +11067,14 @@ function uninstallService() {
|
|
|
10879
11067
|
execSync2(`systemctl --user disable --now ${SYSTEMD_UNIT}`, { stdio: "ignore" });
|
|
10880
11068
|
} catch {}
|
|
10881
11069
|
if (existsSync12(p)) {
|
|
10882
|
-
|
|
11070
|
+
unlinkSync5(p);
|
|
10883
11071
|
removed.push(p);
|
|
10884
11072
|
}
|
|
10885
11073
|
}
|
|
10886
11074
|
return { platform: platform5, removed };
|
|
10887
11075
|
}
|
|
10888
11076
|
function darwinPlistPath() {
|
|
10889
|
-
return
|
|
11077
|
+
return join9(homedir6(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
10890
11078
|
}
|
|
10891
11079
|
function installDarwin(args) {
|
|
10892
11080
|
const plist = darwinPlistPath();
|
|
@@ -10931,7 +11119,7 @@ function installDarwin(args) {
|
|
|
10931
11119
|
</dict>
|
|
10932
11120
|
</plist>
|
|
10933
11121
|
`;
|
|
10934
|
-
|
|
11122
|
+
writeFileSync10(plist, xml, { mode: 420 });
|
|
10935
11123
|
return {
|
|
10936
11124
|
platform: "darwin",
|
|
10937
11125
|
unitPath: plist,
|
|
@@ -10939,7 +11127,7 @@ function installDarwin(args) {
|
|
|
10939
11127
|
};
|
|
10940
11128
|
}
|
|
10941
11129
|
function linuxUnitPath() {
|
|
10942
|
-
return
|
|
11130
|
+
return join9(homedir6(), ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
10943
11131
|
}
|
|
10944
11132
|
function installLinux(args) {
|
|
10945
11133
|
const unit = linuxUnitPath();
|
|
@@ -10968,7 +11156,7 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
|
|
10968
11156
|
[Install]
|
|
10969
11157
|
WantedBy=default.target
|
|
10970
11158
|
`;
|
|
10971
|
-
|
|
11159
|
+
writeFileSync10(unit, content, { mode: 420 });
|
|
10972
11160
|
return {
|
|
10973
11161
|
platform: "linux",
|
|
10974
11162
|
unitPath: unit,
|
|
@@ -10991,7 +11179,7 @@ function readInstalledUnit() {
|
|
|
10991
11179
|
if (!existsSync12(path2))
|
|
10992
11180
|
return { platform: platform5, path: null, content: null };
|
|
10993
11181
|
try {
|
|
10994
|
-
return { platform: platform5, path: path2, content:
|
|
11182
|
+
return { platform: platform5, path: path2, content: readFileSync10(path2, "utf8") };
|
|
10995
11183
|
} catch {
|
|
10996
11184
|
return { platform: platform5, path: path2, content: null };
|
|
10997
11185
|
}
|
|
@@ -11319,7 +11507,7 @@ async function runStop(opts) {
|
|
|
11319
11507
|
}
|
|
11320
11508
|
var init_daemon = __esm(() => {
|
|
11321
11509
|
init_run();
|
|
11322
|
-
|
|
11510
|
+
init_client3();
|
|
11323
11511
|
init_lock();
|
|
11324
11512
|
init_paths2();
|
|
11325
11513
|
});
|
|
@@ -11335,17 +11523,17 @@ import {
|
|
|
11335
11523
|
copyFileSync,
|
|
11336
11524
|
existsSync as existsSync13,
|
|
11337
11525
|
mkdirSync as mkdirSync8,
|
|
11338
|
-
readFileSync as
|
|
11339
|
-
writeFileSync as
|
|
11526
|
+
readFileSync as readFileSync11,
|
|
11527
|
+
writeFileSync as writeFileSync11
|
|
11340
11528
|
} from "node:fs";
|
|
11341
11529
|
import { homedir as homedir7, platform as platform5 } from "node:os";
|
|
11342
|
-
import { dirname as dirname6, join as
|
|
11530
|
+
import { dirname as dirname6, join as join10, resolve } from "node:path";
|
|
11343
11531
|
import { fileURLToPath } from "node:url";
|
|
11344
11532
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
11345
11533
|
function readClaudeConfig() {
|
|
11346
11534
|
if (!existsSync13(CLAUDE_CONFIG))
|
|
11347
11535
|
return {};
|
|
11348
|
-
const text =
|
|
11536
|
+
const text = readFileSync11(CLAUDE_CONFIG, "utf-8").trim();
|
|
11349
11537
|
if (!text)
|
|
11350
11538
|
return {};
|
|
11351
11539
|
try {
|
|
@@ -11357,10 +11545,10 @@ function readClaudeConfig() {
|
|
|
11357
11545
|
function backupClaudeConfig() {
|
|
11358
11546
|
if (!existsSync13(CLAUDE_CONFIG))
|
|
11359
11547
|
return;
|
|
11360
|
-
const backupDir =
|
|
11548
|
+
const backupDir = join10(dirname6(CLAUDE_CONFIG), ".claude", "backups");
|
|
11361
11549
|
mkdirSync8(backupDir, { recursive: true });
|
|
11362
11550
|
const ts = Date.now();
|
|
11363
|
-
const dest =
|
|
11551
|
+
const dest = join10(backupDir, `.claude.json.pre-claudemesh.${ts}`);
|
|
11364
11552
|
copyFileSync(CLAUDE_CONFIG, dest);
|
|
11365
11553
|
}
|
|
11366
11554
|
function patchMcpServer(entry) {
|
|
@@ -11398,7 +11586,7 @@ function removeMcpServer() {
|
|
|
11398
11586
|
}
|
|
11399
11587
|
function flushClaudeConfig(obj) {
|
|
11400
11588
|
mkdirSync8(dirname6(CLAUDE_CONFIG), { recursive: true });
|
|
11401
|
-
|
|
11589
|
+
writeFileSync11(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
|
|
11402
11590
|
`, "utf-8");
|
|
11403
11591
|
try {
|
|
11404
11592
|
chmodSync4(CLAUDE_CONFIG, 384);
|
|
@@ -11420,7 +11608,7 @@ function resolveEntry() {
|
|
|
11420
11608
|
function resolveBundledSkillsDir() {
|
|
11421
11609
|
const here = fileURLToPath(import.meta.url);
|
|
11422
11610
|
const pkgRoot = resolve(dirname6(here), "..", "..");
|
|
11423
|
-
const skillsDir =
|
|
11611
|
+
const skillsDir = join10(pkgRoot, "skills");
|
|
11424
11612
|
if (existsSync13(skillsDir))
|
|
11425
11613
|
return skillsDir;
|
|
11426
11614
|
return null;
|
|
@@ -11434,13 +11622,13 @@ function installSkills() {
|
|
|
11434
11622
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
11435
11623
|
if (!entry.isDirectory())
|
|
11436
11624
|
continue;
|
|
11437
|
-
const srcDir =
|
|
11438
|
-
const dstDir =
|
|
11625
|
+
const srcDir = join10(src, entry.name);
|
|
11626
|
+
const dstDir = join10(CLAUDE_SKILLS_ROOT, entry.name);
|
|
11439
11627
|
mkdirSync8(dstDir, { recursive: true });
|
|
11440
11628
|
for (const file of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
11441
11629
|
if (!file.isFile())
|
|
11442
11630
|
continue;
|
|
11443
|
-
copyFileSync(
|
|
11631
|
+
copyFileSync(join10(srcDir, file.name), join10(dstDir, file.name));
|
|
11444
11632
|
}
|
|
11445
11633
|
installed.push(entry.name);
|
|
11446
11634
|
}
|
|
@@ -11455,7 +11643,7 @@ function uninstallSkills() {
|
|
|
11455
11643
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
11456
11644
|
if (!entry.isDirectory())
|
|
11457
11645
|
continue;
|
|
11458
|
-
const dstDir =
|
|
11646
|
+
const dstDir = join10(CLAUDE_SKILLS_ROOT, entry.name);
|
|
11459
11647
|
if (existsSync13(dstDir)) {
|
|
11460
11648
|
try {
|
|
11461
11649
|
fs.rmSync(dstDir, { recursive: true, force: true });
|
|
@@ -11483,7 +11671,7 @@ function entriesEqual(a, b) {
|
|
|
11483
11671
|
function readClaudeSettings() {
|
|
11484
11672
|
if (!existsSync13(CLAUDE_SETTINGS))
|
|
11485
11673
|
return {};
|
|
11486
|
-
const text =
|
|
11674
|
+
const text = readFileSync11(CLAUDE_SETTINGS, "utf-8").trim();
|
|
11487
11675
|
if (!text)
|
|
11488
11676
|
return {};
|
|
11489
11677
|
try {
|
|
@@ -11494,7 +11682,7 @@ function readClaudeSettings() {
|
|
|
11494
11682
|
}
|
|
11495
11683
|
function writeClaudeSettings(obj) {
|
|
11496
11684
|
mkdirSync8(dirname6(CLAUDE_SETTINGS), { recursive: true });
|
|
11497
|
-
|
|
11685
|
+
writeFileSync11(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
|
|
11498
11686
|
`, "utf-8");
|
|
11499
11687
|
}
|
|
11500
11688
|
function installAllowedTools() {
|
|
@@ -11644,7 +11832,7 @@ function runInstall(args = []) {
|
|
|
11644
11832
|
const installed = installSkills();
|
|
11645
11833
|
if (installed.length > 0) {
|
|
11646
11834
|
render.ok(`Claude skill${installed.length === 1 ? "" : "s"} installed`, installed.join(", "));
|
|
11647
|
-
render.info(dim(` ${
|
|
11835
|
+
render.info(dim(` ${join10(CLAUDE_SKILLS_ROOT, installed[0])}/SKILL.md`));
|
|
11648
11836
|
}
|
|
11649
11837
|
} catch (e) {
|
|
11650
11838
|
render.warn(`skill install failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -11781,9 +11969,9 @@ var init_install = __esm(() => {
|
|
|
11781
11969
|
init_facade();
|
|
11782
11970
|
init_render();
|
|
11783
11971
|
init_styles();
|
|
11784
|
-
CLAUDE_CONFIG =
|
|
11785
|
-
CLAUDE_SETTINGS =
|
|
11786
|
-
CLAUDE_SKILLS_ROOT =
|
|
11972
|
+
CLAUDE_CONFIG = join10(homedir7(), ".claude.json");
|
|
11973
|
+
CLAUDE_SETTINGS = join10(homedir7(), ".claude", "settings.json");
|
|
11974
|
+
CLAUDE_SKILLS_ROOT = join10(homedir7(), ".claude", "skills");
|
|
11787
11975
|
CLAUDEMESH_TOOLS = [
|
|
11788
11976
|
"mcp__claudemesh__cancel_scheduled",
|
|
11789
11977
|
"mcp__claudemesh__check_messages",
|
|
@@ -11838,26 +12026,26 @@ var exports_uninstall = {};
|
|
|
11838
12026
|
__export(exports_uninstall, {
|
|
11839
12027
|
uninstall: () => uninstall
|
|
11840
12028
|
});
|
|
11841
|
-
import { readFileSync as
|
|
11842
|
-
import { join as
|
|
12029
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync12, existsSync as existsSync14, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
|
|
12030
|
+
import { join as join11, dirname as dirname7 } from "node:path";
|
|
11843
12031
|
import { homedir as homedir8 } from "node:os";
|
|
11844
12032
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
11845
12033
|
function bundledSkillsDir() {
|
|
11846
12034
|
const here = fileURLToPath2(import.meta.url);
|
|
11847
|
-
const pkgRoot =
|
|
11848
|
-
const skillsDir =
|
|
12035
|
+
const pkgRoot = join11(dirname7(here), "..", "..");
|
|
12036
|
+
const skillsDir = join11(pkgRoot, "skills");
|
|
11849
12037
|
return existsSync14(skillsDir) ? skillsDir : null;
|
|
11850
12038
|
}
|
|
11851
12039
|
async function uninstall() {
|
|
11852
12040
|
let removed = 0;
|
|
11853
12041
|
if (existsSync14(PATHS.CLAUDE_JSON)) {
|
|
11854
12042
|
try {
|
|
11855
|
-
const raw =
|
|
12043
|
+
const raw = readFileSync12(PATHS.CLAUDE_JSON, "utf-8");
|
|
11856
12044
|
const config = JSON.parse(raw);
|
|
11857
12045
|
const servers = config.mcpServers;
|
|
11858
12046
|
if (servers && "claudemesh" in servers) {
|
|
11859
12047
|
delete servers.claudemesh;
|
|
11860
|
-
|
|
12048
|
+
writeFileSync12(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
|
|
11861
12049
|
`, "utf-8");
|
|
11862
12050
|
render.ok("removed MCP server", dim("~/.claude.json"));
|
|
11863
12051
|
removed++;
|
|
@@ -11866,7 +12054,7 @@ async function uninstall() {
|
|
|
11866
12054
|
}
|
|
11867
12055
|
if (existsSync14(PATHS.CLAUDE_SETTINGS)) {
|
|
11868
12056
|
try {
|
|
11869
|
-
const raw =
|
|
12057
|
+
const raw = readFileSync12(PATHS.CLAUDE_SETTINGS, "utf-8");
|
|
11870
12058
|
const config = JSON.parse(raw);
|
|
11871
12059
|
const hooks = config.hooks;
|
|
11872
12060
|
if (hooks) {
|
|
@@ -11887,7 +12075,7 @@ async function uninstall() {
|
|
|
11887
12075
|
}
|
|
11888
12076
|
}
|
|
11889
12077
|
if (removedHooks > 0) {
|
|
11890
|
-
|
|
12078
|
+
writeFileSync12(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
|
|
11891
12079
|
`, "utf-8");
|
|
11892
12080
|
render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
|
|
11893
12081
|
removed++;
|
|
@@ -11902,7 +12090,7 @@ async function uninstall() {
|
|
|
11902
12090
|
for (const entry of readdirSync2(src, { withFileTypes: true })) {
|
|
11903
12091
|
if (!entry.isDirectory())
|
|
11904
12092
|
continue;
|
|
11905
|
-
const dst =
|
|
12093
|
+
const dst = join11(CLAUDE_SKILLS_ROOT2, entry.name);
|
|
11906
12094
|
if (existsSync14(dst)) {
|
|
11907
12095
|
try {
|
|
11908
12096
|
rmSync2(dst, { recursive: true, force: true });
|
|
@@ -11927,7 +12115,7 @@ var init_uninstall = __esm(() => {
|
|
|
11927
12115
|
init_render();
|
|
11928
12116
|
init_styles();
|
|
11929
12117
|
init_exit_codes();
|
|
11930
|
-
CLAUDE_SKILLS_ROOT2 =
|
|
12118
|
+
CLAUDE_SKILLS_ROOT2 = join11(homedir8(), ".claude", "skills");
|
|
11931
12119
|
});
|
|
11932
12120
|
|
|
11933
12121
|
// src/commands/doctor.ts
|
|
@@ -11935,9 +12123,9 @@ var exports_doctor = {};
|
|
|
11935
12123
|
__export(exports_doctor, {
|
|
11936
12124
|
runDoctor: () => runDoctor
|
|
11937
12125
|
});
|
|
11938
|
-
import { existsSync as existsSync15, readFileSync as
|
|
12126
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13, statSync as statSync3 } from "node:fs";
|
|
11939
12127
|
import { homedir as homedir9, platform as platform6 } from "node:os";
|
|
11940
|
-
import { join as
|
|
12128
|
+
import { join as join12 } from "node:path";
|
|
11941
12129
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
11942
12130
|
function checkNode() {
|
|
11943
12131
|
const major = Number(process.versions.node.split(".")[0]);
|
|
@@ -11961,7 +12149,7 @@ function checkClaudeOnPath() {
|
|
|
11961
12149
|
};
|
|
11962
12150
|
}
|
|
11963
12151
|
function checkMcpRegistered() {
|
|
11964
|
-
const claudeConfig =
|
|
12152
|
+
const claudeConfig = join12(homedir9(), ".claude.json");
|
|
11965
12153
|
if (!existsSync15(claudeConfig)) {
|
|
11966
12154
|
return {
|
|
11967
12155
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
@@ -11970,7 +12158,7 @@ function checkMcpRegistered() {
|
|
|
11970
12158
|
};
|
|
11971
12159
|
}
|
|
11972
12160
|
try {
|
|
11973
|
-
const cfg = JSON.parse(
|
|
12161
|
+
const cfg = JSON.parse(readFileSync13(claudeConfig, "utf-8"));
|
|
11974
12162
|
const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
|
|
11975
12163
|
return {
|
|
11976
12164
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
@@ -11987,7 +12175,7 @@ function checkMcpRegistered() {
|
|
|
11987
12175
|
}
|
|
11988
12176
|
}
|
|
11989
12177
|
function checkHooksRegistered() {
|
|
11990
|
-
const settings =
|
|
12178
|
+
const settings = join12(homedir9(), ".claude", "settings.json");
|
|
11991
12179
|
if (!existsSync15(settings)) {
|
|
11992
12180
|
return {
|
|
11993
12181
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
@@ -11996,7 +12184,7 @@ function checkHooksRegistered() {
|
|
|
11996
12184
|
};
|
|
11997
12185
|
}
|
|
11998
12186
|
try {
|
|
11999
|
-
const raw =
|
|
12187
|
+
const raw = readFileSync13(settings, "utf-8");
|
|
12000
12188
|
const has = raw.includes("claudemesh hook ");
|
|
12001
12189
|
return {
|
|
12002
12190
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
@@ -12022,7 +12210,7 @@ function checkConfigFile() {
|
|
|
12022
12210
|
}
|
|
12023
12211
|
try {
|
|
12024
12212
|
readConfig();
|
|
12025
|
-
const st =
|
|
12213
|
+
const st = statSync3(path2);
|
|
12026
12214
|
const mode = (st.mode & 511).toString(8);
|
|
12027
12215
|
const secure = platform6() === "win32" || mode === "600";
|
|
12028
12216
|
return {
|
|
@@ -12196,7 +12384,7 @@ var exports_status = {};
|
|
|
12196
12384
|
__export(exports_status, {
|
|
12197
12385
|
runStatus: () => runStatus2
|
|
12198
12386
|
});
|
|
12199
|
-
import { statSync as
|
|
12387
|
+
import { statSync as statSync4, existsSync as existsSync16 } from "node:fs";
|
|
12200
12388
|
import WebSocket3 from "ws";
|
|
12201
12389
|
async function probeBroker(url, timeoutMs = 4000) {
|
|
12202
12390
|
return new Promise((resolve2) => {
|
|
@@ -12227,7 +12415,7 @@ async function runStatus2() {
|
|
|
12227
12415
|
const configPath = getConfigPath();
|
|
12228
12416
|
let configPermsNote = "missing";
|
|
12229
12417
|
if (existsSync16(configPath)) {
|
|
12230
|
-
const mode = (
|
|
12418
|
+
const mode = (statSync4(configPath).mode & 511).toString(8).padStart(4, "0");
|
|
12231
12419
|
configPermsNote = mode === "0600" ? `${mode}` : `${mode} — expected 0600`;
|
|
12232
12420
|
}
|
|
12233
12421
|
render.kv([["config", configPath], ["perms", configPermsNote]]);
|
|
@@ -12372,13 +12560,13 @@ var init_check_claude_binary = __esm(() => {
|
|
|
12372
12560
|
});
|
|
12373
12561
|
|
|
12374
12562
|
// src/services/health/check-mcp-registered.ts
|
|
12375
|
-
import { existsSync as existsSync17, readFileSync as
|
|
12563
|
+
import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
|
|
12376
12564
|
function checkMcpRegistered2() {
|
|
12377
12565
|
try {
|
|
12378
12566
|
if (!existsSync17(PATHS.CLAUDE_JSON)) {
|
|
12379
12567
|
return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
|
|
12380
12568
|
}
|
|
12381
|
-
const raw =
|
|
12569
|
+
const raw = readFileSync14(PATHS.CLAUDE_JSON, "utf-8");
|
|
12382
12570
|
const config = JSON.parse(raw);
|
|
12383
12571
|
if (config.mcpServers && "claudemesh" in config.mcpServers) {
|
|
12384
12572
|
return { name: "mcp-registered", ok: true, message: "MCP server registered" };
|
|
@@ -12393,13 +12581,13 @@ var init_check_mcp_registered = __esm(() => {
|
|
|
12393
12581
|
});
|
|
12394
12582
|
|
|
12395
12583
|
// src/services/health/check-hooks-registered.ts
|
|
12396
|
-
import { existsSync as existsSync18, readFileSync as
|
|
12584
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
|
|
12397
12585
|
function checkHooksRegistered2() {
|
|
12398
12586
|
try {
|
|
12399
12587
|
if (!existsSync18(PATHS.CLAUDE_SETTINGS)) {
|
|
12400
12588
|
return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
|
|
12401
12589
|
}
|
|
12402
|
-
const raw =
|
|
12590
|
+
const raw = readFileSync15(PATHS.CLAUDE_SETTINGS, "utf-8");
|
|
12403
12591
|
const config = JSON.parse(raw);
|
|
12404
12592
|
if (config.hooks) {
|
|
12405
12593
|
return { name: "hooks-registered", ok: true, message: "Hooks configured" };
|
|
@@ -12414,14 +12602,14 @@ var init_check_hooks_registered = __esm(() => {
|
|
|
12414
12602
|
});
|
|
12415
12603
|
|
|
12416
12604
|
// src/services/health/check-config-perms.ts
|
|
12417
|
-
import { existsSync as existsSync19, statSync as
|
|
12605
|
+
import { existsSync as existsSync19, statSync as statSync5 } from "node:fs";
|
|
12418
12606
|
function checkConfigPerms() {
|
|
12419
12607
|
const configFile = PATHS.CONFIG_FILE;
|
|
12420
12608
|
if (!existsSync19(configFile)) {
|
|
12421
12609
|
return { name: "config-perms", ok: true, message: "No config file yet (first run)" };
|
|
12422
12610
|
}
|
|
12423
12611
|
try {
|
|
12424
|
-
const mode =
|
|
12612
|
+
const mode = statSync5(configFile).mode & 511;
|
|
12425
12613
|
if (mode <= 384) {
|
|
12426
12614
|
return { name: "config-perms", ok: true, message: `config.json mode ${mode.toString(8)}` };
|
|
12427
12615
|
}
|
|
@@ -12435,13 +12623,13 @@ var init_check_config_perms = __esm(() => {
|
|
|
12435
12623
|
});
|
|
12436
12624
|
|
|
12437
12625
|
// src/services/health/check-keypairs-valid.ts
|
|
12438
|
-
import { existsSync as existsSync20, readFileSync as
|
|
12626
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
|
|
12439
12627
|
function checkKeypairsValid() {
|
|
12440
12628
|
if (!existsSync20(PATHS.CONFIG_FILE)) {
|
|
12441
12629
|
return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
|
|
12442
12630
|
}
|
|
12443
12631
|
try {
|
|
12444
|
-
const raw =
|
|
12632
|
+
const raw = readFileSync16(PATHS.CONFIG_FILE, "utf-8");
|
|
12445
12633
|
const config = JSON.parse(raw);
|
|
12446
12634
|
const meshes = config.meshes ?? [];
|
|
12447
12635
|
if (meshes.length === 0) {
|
|
@@ -12922,17 +13110,17 @@ __export(exports_url_handler, {
|
|
|
12922
13110
|
runUrlHandler: () => runUrlHandler
|
|
12923
13111
|
});
|
|
12924
13112
|
import { platform as platform7, homedir as homedir10 } from "node:os";
|
|
12925
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as
|
|
12926
|
-
import { join as
|
|
13113
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync13, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
|
|
13114
|
+
import { join as join13 } from "node:path";
|
|
12927
13115
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
12928
13116
|
function resolveClaudemeshBin() {
|
|
12929
13117
|
return process.argv[1] ?? "claudemesh";
|
|
12930
13118
|
}
|
|
12931
13119
|
function installDarwin2() {
|
|
12932
13120
|
const binPath = resolveClaudemeshBin();
|
|
12933
|
-
const appDir =
|
|
12934
|
-
const contents =
|
|
12935
|
-
const macOS =
|
|
13121
|
+
const appDir = join13(homedir10(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
|
|
13122
|
+
const contents = join13(appDir, "Contents");
|
|
13123
|
+
const macOS = join13(contents, "MacOS");
|
|
12936
13124
|
mkdirSync9(macOS, { recursive: true });
|
|
12937
13125
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
12938
13126
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -12956,7 +13144,7 @@ function installDarwin2() {
|
|
|
12956
13144
|
</array>
|
|
12957
13145
|
</dict>
|
|
12958
13146
|
</plist>`;
|
|
12959
|
-
|
|
13147
|
+
writeFileSync13(join13(contents, "Info.plist"), plist);
|
|
12960
13148
|
const shim = `#!/bin/sh
|
|
12961
13149
|
URL="$1"
|
|
12962
13150
|
CODE=\${URL#claudemesh://}
|
|
@@ -12970,8 +13158,8 @@ tell application "Terminal"
|
|
|
12970
13158
|
end tell
|
|
12971
13159
|
EOF
|
|
12972
13160
|
`;
|
|
12973
|
-
const shimPath =
|
|
12974
|
-
|
|
13161
|
+
const shimPath = join13(macOS, "open-url");
|
|
13162
|
+
writeFileSync13(shimPath, shim);
|
|
12975
13163
|
chmodSync5(shimPath, 493);
|
|
12976
13164
|
const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
|
|
12977
13165
|
if (lsreg.status !== 0) {
|
|
@@ -12982,7 +13170,7 @@ EOF
|
|
|
12982
13170
|
}
|
|
12983
13171
|
function installLinux2() {
|
|
12984
13172
|
const binPath = resolveClaudemeshBin();
|
|
12985
|
-
const appsDir =
|
|
13173
|
+
const appsDir = join13(homedir10(), ".local", "share", "applications");
|
|
12986
13174
|
mkdirSync9(appsDir, { recursive: true });
|
|
12987
13175
|
const desktop = `[Desktop Entry]
|
|
12988
13176
|
Type=Application
|
|
@@ -12994,8 +13182,8 @@ Terminal=true
|
|
|
12994
13182
|
MimeType=x-scheme-handler/claudemesh;
|
|
12995
13183
|
NoDisplay=true
|
|
12996
13184
|
`;
|
|
12997
|
-
const desktopPath =
|
|
12998
|
-
|
|
13185
|
+
const desktopPath = join13(appsDir, "claudemesh.desktop");
|
|
13186
|
+
writeFileSync13(desktopPath, desktop);
|
|
12999
13187
|
const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
|
|
13000
13188
|
if (xdg1.status !== 0) {
|
|
13001
13189
|
render.warn("xdg-mime not available — skipped mime default registration");
|
|
@@ -13017,8 +13205,8 @@ function installWindows() {
|
|
|
13017
13205
|
`[HKEY_CURRENT_USER\\Software\\Classes\\claudemesh\\shell\\open\\command]`,
|
|
13018
13206
|
`@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
|
|
13019
13207
|
];
|
|
13020
|
-
const regPath =
|
|
13021
|
-
|
|
13208
|
+
const regPath = join13(homedir10(), "claudemesh-handler.reg");
|
|
13209
|
+
writeFileSync13(regPath, lines.join(`\r
|
|
13022
13210
|
`));
|
|
13023
13211
|
const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
|
|
13024
13212
|
if (res.status !== 0) {
|
|
@@ -13029,14 +13217,14 @@ function installWindows() {
|
|
|
13029
13217
|
return EXIT.SUCCESS;
|
|
13030
13218
|
}
|
|
13031
13219
|
function uninstallDarwin() {
|
|
13032
|
-
const appDir =
|
|
13220
|
+
const appDir = join13(homedir10(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
|
|
13033
13221
|
if (existsSync21(appDir))
|
|
13034
13222
|
rmSync3(appDir, { recursive: true, force: true });
|
|
13035
13223
|
render.ok("removed claudemesh:// handler on macOS");
|
|
13036
13224
|
return EXIT.SUCCESS;
|
|
13037
13225
|
}
|
|
13038
13226
|
function uninstallLinux() {
|
|
13039
|
-
const desktopPath =
|
|
13227
|
+
const desktopPath = join13(homedir10(), ".local", "share", "applications", "claudemesh.desktop");
|
|
13040
13228
|
if (existsSync21(desktopPath))
|
|
13041
13229
|
rmSync3(desktopPath, { force: true });
|
|
13042
13230
|
render.ok("removed claudemesh:// handler on Linux");
|
|
@@ -13082,8 +13270,8 @@ var exports_status_line = {};
|
|
|
13082
13270
|
__export(exports_status_line, {
|
|
13083
13271
|
runStatusLine: () => runStatusLine
|
|
13084
13272
|
});
|
|
13085
|
-
import { existsSync as existsSync22, readFileSync as
|
|
13086
|
-
import { join as
|
|
13273
|
+
import { existsSync as existsSync22, readFileSync as readFileSync17 } from "node:fs";
|
|
13274
|
+
import { join as join14 } from "node:path";
|
|
13087
13275
|
import { homedir as homedir11 } from "node:os";
|
|
13088
13276
|
async function runStatusLine() {
|
|
13089
13277
|
try {
|
|
@@ -13092,11 +13280,11 @@ async function runStatusLine() {
|
|
|
13092
13280
|
process.stdout.write("◇ claudemesh (not joined)");
|
|
13093
13281
|
return EXIT.SUCCESS;
|
|
13094
13282
|
}
|
|
13095
|
-
const cachePath =
|
|
13283
|
+
const cachePath = join14(homedir11(), ".claudemesh", "peer-cache.json");
|
|
13096
13284
|
let cache = {};
|
|
13097
13285
|
if (existsSync22(cachePath)) {
|
|
13098
13286
|
try {
|
|
13099
|
-
cache = JSON.parse(
|
|
13287
|
+
cache = JSON.parse(readFileSync17(cachePath, "utf-8"));
|
|
13100
13288
|
} catch {}
|
|
13101
13289
|
}
|
|
13102
13290
|
const pick = config.meshes[0];
|
|
@@ -13127,7 +13315,7 @@ __export(exports_backup, {
|
|
|
13127
13315
|
runRestore: () => runRestore,
|
|
13128
13316
|
runBackup: () => runBackup
|
|
13129
13317
|
});
|
|
13130
|
-
import { readFileSync as
|
|
13318
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, existsSync as existsSync23 } from "node:fs";
|
|
13131
13319
|
import { createInterface as createInterface11 } from "node:readline";
|
|
13132
13320
|
function readHidden(prompt5) {
|
|
13133
13321
|
return new Promise((resolve2) => {
|
|
@@ -13173,7 +13361,7 @@ async function runBackup(outPath) {
|
|
|
13173
13361
|
console.error(" No config found — nothing to back up. Join a mesh first.");
|
|
13174
13362
|
return EXIT.NOT_FOUND;
|
|
13175
13363
|
}
|
|
13176
|
-
const plaintext =
|
|
13364
|
+
const plaintext = readFileSync18(configPath);
|
|
13177
13365
|
const pass = await readHidden(" Passphrase (min 12 chars): ");
|
|
13178
13366
|
if (pass.length < 12) {
|
|
13179
13367
|
console.error(" ✗ Passphrase too short.");
|
|
@@ -13191,7 +13379,7 @@ async function runBackup(outPath) {
|
|
|
13191
13379
|
const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
|
|
13192
13380
|
const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
|
|
13193
13381
|
const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
|
|
13194
|
-
|
|
13382
|
+
writeFileSync14(file, blob, { mode: 384 });
|
|
13195
13383
|
console.log(`
|
|
13196
13384
|
✓ Backup saved: ${file}`);
|
|
13197
13385
|
console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
|
|
@@ -13207,7 +13395,7 @@ async function runRestore(inPath) {
|
|
|
13207
13395
|
console.error(` ✗ File not found: ${inPath}`);
|
|
13208
13396
|
return EXIT.NOT_FOUND;
|
|
13209
13397
|
}
|
|
13210
|
-
const blob =
|
|
13398
|
+
const blob = readFileSync18(inPath);
|
|
13211
13399
|
if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
|
|
13212
13400
|
console.error(" ✗ Not a claudemesh backup file (bad magic).");
|
|
13213
13401
|
return EXIT.INVALID_ARGS;
|
|
@@ -13228,10 +13416,10 @@ async function runRestore(inPath) {
|
|
|
13228
13416
|
const configPath = getConfigPath();
|
|
13229
13417
|
if (existsSync23(configPath)) {
|
|
13230
13418
|
const backupOld = `${configPath}.before-restore.${Date.now()}`;
|
|
13231
|
-
|
|
13419
|
+
writeFileSync14(backupOld, readFileSync18(configPath), { mode: 384 });
|
|
13232
13420
|
console.log(` ↻ Existing config saved to ${backupOld}`);
|
|
13233
13421
|
}
|
|
13234
|
-
|
|
13422
|
+
writeFileSync14(configPath, Buffer.from(plaintext), { mode: 384 });
|
|
13235
13423
|
console.log(`
|
|
13236
13424
|
✓ Config restored to ${configPath}`);
|
|
13237
13425
|
console.log(" Run `claudemesh list` to verify your meshes.\n");
|
|
@@ -13252,7 +13440,7 @@ __export(exports_upgrade, {
|
|
|
13252
13440
|
});
|
|
13253
13441
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
13254
13442
|
import { existsSync as existsSync24 } from "node:fs";
|
|
13255
|
-
import { dirname as dirname8, join as
|
|
13443
|
+
import { dirname as dirname8, join as join15, resolve as resolve2 } from "node:path";
|
|
13256
13444
|
async function latestVersion() {
|
|
13257
13445
|
try {
|
|
13258
13446
|
const res = await fetch(URLS.NPM_REGISTRY, { signal: AbortSignal.timeout(8000) });
|
|
@@ -13265,14 +13453,14 @@ async function latestVersion() {
|
|
|
13265
13453
|
}
|
|
13266
13454
|
}
|
|
13267
13455
|
function findNpm() {
|
|
13268
|
-
const portable =
|
|
13456
|
+
const portable = join15(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
|
|
13269
13457
|
if (existsSync24(portable)) {
|
|
13270
|
-
return { npm: portable, prefix:
|
|
13458
|
+
return { npm: portable, prefix: join15(process.env.HOME ?? "", ".claudemesh") };
|
|
13271
13459
|
}
|
|
13272
13460
|
let cur = resolve2(process.argv[1] ?? ".");
|
|
13273
13461
|
for (let i = 0;i < 6; i++) {
|
|
13274
13462
|
cur = dirname8(cur);
|
|
13275
|
-
const candidate =
|
|
13463
|
+
const candidate = join15(cur, "bin", "npm");
|
|
13276
13464
|
if (existsSync24(candidate))
|
|
13277
13465
|
return { npm: candidate };
|
|
13278
13466
|
}
|
|
@@ -13335,9 +13523,9 @@ __export(exports_grants, {
|
|
|
13335
13523
|
runBlock: () => runBlock,
|
|
13336
13524
|
isAllowed: () => isAllowed
|
|
13337
13525
|
});
|
|
13338
|
-
import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as
|
|
13526
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync15 } from "node:fs";
|
|
13339
13527
|
import { homedir as homedir12 } from "node:os";
|
|
13340
|
-
import { join as
|
|
13528
|
+
import { join as join16 } from "node:path";
|
|
13341
13529
|
async function syncToBroker(meshSlug, grants) {
|
|
13342
13530
|
const auth = getStoredToken();
|
|
13343
13531
|
if (!auth)
|
|
@@ -13358,16 +13546,16 @@ function readGrants() {
|
|
|
13358
13546
|
if (!existsSync25(GRANT_FILE))
|
|
13359
13547
|
return {};
|
|
13360
13548
|
try {
|
|
13361
|
-
return JSON.parse(
|
|
13549
|
+
return JSON.parse(readFileSync19(GRANT_FILE, "utf-8"));
|
|
13362
13550
|
} catch {
|
|
13363
13551
|
return {};
|
|
13364
13552
|
}
|
|
13365
13553
|
}
|
|
13366
13554
|
function writeGrants(g) {
|
|
13367
|
-
const dir =
|
|
13555
|
+
const dir = join16(homedir12(), ".claudemesh");
|
|
13368
13556
|
if (!existsSync25(dir))
|
|
13369
13557
|
mkdirSync10(dir, { recursive: true });
|
|
13370
|
-
|
|
13558
|
+
writeFileSync15(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
|
|
13371
13559
|
}
|
|
13372
13560
|
function resolveCaps(input) {
|
|
13373
13561
|
if (input.includes("all"))
|
|
@@ -13523,7 +13711,7 @@ var init_grants = __esm(() => {
|
|
|
13523
13711
|
BROKER_HTTP7 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
13524
13712
|
ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
|
|
13525
13713
|
DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
|
|
13526
|
-
GRANT_FILE =
|
|
13714
|
+
GRANT_FILE = join16(homedir12(), ".claudemesh", "grants.json");
|
|
13527
13715
|
});
|
|
13528
13716
|
|
|
13529
13717
|
// src/commands/profile.ts
|
|
@@ -14595,15 +14783,56 @@ Once \`claudemesh install\` has run (registers MCP entry + starts daemon service
|
|
|
14595
14783
|
| \`--groups "name:role,name2:role2,all"\` | the group selection prompt | comma-separated \`<groupname>:<role>\` entries; the literal \`all\` joins \`@all\` |
|
|
14596
14784
|
| \`--role <lead\\|member\\|observer>\` | the role prompt | applied to all groups in \`--groups\` that didn't specify their own |
|
|
14597
14785
|
| \`--message-mode <push\\|inbox>\` | the message-mode prompt | \`push\` (default) emits \`<channel>\` notifications mid-turn; \`inbox\` only buffers — quieter for headless agents |
|
|
14598
|
-
| \`--system-prompt <
|
|
14786
|
+
| \`--system-prompt <text>\` | nothing — pure pass-through | forwarded to \`claude --system-prompt\` (overrides default; pass a string, not a path) |
|
|
14599
14787
|
| \`--resume <session-id>\` | nothing — pure pass-through | forwarded to \`claude --resume\` to continue a prior Claude Code session |
|
|
14600
|
-
| \`--continue\` | nothing — pure pass-through | forwarded to \`claude --continue\` |
|
|
14788
|
+
| \`--continue\` | nothing — pure pass-through | forwarded to \`claude --continue\` (resumes the last session in this cwd) |
|
|
14601
14789
|
| \`-y\` / \`--yes\` | every confirmation prompt | including the "you'll skip ALL permission prompts" gate. **Use for autonomous agents; omit for shared/multi-person meshes.** |
|
|
14602
|
-
|
|
|
14790
|
+
| \`--quiet\` | the wizard + welcome banner | suppresses the launch wizard and banner. Combine with \`-y\` for true headless: \`--quiet\` alone won't bypass Claude's permission prompts, so a script using only \`--quiet\` will hang on the first tool call. |
|
|
14603
14791
|
| \`--\` | (separator) | everything after \`--\` is forwarded verbatim to \`claude\`. Example: \`claudemesh launch --name X -y -- --resume abc123 --model opus\` |
|
|
14604
14792
|
|
|
14793
|
+
> **All twelve flags are end-to-end wired as of \`claudemesh-cli@1.27.1\`.** Earlier builds silently dropped \`--role\`, \`--groups\`, \`--message-mode\`, \`--system-prompt\`, \`--continue\`, and \`--quiet\` at the CLI entrypoint — they were declared but never reached \`runLaunch\`. If a script targets older versions, those flags are no-ops.
|
|
14794
|
+
|
|
14605
14795
|
### Wizard-free spawn templates
|
|
14606
14796
|
|
|
14797
|
+
#### Canonical fully-populated spawn (every flag set explicitly)
|
|
14798
|
+
|
|
14799
|
+
The kitchen-sink form — copy, set every value, and the session boots without a single interactive prompt or banner. Use as a base when scripting from cron, hooks, CI, or another agent:
|
|
14800
|
+
|
|
14801
|
+
\`\`\`bash
|
|
14802
|
+
claudemesh launch \\
|
|
14803
|
+
--name "ci-bot" \\
|
|
14804
|
+
--mesh openclaw \\
|
|
14805
|
+
--role member \\
|
|
14806
|
+
--groups "frontend:lead,reviewers:observer,all" \\
|
|
14807
|
+
--message-mode inbox \\
|
|
14808
|
+
--system-prompt "$(cat ~/agents/ci-bot.md)" \\
|
|
14809
|
+
--quiet \\
|
|
14810
|
+
-y \\
|
|
14811
|
+
-- \\
|
|
14812
|
+
--model opus \\
|
|
14813
|
+
--resume "$LAST_SESSION_ID"
|
|
14814
|
+
\`\`\`
|
|
14815
|
+
|
|
14816
|
+
Annotated:
|
|
14817
|
+
|
|
14818
|
+
| Position | Value | Effect |
|
|
14819
|
+
|---|---|---|
|
|
14820
|
+
| \`--name "ci-bot"\` | identity | what peers see in \`peer list\` and \`<channel from_name>\` — pin so peers always see the same name across machines |
|
|
14821
|
+
| \`--mesh openclaw\` | workspace | required when you have ≥2 joined meshes; safe to include even with 1 (becomes a no-op assertion) |
|
|
14822
|
+
| \`--role member\` | session label | free-form tag used by group conventions; common values: \`lead\`, \`member\`, \`observer\`, \`bot\`, \`oncall\` |
|
|
14823
|
+
| \`--groups "frontend:lead,..."\` | group memberships | comma-separated \`<group>:<role>\` pairs; bare \`all\` joins \`@all\` with no role |
|
|
14824
|
+
| \`--message-mode inbox\` | delivery | \`push\` interrupts mid-turn (default); \`inbox\` buffers silently; \`off\` disables messages but keeps tool calls |
|
|
14825
|
+
| \`--system-prompt "..."\` | claude system prompt | overrides Claude's default. Pass a string, not a path — wrap with \`$(cat …)\` if you keep prompts in files |
|
|
14826
|
+
| \`--quiet\` | output | suppress the wizard and banner — clean stdout for the spawning script |
|
|
14827
|
+
| \`-y\` | consent | skips every permission prompt (claudemesh's policy gate **and** Claude's \`--dangerously-skip-permissions\`). Required for true headless |
|
|
14828
|
+
| \`--\` | separator | everything after is passed verbatim to \`claude\` |
|
|
14829
|
+
| \`--model opus\` | claude flag | example claude-side override |
|
|
14830
|
+
| \`--resume "$LAST_SESSION_ID"\` | claude flag | resume a prior Claude session inside this mesh identity |
|
|
14831
|
+
|
|
14832
|
+
**Rule of thumb:** for any unattended spawn, the minimum is \`--name + --mesh + -y + --quiet\`. Add \`--system-prompt\` to seed task context, \`--message-mode inbox\` to keep the bot quiet, and \`--role\` + \`--groups\` so peers know how to address it. Drop \`--quiet\` when a human is watching the script's stdout.
|
|
14833
|
+
|
|
14834
|
+
#### Trimmed templates
|
|
14835
|
+
|
|
14607
14836
|
\`\`\`bash
|
|
14608
14837
|
# Minimal — single joined mesh, fresh agent, autonomous:
|
|
14609
14838
|
claudemesh launch --name "Lug Nut" -y
|
|
@@ -14624,9 +14853,9 @@ claudemesh launch --name "Mou" --mesh openclaw -y -- --resume abc123-...
|
|
|
14624
14853
|
|
|
14625
14854
|
# Quiet, headless, system-prompt loaded — for cron / hooks:
|
|
14626
14855
|
claudemesh launch --name "ci-bot" --mesh openclaw \\
|
|
14627
|
-
--system-prompt /
|
|
14856
|
+
--system-prompt "$(cat ~/agents/ci-bot.md)" \\
|
|
14628
14857
|
--message-mode inbox \\
|
|
14629
|
-
|
|
14858
|
+
--quiet -y
|
|
14630
14859
|
\`\`\`
|
|
14631
14860
|
|
|
14632
14861
|
If any required flag is missing AND stdin is a TTY, \`launch\` falls back to its prompt for that single field. **In a non-TTY context (Bash tool, cron, AppleScript pipe), missing flags cause the verb to fail-closed — never silently use a default that affects identity.**
|
|
@@ -15164,7 +15393,7 @@ __export(exports_file, {
|
|
|
15164
15393
|
});
|
|
15165
15394
|
import { hostname as osHostname } from "node:os";
|
|
15166
15395
|
import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
|
|
15167
|
-
import { statSync as
|
|
15396
|
+
import { statSync as statSync7, existsSync as existsSync26, writeFileSync as writeFileSync16, mkdirSync as mkdirSync11 } from "node:fs";
|
|
15168
15397
|
function emitJson2(data) {
|
|
15169
15398
|
console.log(JSON.stringify(data, null, 2));
|
|
15170
15399
|
}
|
|
@@ -15185,7 +15414,7 @@ async function runFileShare(filePath, opts) {
|
|
|
15185
15414
|
render.err(`File not found: ${absPath}`);
|
|
15186
15415
|
return EXIT.INVALID_ARGS;
|
|
15187
15416
|
}
|
|
15188
|
-
const stat =
|
|
15417
|
+
const stat = statSync7(absPath);
|
|
15189
15418
|
if (!stat.isFile()) {
|
|
15190
15419
|
render.err(`Not a regular file: ${absPath}`);
|
|
15191
15420
|
return EXIT.INVALID_ARGS;
|
|
@@ -15261,7 +15490,7 @@ async function runFileGet(fileId, opts) {
|
|
|
15261
15490
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
15262
15491
|
const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
|
|
15263
15492
|
mkdirSync11(dirname9(outPath), { recursive: true });
|
|
15264
|
-
|
|
15493
|
+
writeFileSync16(outPath, buf);
|
|
15265
15494
|
if (opts.json) {
|
|
15266
15495
|
emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
|
|
15267
15496
|
} else {
|
|
@@ -15871,7 +16100,7 @@ __export(exports_bridge, {
|
|
|
15871
16100
|
runBridge: () => runBridge,
|
|
15872
16101
|
bridgeConfigTemplate: () => bridgeConfigTemplate
|
|
15873
16102
|
});
|
|
15874
|
-
import { readFileSync as
|
|
16103
|
+
import { readFileSync as readFileSync20, existsSync as existsSync27 } from "node:fs";
|
|
15875
16104
|
function parseConfig(text) {
|
|
15876
16105
|
const trimmed = text.trim();
|
|
15877
16106
|
if (trimmed.startsWith("{"))
|
|
@@ -15921,7 +16150,7 @@ async function runBridge(configPath) {
|
|
|
15921
16150
|
}
|
|
15922
16151
|
let cfg;
|
|
15923
16152
|
try {
|
|
15924
|
-
cfg = parseConfig(
|
|
16153
|
+
cfg = parseConfig(readFileSync20(configPath, "utf-8"));
|
|
15925
16154
|
} catch (e) {
|
|
15926
16155
|
render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15927
16156
|
return EXIT.INVALID_ARGS;
|
|
@@ -19197,4 +19426,4 @@ main().catch((err) => {
|
|
|
19197
19426
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
19198
19427
|
});
|
|
19199
19428
|
|
|
19200
|
-
//# debugId=
|
|
19429
|
+
//# debugId=1F2A51E3A3AE432A64756E2164756E21
|