claudemesh-cli 1.28.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entrypoints/cli.js +770 -188
- package/dist/entrypoints/cli.js.map +17 -12
- package/dist/entrypoints/mcp.js +2 -2
- package/dist/entrypoints/mcp.js.map +2 -2
- package/package.json +1 -1
package/dist/entrypoints/cli.js
CHANGED
|
@@ -92,7 +92,8 @@ var init_exit_codes = __esm(() => {
|
|
|
92
92
|
ALREADY_EXISTS: 6,
|
|
93
93
|
PERMISSION_DENIED: 7,
|
|
94
94
|
INTERNAL_ERROR: 8,
|
|
95
|
-
CLAUDE_MISSING: 9
|
|
95
|
+
CLAUDE_MISSING: 9,
|
|
96
|
+
IO_ERROR: 10
|
|
96
97
|
};
|
|
97
98
|
});
|
|
98
99
|
|
|
@@ -103,7 +104,7 @@ __export(exports_urls, {
|
|
|
103
104
|
VERSION: () => VERSION,
|
|
104
105
|
URLS: () => URLS
|
|
105
106
|
});
|
|
106
|
-
var URLS, VERSION = "1.
|
|
107
|
+
var URLS, VERSION = "1.30.0", env;
|
|
107
108
|
var init_urls = __esm(() => {
|
|
108
109
|
URLS = {
|
|
109
110
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -3668,7 +3669,50 @@ var init_local_token = __esm(() => {
|
|
|
3668
3669
|
init_paths2();
|
|
3669
3670
|
});
|
|
3670
3671
|
|
|
3672
|
+
// src/services/session/token.ts
|
|
3673
|
+
var exports_token = {};
|
|
3674
|
+
__export(exports_token, {
|
|
3675
|
+
readSessionTokenFromEnv: () => readSessionTokenFromEnv,
|
|
3676
|
+
mintSessionToken: () => mintSessionToken,
|
|
3677
|
+
TOKEN_FILE_ENV: () => TOKEN_FILE_ENV
|
|
3678
|
+
});
|
|
3679
|
+
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
3680
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3681
|
+
function mintSessionToken(dir, fileName = "session-token") {
|
|
3682
|
+
const token = randomBytes5(32).toString("hex");
|
|
3683
|
+
const filePath = `${dir}/${fileName}`;
|
|
3684
|
+
writeFileSync5(filePath, token, { mode: 384 });
|
|
3685
|
+
return { token, filePath };
|
|
3686
|
+
}
|
|
3687
|
+
function readSessionTokenFromEnv(env2 = process.env) {
|
|
3688
|
+
const direct = env2.CLAUDEMESH_IPC_TOKEN;
|
|
3689
|
+
if (direct && /^[0-9a-f]{64}$/i.test(direct))
|
|
3690
|
+
return direct.toLowerCase();
|
|
3691
|
+
const path = env2[ENV_TOKEN_FILE];
|
|
3692
|
+
if (!path)
|
|
3693
|
+
return null;
|
|
3694
|
+
try {
|
|
3695
|
+
if (!existsSync5(path))
|
|
3696
|
+
return null;
|
|
3697
|
+
const raw = readFileSync5(path, "utf8").trim();
|
|
3698
|
+
if (/^[0-9a-f]{64}$/i.test(raw))
|
|
3699
|
+
return raw.toLowerCase();
|
|
3700
|
+
return null;
|
|
3701
|
+
} catch {
|
|
3702
|
+
return null;
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
var ENV_TOKEN_FILE = "CLAUDEMESH_IPC_TOKEN_FILE", TOKEN_FILE_ENV;
|
|
3706
|
+
var init_token = __esm(() => {
|
|
3707
|
+
TOKEN_FILE_ENV = ENV_TOKEN_FILE;
|
|
3708
|
+
});
|
|
3709
|
+
|
|
3671
3710
|
// src/daemon/ipc/client.ts
|
|
3711
|
+
var exports_client = {};
|
|
3712
|
+
__export(exports_client, {
|
|
3713
|
+
ipc: () => ipc,
|
|
3714
|
+
IpcError: () => IpcError
|
|
3715
|
+
});
|
|
3672
3716
|
import { request as httpRequest } from "node:http";
|
|
3673
3717
|
async function ipc(opts) {
|
|
3674
3718
|
const useTcp = !!opts.preferTcp;
|
|
@@ -3688,6 +3732,11 @@ async function ipc(opts) {
|
|
|
3688
3732
|
throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
|
|
3689
3733
|
headers.authorization = `Bearer ${tok}`;
|
|
3690
3734
|
}
|
|
3735
|
+
if (!useTcp) {
|
|
3736
|
+
const sessionTok = readSessionTokenFromEnv();
|
|
3737
|
+
if (sessionTok)
|
|
3738
|
+
headers.authorization = `ClaudeMesh-Session ${sessionTok}`;
|
|
3739
|
+
}
|
|
3691
3740
|
return new Promise((resolve, reject) => {
|
|
3692
3741
|
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
3742
|
const chunks = [];
|
|
@@ -3712,6 +3761,7 @@ var IpcError;
|
|
|
3712
3761
|
var init_client3 = __esm(() => {
|
|
3713
3762
|
init_paths2();
|
|
3714
3763
|
init_local_token();
|
|
3764
|
+
init_token();
|
|
3715
3765
|
IpcError = class IpcError extends Error {
|
|
3716
3766
|
status;
|
|
3717
3767
|
payload;
|
|
@@ -3729,7 +3779,7 @@ __export(exports_lifecycle, {
|
|
|
3729
3779
|
ensureDaemonReady: () => ensureDaemonReady,
|
|
3730
3780
|
_resetDaemonReadyCache: () => _resetDaemonReadyCache
|
|
3731
3781
|
});
|
|
3732
|
-
import { existsSync as
|
|
3782
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
3733
3783
|
import { join as join4 } from "node:path";
|
|
3734
3784
|
async function ensureDaemonReady(opts = {}) {
|
|
3735
3785
|
if (lastResultThisProcess && (lastResultThisProcess.state === "up" || lastResultThisProcess.state === "started")) {
|
|
@@ -3770,7 +3820,7 @@ async function runEnsureDaemon(opts) {
|
|
|
3770
3820
|
return { state: "spawn-failed", durationMs: Date.now() - t0, reason: spawnRes.reason };
|
|
3771
3821
|
}
|
|
3772
3822
|
async function probeDaemon() {
|
|
3773
|
-
if (!
|
|
3823
|
+
if (!existsSync6(DAEMON_PATHS.SOCK_FILE))
|
|
3774
3824
|
return "absent";
|
|
3775
3825
|
try {
|
|
3776
3826
|
const res = await ipc({ path: "/v1/version", timeoutMs: PROBE_TIMEOUT_MS });
|
|
@@ -3803,7 +3853,7 @@ function recentSpawnFailureFresh() {
|
|
|
3803
3853
|
}
|
|
3804
3854
|
function markSpawnFailure() {
|
|
3805
3855
|
try {
|
|
3806
|
-
|
|
3856
|
+
writeFileSync6(SPAWN_FAIL_FILE(), String(Date.now()), { mode: 384 });
|
|
3807
3857
|
} catch {}
|
|
3808
3858
|
}
|
|
3809
3859
|
function clearSpawnFailure() {
|
|
@@ -3840,9 +3890,9 @@ async function spawnDaemon(opts) {
|
|
|
3840
3890
|
}
|
|
3841
3891
|
async function acquireOrShareLock(_opts) {
|
|
3842
3892
|
const lockPath = SPAWN_LOCK_FILE();
|
|
3843
|
-
if (
|
|
3893
|
+
if (existsSync6(lockPath)) {
|
|
3844
3894
|
try {
|
|
3845
|
-
const pidStr =
|
|
3895
|
+
const pidStr = readFileSync6(lockPath, "utf8").trim();
|
|
3846
3896
|
const pid = Number.parseInt(pidStr, 10);
|
|
3847
3897
|
if (Number.isFinite(pid) && pid > 0) {
|
|
3848
3898
|
try {
|
|
@@ -3853,7 +3903,7 @@ async function acquireOrShareLock(_opts) {
|
|
|
3853
3903
|
} catch {}
|
|
3854
3904
|
}
|
|
3855
3905
|
try {
|
|
3856
|
-
|
|
3906
|
+
writeFileSync6(lockPath, String(process.pid), { mode: 384 });
|
|
3857
3907
|
} catch {}
|
|
3858
3908
|
return "acquired";
|
|
3859
3909
|
}
|
|
@@ -3865,7 +3915,7 @@ function releaseLock() {
|
|
|
3865
3915
|
async function pollForSocket(budgetMs) {
|
|
3866
3916
|
const start = Date.now();
|
|
3867
3917
|
while (Date.now() - start < budgetMs) {
|
|
3868
|
-
if (
|
|
3918
|
+
if (existsSync6(DAEMON_PATHS.SOCK_FILE)) {
|
|
3869
3919
|
const probe = await probeDaemon();
|
|
3870
3920
|
if (probe === "up")
|
|
3871
3921
|
return { ok: true };
|
|
@@ -3892,6 +3942,38 @@ var init_lifecycle = __esm(() => {
|
|
|
3892
3942
|
init_paths2();
|
|
3893
3943
|
});
|
|
3894
3944
|
|
|
3945
|
+
// src/services/broker/session-hello-sig.ts
|
|
3946
|
+
var exports_session_hello_sig = {};
|
|
3947
|
+
__export(exports_session_hello_sig, {
|
|
3948
|
+
signSessionHello: () => signSessionHello,
|
|
3949
|
+
signParentAttestation: () => signParentAttestation,
|
|
3950
|
+
DEFAULT_ATTESTATION_TTL_MS: () => DEFAULT_ATTESTATION_TTL_MS
|
|
3951
|
+
});
|
|
3952
|
+
async function signParentAttestation(args) {
|
|
3953
|
+
const s = await ensureSodium();
|
|
3954
|
+
const expiresAt = (args.now ?? Date.now()) + (args.ttlMs ?? DEFAULT_ATTESTATION_TTL_MS);
|
|
3955
|
+
const canonical = `claudemesh-session-attest|${args.parentMemberPubkey}|${args.sessionPubkey}|${expiresAt}`;
|
|
3956
|
+
const sig = s.crypto_sign_detached(s.from_string(canonical), s.from_hex(args.parentSecretKey));
|
|
3957
|
+
return {
|
|
3958
|
+
sessionPubkey: args.sessionPubkey,
|
|
3959
|
+
parentMemberPubkey: args.parentMemberPubkey,
|
|
3960
|
+
expiresAt,
|
|
3961
|
+
signature: s.to_hex(sig)
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
async function signSessionHello(args) {
|
|
3965
|
+
const s = await ensureSodium();
|
|
3966
|
+
const timestamp2 = args.now ?? Date.now();
|
|
3967
|
+
const canonical = `claudemesh-session-hello|${args.meshId}|${args.parentMemberPubkey}|${args.sessionPubkey}|${timestamp2}`;
|
|
3968
|
+
const sig = s.crypto_sign_detached(s.from_string(canonical), s.from_hex(args.sessionSecretKey));
|
|
3969
|
+
return { timestamp: timestamp2, signature: s.to_hex(sig) };
|
|
3970
|
+
}
|
|
3971
|
+
var DEFAULT_ATTESTATION_TTL_MS;
|
|
3972
|
+
var init_session_hello_sig = __esm(() => {
|
|
3973
|
+
init_keypair();
|
|
3974
|
+
DEFAULT_ATTESTATION_TTL_MS = 12 * 60 * 60 * 1000;
|
|
3975
|
+
});
|
|
3976
|
+
|
|
3895
3977
|
// src/commands/launch.ts
|
|
3896
3978
|
var exports_launch = {};
|
|
3897
3979
|
__export(exports_launch, {
|
|
@@ -3899,7 +3981,7 @@ __export(exports_launch, {
|
|
|
3899
3981
|
});
|
|
3900
3982
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
3901
3983
|
import { randomUUID } from "node:crypto";
|
|
3902
|
-
import { mkdtempSync, writeFileSync as
|
|
3984
|
+
import { mkdtempSync, writeFileSync as writeFileSync7, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
3903
3985
|
import { tmpdir, hostname as hostname2, homedir as homedir3 } from "node:os";
|
|
3904
3986
|
import { join as join5 } from "node:path";
|
|
3905
3987
|
import { createInterface as createInterface4 } from "node:readline";
|
|
@@ -4248,8 +4330,8 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4248
4330
|
await ensureDaemonRunning(mesh.slug, args.quiet);
|
|
4249
4331
|
try {
|
|
4250
4332
|
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4251
|
-
if (
|
|
4252
|
-
const claudeConfig = JSON.parse(
|
|
4333
|
+
if (existsSync7(claudeConfigPath)) {
|
|
4334
|
+
const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
|
|
4253
4335
|
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
4254
4336
|
let cleaned = 0;
|
|
4255
4337
|
for (const key of Object.keys(mcpServers)) {
|
|
@@ -4267,7 +4349,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4267
4349
|
}
|
|
4268
4350
|
if (cleaned > 0) {
|
|
4269
4351
|
claudeConfig.mcpServers = mcpServers;
|
|
4270
|
-
|
|
4352
|
+
writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4271
4353
|
`, "utf-8");
|
|
4272
4354
|
}
|
|
4273
4355
|
}
|
|
@@ -4293,8 +4375,61 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4293
4375
|
...parsedGroups.length > 0 ? { groups: parsedGroups } : {},
|
|
4294
4376
|
messageMode
|
|
4295
4377
|
};
|
|
4296
|
-
|
|
4378
|
+
writeFileSync7(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
|
|
4297
4379
|
`, "utf-8");
|
|
4380
|
+
const isResume = args.resume !== null || args.continueSession;
|
|
4381
|
+
const claudeSessionId = isResume ? undefined : randomUUID();
|
|
4382
|
+
let sessionTokenFilePath = null;
|
|
4383
|
+
let sessionTokenForCleanup = null;
|
|
4384
|
+
try {
|
|
4385
|
+
const { mintSessionToken: mintSessionToken2, TOKEN_FILE_ENV: TOKEN_FILE_ENV2 } = await Promise.resolve().then(() => (init_token(), exports_token));
|
|
4386
|
+
const minted = mintSessionToken2(tmpDir);
|
|
4387
|
+
sessionTokenFilePath = minted.filePath;
|
|
4388
|
+
sessionTokenForCleanup = minted.token;
|
|
4389
|
+
let presencePayload;
|
|
4390
|
+
try {
|
|
4391
|
+
const { generateKeypair: generateKeypair4 } = await Promise.resolve().then(() => (init_facade7(), exports_facade4));
|
|
4392
|
+
const { signParentAttestation: signParentAttestation2 } = await Promise.resolve().then(() => (init_session_hello_sig(), exports_session_hello_sig));
|
|
4393
|
+
const sessionKp = await generateKeypair4();
|
|
4394
|
+
const att = await signParentAttestation2({
|
|
4395
|
+
parentMemberPubkey: mesh.pubkey,
|
|
4396
|
+
parentSecretKey: mesh.secretKey,
|
|
4397
|
+
sessionPubkey: sessionKp.publicKey
|
|
4398
|
+
});
|
|
4399
|
+
presencePayload = {
|
|
4400
|
+
session_pubkey: sessionKp.publicKey,
|
|
4401
|
+
session_secret_key: sessionKp.secretKey,
|
|
4402
|
+
parent_attestation: {
|
|
4403
|
+
session_pubkey: att.sessionPubkey,
|
|
4404
|
+
parent_member_pubkey: att.parentMemberPubkey,
|
|
4405
|
+
expires_at: att.expiresAt,
|
|
4406
|
+
signature: att.signature
|
|
4407
|
+
}
|
|
4408
|
+
};
|
|
4409
|
+
} catch {}
|
|
4410
|
+
const { ipc: ipc2 } = await Promise.resolve().then(() => (init_client3(), exports_client));
|
|
4411
|
+
const sessionIdForRegister = claudeSessionId ?? randomUUID();
|
|
4412
|
+
await ipc2({
|
|
4413
|
+
method: "POST",
|
|
4414
|
+
path: "/v1/sessions/register",
|
|
4415
|
+
timeoutMs: 3000,
|
|
4416
|
+
body: {
|
|
4417
|
+
token: minted.token,
|
|
4418
|
+
session_id: sessionIdForRegister,
|
|
4419
|
+
mesh: mesh.slug,
|
|
4420
|
+
display_name: displayName,
|
|
4421
|
+
pid: process.pid,
|
|
4422
|
+
cwd: process.cwd(),
|
|
4423
|
+
...role ? { role } : {},
|
|
4424
|
+
...parsedGroups.length > 0 ? { groups: parsedGroups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`) } : {},
|
|
4425
|
+
...presencePayload ? { presence: presencePayload } : {}
|
|
4426
|
+
}
|
|
4427
|
+
}).catch(() => null);
|
|
4428
|
+
process._claudemeshTokenEnv = {
|
|
4429
|
+
name: TOKEN_FILE_ENV2,
|
|
4430
|
+
value: minted.filePath
|
|
4431
|
+
};
|
|
4432
|
+
} catch {}
|
|
4298
4433
|
if (!args.quiet) {
|
|
4299
4434
|
printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
|
|
4300
4435
|
}
|
|
@@ -4303,7 +4438,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4303
4438
|
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4304
4439
|
let claudeConfig = {};
|
|
4305
4440
|
try {
|
|
4306
|
-
claudeConfig = JSON.parse(
|
|
4441
|
+
claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
|
|
4307
4442
|
} catch {
|
|
4308
4443
|
claudeConfig = {};
|
|
4309
4444
|
}
|
|
@@ -4330,7 +4465,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4330
4465
|
meshMcpEntries.push({ key: entryKey, entry });
|
|
4331
4466
|
}
|
|
4332
4467
|
claudeConfig.mcpServers = mcpServers;
|
|
4333
|
-
|
|
4468
|
+
writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4334
4469
|
`, "utf-8");
|
|
4335
4470
|
if (!args.quiet && meshMcpEntries.length > 0) {
|
|
4336
4471
|
console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
|
|
@@ -4351,8 +4486,6 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4351
4486
|
}
|
|
4352
4487
|
filtered.push(args.claudeArgs[i]);
|
|
4353
4488
|
}
|
|
4354
|
-
const isResume = args.resume !== null || args.continueSession;
|
|
4355
|
-
const claudeSessionId = isResume ? undefined : randomUUID();
|
|
4356
4489
|
const claudeArgs = [
|
|
4357
4490
|
"--dangerously-load-development-channels",
|
|
4358
4491
|
"server:claudemesh",
|
|
@@ -4372,7 +4505,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4372
4505
|
join5(homedir3(), ".claude", "bin", "claude")
|
|
4373
4506
|
];
|
|
4374
4507
|
for (const c of candidates) {
|
|
4375
|
-
if (
|
|
4508
|
+
if (existsSync7(c)) {
|
|
4376
4509
|
claudeBin = c;
|
|
4377
4510
|
break;
|
|
4378
4511
|
}
|
|
@@ -4382,13 +4515,13 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4382
4515
|
if (meshMcpEntries.length > 0) {
|
|
4383
4516
|
try {
|
|
4384
4517
|
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4385
|
-
const claudeConfig = JSON.parse(
|
|
4518
|
+
const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
|
|
4386
4519
|
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
4387
4520
|
for (const { key } of meshMcpEntries) {
|
|
4388
4521
|
delete mcpServers[key];
|
|
4389
4522
|
}
|
|
4390
4523
|
claudeConfig.mcpServers = mcpServers;
|
|
4391
|
-
|
|
4524
|
+
writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4392
4525
|
`, "utf-8");
|
|
4393
4526
|
} catch {}
|
|
4394
4527
|
}
|
|
@@ -4418,6 +4551,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4418
4551
|
CLAUDEMESH_CONFIG_DIR: tmpDir,
|
|
4419
4552
|
CLAUDEMESH_DISPLAY_NAME: displayName,
|
|
4420
4553
|
...claudeSessionId ? { CLAUDEMESH_SESSION_ID: claudeSessionId } : {},
|
|
4554
|
+
...sessionTokenFilePath ? { CLAUDEMESH_IPC_TOKEN_FILE: sessionTokenFilePath } : {},
|
|
4421
4555
|
MCP_TIMEOUT: process.env.MCP_TIMEOUT ?? "30000",
|
|
4422
4556
|
MAX_MCP_OUTPUT_TOKENS: process.env.MAX_MCP_OUTPUT_TOKENS ?? "50000",
|
|
4423
4557
|
...role ? { CLAUDEMESH_ROLE: role } : {}
|
|
@@ -5085,7 +5219,7 @@ __export(exports_join, {
|
|
|
5085
5219
|
runJoin: () => runJoin
|
|
5086
5220
|
});
|
|
5087
5221
|
import sodium3 from "libsodium-wrappers";
|
|
5088
|
-
import { writeFileSync as
|
|
5222
|
+
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "node:fs";
|
|
5089
5223
|
import { join as join6, dirname as dirname3 } from "node:path";
|
|
5090
5224
|
import { homedir as homedir4, hostname as hostname3 } from "node:os";
|
|
5091
5225
|
function deriveAppBaseUrl() {
|
|
@@ -5210,7 +5344,7 @@ async function runJoin(args) {
|
|
|
5210
5344
|
const inviteFile = join6(configDir, `invite-${payload.mesh_slug}.txt`);
|
|
5211
5345
|
try {
|
|
5212
5346
|
mkdirSync4(dirname3(inviteFile), { recursive: true });
|
|
5213
|
-
|
|
5347
|
+
writeFileSync8(inviteFile, link, "utf-8");
|
|
5214
5348
|
} catch {}
|
|
5215
5349
|
console.log("");
|
|
5216
5350
|
console.log(`✓ Joined "${payload.mesh_slug}" as ${displayName}${enroll.alreadyMember ? " (already a member — re-enrolled with same pubkey)" : ""}`);
|
|
@@ -7660,6 +7794,45 @@ var init_daemon_route = __esm(() => {
|
|
|
7660
7794
|
init_warnings();
|
|
7661
7795
|
});
|
|
7662
7796
|
|
|
7797
|
+
// src/services/session/resolve.ts
|
|
7798
|
+
var exports_resolve = {};
|
|
7799
|
+
__export(exports_resolve, {
|
|
7800
|
+
getSessionInfo: () => getSessionInfo,
|
|
7801
|
+
_resetSessionCache: () => _resetSessionCache
|
|
7802
|
+
});
|
|
7803
|
+
async function getSessionInfo() {
|
|
7804
|
+
if (cached !== undefined)
|
|
7805
|
+
return cached;
|
|
7806
|
+
const tok = readSessionTokenFromEnv();
|
|
7807
|
+
if (!tok) {
|
|
7808
|
+
cached = null;
|
|
7809
|
+
return null;
|
|
7810
|
+
}
|
|
7811
|
+
try {
|
|
7812
|
+
const res = await ipc({
|
|
7813
|
+
path: "/v1/sessions/me",
|
|
7814
|
+
timeoutMs: 1500
|
|
7815
|
+
});
|
|
7816
|
+
if (res.status !== 200 || !res.body.session) {
|
|
7817
|
+
cached = null;
|
|
7818
|
+
return null;
|
|
7819
|
+
}
|
|
7820
|
+
cached = res.body.session;
|
|
7821
|
+
return cached;
|
|
7822
|
+
} catch {
|
|
7823
|
+
cached = null;
|
|
7824
|
+
return null;
|
|
7825
|
+
}
|
|
7826
|
+
}
|
|
7827
|
+
function _resetSessionCache() {
|
|
7828
|
+
cached = undefined;
|
|
7829
|
+
}
|
|
7830
|
+
var cached = undefined;
|
|
7831
|
+
var init_resolve = __esm(() => {
|
|
7832
|
+
init_client3();
|
|
7833
|
+
init_token();
|
|
7834
|
+
});
|
|
7835
|
+
|
|
7663
7836
|
// src/commands/peers.ts
|
|
7664
7837
|
var exports_peers = {};
|
|
7665
7838
|
__export(exports_peers, {
|
|
@@ -7699,7 +7872,14 @@ function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
|
|
|
7699
7872
|
}
|
|
7700
7873
|
async function runPeers(flags) {
|
|
7701
7874
|
const config = readConfig();
|
|
7702
|
-
|
|
7875
|
+
let slugs;
|
|
7876
|
+
if (flags.mesh) {
|
|
7877
|
+
slugs = [flags.mesh];
|
|
7878
|
+
} else {
|
|
7879
|
+
const { getSessionInfo: getSessionInfo2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
|
|
7880
|
+
const sess = await getSessionInfo2();
|
|
7881
|
+
slugs = sess ? [sess.mesh] : config.meshes.map((m) => m.slug);
|
|
7882
|
+
}
|
|
7703
7883
|
if (slugs.length === 0) {
|
|
7704
7884
|
render.err("No meshes joined.");
|
|
7705
7885
|
render.hint("claudemesh <invite-url> # join + launch");
|
|
@@ -8315,7 +8495,7 @@ async function runMsgStatus(id, opts) {
|
|
|
8315
8495
|
console.log(JSON.stringify(result, null, 2));
|
|
8316
8496
|
return EXIT.SUCCESS;
|
|
8317
8497
|
}
|
|
8318
|
-
render.section(`message ${
|
|
8498
|
+
render.section(`message ${lookupId.slice(0, 12)}…`);
|
|
8319
8499
|
render.kv([
|
|
8320
8500
|
["target", result.targetSpec],
|
|
8321
8501
|
["delivered", result.delivered ? "yes" : "no"],
|
|
@@ -8669,12 +8849,12 @@ var init_whoami = __esm(() => {
|
|
|
8669
8849
|
});
|
|
8670
8850
|
|
|
8671
8851
|
// src/daemon/lock.ts
|
|
8672
|
-
import { existsSync as
|
|
8852
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
8673
8853
|
import { dirname as dirname4 } from "node:path";
|
|
8674
8854
|
function acquireSingletonLock() {
|
|
8675
8855
|
mkdirSync5(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
|
|
8676
|
-
if (
|
|
8677
|
-
const raw =
|
|
8856
|
+
if (existsSync8(DAEMON_PATHS.PID_FILE)) {
|
|
8857
|
+
const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8678
8858
|
const oldPid = Number.parseInt(raw, 10);
|
|
8679
8859
|
if (Number.isFinite(oldPid) && oldPid > 0 && isProcessAlive(oldPid)) {
|
|
8680
8860
|
return { result: "already-running", pid: oldPid };
|
|
@@ -8682,22 +8862,22 @@ function acquireSingletonLock() {
|
|
|
8682
8862
|
try {
|
|
8683
8863
|
unlinkSync3(DAEMON_PATHS.PID_FILE);
|
|
8684
8864
|
} catch {}
|
|
8685
|
-
|
|
8865
|
+
writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
|
|
8686
8866
|
return { result: "stale", pid: process.pid };
|
|
8687
8867
|
}
|
|
8688
|
-
|
|
8868
|
+
writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
|
|
8689
8869
|
return { result: "acquired", pid: process.pid };
|
|
8690
8870
|
}
|
|
8691
8871
|
function releaseSingletonLock() {
|
|
8692
8872
|
try {
|
|
8693
|
-
const raw =
|
|
8873
|
+
const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8694
8874
|
if (Number.parseInt(raw, 10) === process.pid)
|
|
8695
8875
|
unlinkSync3(DAEMON_PATHS.PID_FILE);
|
|
8696
8876
|
} catch {}
|
|
8697
8877
|
}
|
|
8698
8878
|
function readRunningPid() {
|
|
8699
8879
|
try {
|
|
8700
|
-
const raw =
|
|
8880
|
+
const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8701
8881
|
const pid = Number.parseInt(raw, 10);
|
|
8702
8882
|
if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
|
|
8703
8883
|
return pid;
|
|
@@ -8843,17 +9023,17 @@ function requeueDeadOrPending(db, args) {
|
|
|
8843
9023
|
|
|
8844
9024
|
// src/daemon/db/sqlite.ts
|
|
8845
9025
|
async function loadSqlite() {
|
|
8846
|
-
if (
|
|
8847
|
-
return
|
|
9026
|
+
if (cached2)
|
|
9027
|
+
return cached2;
|
|
8848
9028
|
try {
|
|
8849
9029
|
const mod = await import("node:sqlite");
|
|
8850
|
-
|
|
8851
|
-
return
|
|
9030
|
+
cached2 = mod.DatabaseSync;
|
|
9031
|
+
return cached2;
|
|
8852
9032
|
} catch (nodeErr) {
|
|
8853
9033
|
try {
|
|
8854
9034
|
const bunMod = await import("bun:sqlite");
|
|
8855
|
-
|
|
8856
|
-
return
|
|
9035
|
+
cached2 = bunMod.Database;
|
|
9036
|
+
return cached2;
|
|
8857
9037
|
} catch {
|
|
8858
9038
|
const msg = `claudemesh daemon requires Node.js 22.5+ for the embedded SQLite store (node:sqlite), or Bun (bun:sqlite) for dev. Current: ${process.version}. Original error: ${String(nodeErr)}`;
|
|
8859
9039
|
throw new Error(msg);
|
|
@@ -8884,7 +9064,7 @@ function inImmediateTx(db, fn) {
|
|
|
8884
9064
|
throw err;
|
|
8885
9065
|
}
|
|
8886
9066
|
}
|
|
8887
|
-
var
|
|
9067
|
+
var cached2 = null;
|
|
8888
9068
|
|
|
8889
9069
|
// src/daemon/fingerprint.ts
|
|
8890
9070
|
import { createHash } from "node:crypto";
|
|
@@ -9127,9 +9307,88 @@ function bindSseStream(res, bus) {
|
|
|
9127
9307
|
return cleanup;
|
|
9128
9308
|
}
|
|
9129
9309
|
|
|
9310
|
+
// src/daemon/session-registry.ts
|
|
9311
|
+
function startReaper() {
|
|
9312
|
+
if (reaperHandle)
|
|
9313
|
+
return;
|
|
9314
|
+
reaperHandle = setInterval(reapDead, REAPER_INTERVAL_MS).unref?.() ?? reaperHandle;
|
|
9315
|
+
}
|
|
9316
|
+
function setRegistryHooks(next) {
|
|
9317
|
+
hooks.onRegister = next.onRegister;
|
|
9318
|
+
hooks.onDeregister = next.onDeregister;
|
|
9319
|
+
}
|
|
9320
|
+
function registerSession(info) {
|
|
9321
|
+
const priorToken = bySessionId.get(info.sessionId);
|
|
9322
|
+
if (priorToken && priorToken !== info.token) {
|
|
9323
|
+
const prior = byToken.get(priorToken);
|
|
9324
|
+
if (prior) {
|
|
9325
|
+
byToken.delete(priorToken);
|
|
9326
|
+
try {
|
|
9327
|
+
hooks.onDeregister?.(prior);
|
|
9328
|
+
} catch {}
|
|
9329
|
+
}
|
|
9330
|
+
}
|
|
9331
|
+
const stored = { ...info, registeredAt: Date.now() };
|
|
9332
|
+
byToken.set(info.token, stored);
|
|
9333
|
+
bySessionId.set(info.sessionId, info.token);
|
|
9334
|
+
try {
|
|
9335
|
+
hooks.onRegister?.(stored);
|
|
9336
|
+
} catch {}
|
|
9337
|
+
return stored;
|
|
9338
|
+
}
|
|
9339
|
+
function deregisterByToken(token) {
|
|
9340
|
+
const entry = byToken.get(token);
|
|
9341
|
+
if (!entry)
|
|
9342
|
+
return false;
|
|
9343
|
+
byToken.delete(token);
|
|
9344
|
+
if (bySessionId.get(entry.sessionId) === token)
|
|
9345
|
+
bySessionId.delete(entry.sessionId);
|
|
9346
|
+
try {
|
|
9347
|
+
hooks.onDeregister?.(entry);
|
|
9348
|
+
} catch {}
|
|
9349
|
+
return true;
|
|
9350
|
+
}
|
|
9351
|
+
function resolveToken(token) {
|
|
9352
|
+
const entry = byToken.get(token);
|
|
9353
|
+
if (!entry)
|
|
9354
|
+
return null;
|
|
9355
|
+
if (Date.now() - entry.registeredAt > TTL_MS) {
|
|
9356
|
+
deregisterByToken(token);
|
|
9357
|
+
return null;
|
|
9358
|
+
}
|
|
9359
|
+
return entry;
|
|
9360
|
+
}
|
|
9361
|
+
function listSessions() {
|
|
9362
|
+
return [...byToken.values()];
|
|
9363
|
+
}
|
|
9364
|
+
function reapDead() {
|
|
9365
|
+
const dead = [];
|
|
9366
|
+
for (const [token, info] of byToken.entries()) {
|
|
9367
|
+
if (Date.now() - info.registeredAt > TTL_MS) {
|
|
9368
|
+
dead.push(token);
|
|
9369
|
+
continue;
|
|
9370
|
+
}
|
|
9371
|
+
try {
|
|
9372
|
+
process.kill(info.pid, 0);
|
|
9373
|
+
} catch {
|
|
9374
|
+
dead.push(token);
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
9377
|
+
for (const t of dead)
|
|
9378
|
+
deregisterByToken(t);
|
|
9379
|
+
}
|
|
9380
|
+
var TTL_MS, REAPER_INTERVAL_MS, byToken, bySessionId, hooks, reaperHandle = null;
|
|
9381
|
+
var init_session_registry = __esm(() => {
|
|
9382
|
+
TTL_MS = 24 * 60 * 60 * 1000;
|
|
9383
|
+
REAPER_INTERVAL_MS = 30 * 1000;
|
|
9384
|
+
byToken = new Map;
|
|
9385
|
+
bySessionId = new Map;
|
|
9386
|
+
hooks = {};
|
|
9387
|
+
});
|
|
9388
|
+
|
|
9130
9389
|
// src/daemon/ipc/server.ts
|
|
9131
9390
|
import { createServer as createServer2 } from "node:http";
|
|
9132
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
9391
|
+
import { chmodSync as chmodSync3, existsSync as existsSync9, unlinkSync as unlinkSync4 } from "node:fs";
|
|
9133
9392
|
import { timingSafeEqual } from "node:crypto";
|
|
9134
9393
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
9135
9394
|
function startIpcServer(opts) {
|
|
@@ -9145,7 +9404,7 @@ function startIpcServer(opts) {
|
|
|
9145
9404
|
meshConfigs: opts.meshConfigs,
|
|
9146
9405
|
onPendingInserted: opts.onPendingInserted
|
|
9147
9406
|
});
|
|
9148
|
-
if (
|
|
9407
|
+
if (existsSync9(DAEMON_PATHS.SOCK_FILE)) {
|
|
9149
9408
|
try {
|
|
9150
9409
|
unlinkSync4(DAEMON_PATHS.SOCK_FILE);
|
|
9151
9410
|
} catch {}
|
|
@@ -9231,11 +9490,19 @@ function makeHandler(opts) {
|
|
|
9231
9490
|
return;
|
|
9232
9491
|
}
|
|
9233
9492
|
}
|
|
9493
|
+
let session = null;
|
|
9494
|
+
{
|
|
9495
|
+
const authz = req.headers.authorization ?? "";
|
|
9496
|
+
const sm = /^ClaudeMesh-Session\s+([0-9a-f]{64})$/i.exec(authz.trim());
|
|
9497
|
+
if (sm && sm[1])
|
|
9498
|
+
session = resolveToken(sm[1].toLowerCase());
|
|
9499
|
+
}
|
|
9500
|
+
const meshFromCtx = (explicit) => explicit && explicit.trim() ? explicit : session?.mesh ?? null;
|
|
9234
9501
|
if (req.method === "GET" && url.pathname === "/v1/version") {
|
|
9235
9502
|
respond(res, 200, {
|
|
9236
9503
|
daemon_version: VERSION,
|
|
9237
9504
|
ipc_api: "v1",
|
|
9238
|
-
ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory"],
|
|
9505
|
+
ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory", "sessions"],
|
|
9239
9506
|
schema_version: 1
|
|
9240
9507
|
});
|
|
9241
9508
|
return;
|
|
@@ -9244,6 +9511,102 @@ function makeHandler(opts) {
|
|
|
9244
9511
|
respond(res, 200, { ok: true, pid: process.pid });
|
|
9245
9512
|
return;
|
|
9246
9513
|
}
|
|
9514
|
+
if (req.method === "POST" && url.pathname === "/v1/sessions/register") {
|
|
9515
|
+
try {
|
|
9516
|
+
const body = await readJsonBody(req, 64 * 1024);
|
|
9517
|
+
if (!body) {
|
|
9518
|
+
respond(res, 400, { error: "missing body" });
|
|
9519
|
+
return;
|
|
9520
|
+
}
|
|
9521
|
+
const token = typeof body.token === "string" ? body.token : "";
|
|
9522
|
+
if (!/^[0-9a-f]{64}$/i.test(token)) {
|
|
9523
|
+
respond(res, 400, { error: "token must be 64 hex chars" });
|
|
9524
|
+
return;
|
|
9525
|
+
}
|
|
9526
|
+
const sessionId = typeof body.session_id === "string" ? body.session_id : "";
|
|
9527
|
+
const mesh = typeof body.mesh === "string" ? body.mesh : "";
|
|
9528
|
+
const displayName = typeof body.display_name === "string" ? body.display_name : "";
|
|
9529
|
+
const pid = typeof body.pid === "number" ? body.pid : 0;
|
|
9530
|
+
if (!sessionId || !mesh || !displayName || !pid) {
|
|
9531
|
+
respond(res, 400, { error: "session_id, mesh, display_name, pid all required" });
|
|
9532
|
+
return;
|
|
9533
|
+
}
|
|
9534
|
+
const cwd = typeof body.cwd === "string" ? body.cwd : undefined;
|
|
9535
|
+
const role = typeof body.role === "string" ? body.role : undefined;
|
|
9536
|
+
const groups = Array.isArray(body.groups) ? body.groups.filter((g) => typeof g === "string") : undefined;
|
|
9537
|
+
let presence;
|
|
9538
|
+
const rawPresence = body.presence;
|
|
9539
|
+
if (rawPresence && typeof rawPresence === "object") {
|
|
9540
|
+
const p = rawPresence;
|
|
9541
|
+
const sessionPubkey = typeof p.session_pubkey === "string" ? p.session_pubkey.toLowerCase() : "";
|
|
9542
|
+
const sessionSecretKey = typeof p.session_secret_key === "string" ? p.session_secret_key.toLowerCase() : "";
|
|
9543
|
+
const att = p.parent_attestation;
|
|
9544
|
+
if (/^[0-9a-f]{64}$/.test(sessionPubkey) && /^[0-9a-f]{128}$/.test(sessionSecretKey) && att && typeof att === "object" && typeof att.session_pubkey === "string" && typeof att.parent_member_pubkey === "string" && typeof att.expires_at === "number" && typeof att.signature === "string") {
|
|
9545
|
+
presence = {
|
|
9546
|
+
sessionPubkey,
|
|
9547
|
+
sessionSecretKey,
|
|
9548
|
+
parentAttestation: {
|
|
9549
|
+
sessionPubkey: att.session_pubkey.toLowerCase(),
|
|
9550
|
+
parentMemberPubkey: att.parent_member_pubkey.toLowerCase(),
|
|
9551
|
+
expiresAt: att.expires_at,
|
|
9552
|
+
signature: att.signature.toLowerCase()
|
|
9553
|
+
}
|
|
9554
|
+
};
|
|
9555
|
+
} else {
|
|
9556
|
+
opts.log("warn", "session_register_presence_malformed", { mesh });
|
|
9557
|
+
}
|
|
9558
|
+
}
|
|
9559
|
+
const stored = registerSession({
|
|
9560
|
+
token: token.toLowerCase(),
|
|
9561
|
+
sessionId,
|
|
9562
|
+
mesh,
|
|
9563
|
+
displayName,
|
|
9564
|
+
pid,
|
|
9565
|
+
cwd,
|
|
9566
|
+
role,
|
|
9567
|
+
groups,
|
|
9568
|
+
...presence ? { presence } : {}
|
|
9569
|
+
});
|
|
9570
|
+
opts.log("info", "session_registered", {
|
|
9571
|
+
sessionId,
|
|
9572
|
+
mesh,
|
|
9573
|
+
pid,
|
|
9574
|
+
presence: presence ? "yes" : "no"
|
|
9575
|
+
});
|
|
9576
|
+
respond(res, 200, {
|
|
9577
|
+
ok: true,
|
|
9578
|
+
registered_at: stored.registeredAt,
|
|
9579
|
+
presence_accepted: !!presence
|
|
9580
|
+
});
|
|
9581
|
+
} catch (e) {
|
|
9582
|
+
respond(res, 400, { error: String(e) });
|
|
9583
|
+
}
|
|
9584
|
+
return;
|
|
9585
|
+
}
|
|
9586
|
+
if (req.method === "DELETE" && url.pathname.startsWith("/v1/sessions/")) {
|
|
9587
|
+
const tail = url.pathname.slice("/v1/sessions/".length);
|
|
9588
|
+
if (!/^[0-9a-f]{64}$/i.test(tail)) {
|
|
9589
|
+
respond(res, 400, { error: "invalid token" });
|
|
9590
|
+
return;
|
|
9591
|
+
}
|
|
9592
|
+
const ok = deregisterByToken(tail.toLowerCase());
|
|
9593
|
+
respond(res, ok ? 200 : 404, { ok, token_prefix: tail.slice(0, 8) });
|
|
9594
|
+
return;
|
|
9595
|
+
}
|
|
9596
|
+
if (req.method === "GET" && url.pathname === "/v1/sessions/me") {
|
|
9597
|
+
if (!session) {
|
|
9598
|
+
respond(res, 401, { error: "no session token" });
|
|
9599
|
+
return;
|
|
9600
|
+
}
|
|
9601
|
+
const { token, ...redacted } = session;
|
|
9602
|
+
respond(res, 200, { session: { ...redacted, token_prefix: token.slice(0, 8) } });
|
|
9603
|
+
return;
|
|
9604
|
+
}
|
|
9605
|
+
if (req.method === "GET" && url.pathname === "/v1/sessions") {
|
|
9606
|
+
const all = listSessions().map(({ token, ...rest }) => ({ ...rest, token_prefix: token.slice(0, 8) }));
|
|
9607
|
+
respond(res, 200, { sessions: all });
|
|
9608
|
+
return;
|
|
9609
|
+
}
|
|
9247
9610
|
if (req.method === "GET" && url.pathname === "/v1/events") {
|
|
9248
9611
|
if (!opts.bus) {
|
|
9249
9612
|
respond(res, 503, { error: "event bus not initialised" });
|
|
@@ -9257,7 +9620,7 @@ function makeHandler(opts) {
|
|
|
9257
9620
|
respond(res, 503, { error: "broker not initialised" });
|
|
9258
9621
|
return;
|
|
9259
9622
|
}
|
|
9260
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9623
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9261
9624
|
try {
|
|
9262
9625
|
const all = [];
|
|
9263
9626
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
@@ -9282,7 +9645,7 @@ function makeHandler(opts) {
|
|
|
9282
9645
|
respond(res, 503, { error: "broker not initialised" });
|
|
9283
9646
|
return;
|
|
9284
9647
|
}
|
|
9285
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9648
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9286
9649
|
const key = url.searchParams.get("key");
|
|
9287
9650
|
try {
|
|
9288
9651
|
if (key) {
|
|
@@ -9323,7 +9686,7 @@ function makeHandler(opts) {
|
|
|
9323
9686
|
respond(res, 400, { error: "missing 'key' (string)" });
|
|
9324
9687
|
return;
|
|
9325
9688
|
}
|
|
9326
|
-
const requested = (typeof body.mesh === "string" ? body.mesh : null)
|
|
9689
|
+
const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : null);
|
|
9327
9690
|
let chosen = requested;
|
|
9328
9691
|
if (!chosen && opts.brokers.size === 1)
|
|
9329
9692
|
chosen = opts.brokers.keys().next().value;
|
|
@@ -9349,7 +9712,7 @@ function makeHandler(opts) {
|
|
|
9349
9712
|
return;
|
|
9350
9713
|
}
|
|
9351
9714
|
const query = url.searchParams.get("q") ?? "";
|
|
9352
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9715
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9353
9716
|
try {
|
|
9354
9717
|
const all = [];
|
|
9355
9718
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
@@ -9376,7 +9739,7 @@ function makeHandler(opts) {
|
|
|
9376
9739
|
respond(res, 400, { error: "missing 'content' (string)" });
|
|
9377
9740
|
return;
|
|
9378
9741
|
}
|
|
9379
|
-
const requested = (typeof body.mesh === "string" ? body.mesh : null)
|
|
9742
|
+
const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : null);
|
|
9380
9743
|
let chosen = requested;
|
|
9381
9744
|
if (!chosen && opts.brokers.size === 1)
|
|
9382
9745
|
chosen = opts.brokers.keys().next().value;
|
|
@@ -9434,7 +9797,7 @@ function makeHandler(opts) {
|
|
|
9434
9797
|
return;
|
|
9435
9798
|
}
|
|
9436
9799
|
const query = url.searchParams.get("query") ?? undefined;
|
|
9437
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9800
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9438
9801
|
try {
|
|
9439
9802
|
const all = [];
|
|
9440
9803
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
@@ -9464,7 +9827,7 @@ function makeHandler(opts) {
|
|
|
9464
9827
|
respond(res, 400, { error: "missing skill name" });
|
|
9465
9828
|
return;
|
|
9466
9829
|
}
|
|
9467
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9830
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9468
9831
|
try {
|
|
9469
9832
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
9470
9833
|
if (filterMesh && filterMesh !== slug)
|
|
@@ -9492,7 +9855,7 @@ function makeHandler(opts) {
|
|
|
9492
9855
|
respond(res, 400, { error: "expected JSON object" });
|
|
9493
9856
|
return;
|
|
9494
9857
|
}
|
|
9495
|
-
const requested = (typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh"))
|
|
9858
|
+
const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh"));
|
|
9496
9859
|
const targets = requested ? [opts.brokers.get(requested)].filter(Boolean) : [...opts.brokers.values()];
|
|
9497
9860
|
if (targets.length === 0) {
|
|
9498
9861
|
respond(res, 404, { error: "mesh_not_attached", mesh: requested });
|
|
@@ -9776,16 +10139,16 @@ function parseSendRequest(body, idempotencyHeader) {
|
|
|
9776
10139
|
}
|
|
9777
10140
|
async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
|
|
9778
10141
|
const { encryptDirect: encryptDirect2 } = await Promise.resolve().then(() => (init_box(), exports_box));
|
|
9779
|
-
const { randomBytes:
|
|
10142
|
+
const { randomBytes: randomBytes6 } = await import("node:crypto");
|
|
9780
10143
|
const to = req.to.trim();
|
|
9781
10144
|
if (to.startsWith("#") && /^#[0-9a-z_-]{20,}$/i.test(to)) {
|
|
9782
10145
|
const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
|
|
9783
|
-
const nonce =
|
|
10146
|
+
const nonce = randomBytes6(24).toString("base64");
|
|
9784
10147
|
return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
|
|
9785
10148
|
}
|
|
9786
10149
|
if (to.startsWith("@") || to === "*") {
|
|
9787
10150
|
const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
|
|
9788
|
-
const nonce =
|
|
10151
|
+
const nonce = randomBytes6(24).toString("base64");
|
|
9789
10152
|
return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
|
|
9790
10153
|
}
|
|
9791
10154
|
if (/^[0-9a-f]{64}$/i.test(to)) {
|
|
@@ -9826,6 +10189,7 @@ function respond(res, status, body) {
|
|
|
9826
10189
|
var init_server = __esm(() => {
|
|
9827
10190
|
init_paths2();
|
|
9828
10191
|
init_send2();
|
|
10192
|
+
init_session_registry();
|
|
9829
10193
|
init_urls();
|
|
9830
10194
|
});
|
|
9831
10195
|
|
|
@@ -10314,9 +10678,168 @@ var init_broker = __esm(() => {
|
|
|
10314
10678
|
BACKOFF_CAPS_MS = [1000, 2000, 4000, 8000, 16000, 30000];
|
|
10315
10679
|
});
|
|
10316
10680
|
|
|
10681
|
+
// src/daemon/session-broker.ts
|
|
10682
|
+
import { hostname as osHostname } from "node:os";
|
|
10683
|
+
import WebSocket3 from "ws";
|
|
10684
|
+
|
|
10685
|
+
class SessionBrokerClient {
|
|
10686
|
+
opts;
|
|
10687
|
+
ws = null;
|
|
10688
|
+
_status = "closed";
|
|
10689
|
+
closed = false;
|
|
10690
|
+
reconnectAttempt = 0;
|
|
10691
|
+
reconnectTimer = null;
|
|
10692
|
+
helloTimer = null;
|
|
10693
|
+
constructor(opts) {
|
|
10694
|
+
this.opts = opts;
|
|
10695
|
+
}
|
|
10696
|
+
get status() {
|
|
10697
|
+
return this._status;
|
|
10698
|
+
}
|
|
10699
|
+
get meshSlug() {
|
|
10700
|
+
return this.opts.mesh.slug;
|
|
10701
|
+
}
|
|
10702
|
+
get sessionPubkey() {
|
|
10703
|
+
return this.opts.sessionPubkey;
|
|
10704
|
+
}
|
|
10705
|
+
log = (level, msg, meta) => {
|
|
10706
|
+
(this.opts.log ?? defaultLog2)(level, msg, {
|
|
10707
|
+
mesh: this.opts.mesh.slug,
|
|
10708
|
+
session_pubkey: this.opts.sessionPubkey.slice(0, 12),
|
|
10709
|
+
...meta
|
|
10710
|
+
});
|
|
10711
|
+
};
|
|
10712
|
+
setStatus(s) {
|
|
10713
|
+
if (this._status === s)
|
|
10714
|
+
return;
|
|
10715
|
+
this._status = s;
|
|
10716
|
+
this.opts.onStatusChange?.(s);
|
|
10717
|
+
}
|
|
10718
|
+
async connect() {
|
|
10719
|
+
if (this.closed)
|
|
10720
|
+
throw new Error("client_closed");
|
|
10721
|
+
if (this._status === "connecting" || this._status === "open")
|
|
10722
|
+
return;
|
|
10723
|
+
this.setStatus("connecting");
|
|
10724
|
+
const ws = new WebSocket3(this.opts.mesh.brokerUrl);
|
|
10725
|
+
this.ws = ws;
|
|
10726
|
+
return new Promise((resolve, reject) => {
|
|
10727
|
+
ws.on("open", async () => {
|
|
10728
|
+
try {
|
|
10729
|
+
const { timestamp: timestamp2, signature } = await signSessionHello({
|
|
10730
|
+
meshId: this.opts.mesh.meshId,
|
|
10731
|
+
parentMemberPubkey: this.opts.mesh.pubkey,
|
|
10732
|
+
sessionPubkey: this.opts.sessionPubkey,
|
|
10733
|
+
sessionSecretKey: this.opts.sessionSecretKey
|
|
10734
|
+
});
|
|
10735
|
+
ws.send(JSON.stringify({
|
|
10736
|
+
type: "session_hello",
|
|
10737
|
+
meshId: this.opts.mesh.meshId,
|
|
10738
|
+
parentMemberId: this.opts.mesh.memberId,
|
|
10739
|
+
parentMemberPubkey: this.opts.mesh.pubkey,
|
|
10740
|
+
sessionPubkey: this.opts.sessionPubkey,
|
|
10741
|
+
parentAttestation: this.opts.parentAttestation,
|
|
10742
|
+
displayName: this.opts.displayName,
|
|
10743
|
+
sessionId: this.opts.sessionId,
|
|
10744
|
+
pid: this.opts.pid,
|
|
10745
|
+
cwd: this.opts.cwd ?? process.cwd(),
|
|
10746
|
+
hostname: osHostname(),
|
|
10747
|
+
peerType: "ai",
|
|
10748
|
+
channel: "claudemesh-session",
|
|
10749
|
+
...this.opts.groups && this.opts.groups.length > 0 ? { groups: this.opts.groups } : {},
|
|
10750
|
+
...this.opts.role ? { role: this.opts.role } : {},
|
|
10751
|
+
timestamp: timestamp2,
|
|
10752
|
+
signature
|
|
10753
|
+
}));
|
|
10754
|
+
this.helloTimer = setTimeout(() => {
|
|
10755
|
+
this.log("warn", "session_hello_ack_timeout");
|
|
10756
|
+
try {
|
|
10757
|
+
ws.close();
|
|
10758
|
+
} catch {}
|
|
10759
|
+
reject(new Error("session_hello_ack_timeout"));
|
|
10760
|
+
}, HELLO_ACK_TIMEOUT_MS3);
|
|
10761
|
+
} catch (e) {
|
|
10762
|
+
reject(e instanceof Error ? e : new Error(String(e)));
|
|
10763
|
+
}
|
|
10764
|
+
});
|
|
10765
|
+
ws.on("message", (raw) => {
|
|
10766
|
+
let msg;
|
|
10767
|
+
try {
|
|
10768
|
+
msg = JSON.parse(raw.toString());
|
|
10769
|
+
} catch {
|
|
10770
|
+
return;
|
|
10771
|
+
}
|
|
10772
|
+
if (msg.type === "hello_ack") {
|
|
10773
|
+
if (this.helloTimer)
|
|
10774
|
+
clearTimeout(this.helloTimer);
|
|
10775
|
+
this.helloTimer = null;
|
|
10776
|
+
this.setStatus("open");
|
|
10777
|
+
this.reconnectAttempt = 0;
|
|
10778
|
+
resolve();
|
|
10779
|
+
return;
|
|
10780
|
+
}
|
|
10781
|
+
if (msg.type === "error") {
|
|
10782
|
+
this.log("warn", "broker_error", { code: msg.code, message: msg.message });
|
|
10783
|
+
if (msg.code === "unknown_message_type") {
|
|
10784
|
+
this.closed = true;
|
|
10785
|
+
}
|
|
10786
|
+
return;
|
|
10787
|
+
}
|
|
10788
|
+
});
|
|
10789
|
+
ws.on("close", (code, reason) => {
|
|
10790
|
+
if (this.helloTimer) {
|
|
10791
|
+
clearTimeout(this.helloTimer);
|
|
10792
|
+
this.helloTimer = null;
|
|
10793
|
+
}
|
|
10794
|
+
if (this.closed) {
|
|
10795
|
+
this.setStatus("closed");
|
|
10796
|
+
return;
|
|
10797
|
+
}
|
|
10798
|
+
this.setStatus("reconnecting");
|
|
10799
|
+
const wait = BACKOFF_CAPS_MS2[Math.min(this.reconnectAttempt, BACKOFF_CAPS_MS2.length - 1)] ?? 30000;
|
|
10800
|
+
this.reconnectAttempt++;
|
|
10801
|
+
this.log("info", "session_broker_reconnect_scheduled", { wait_ms: wait, code, reason: reason.toString("utf8") });
|
|
10802
|
+
this.reconnectTimer = setTimeout(() => this.connect().catch((err) => this.log("warn", "session_broker_reconnect_failed", { err: String(err) })), wait);
|
|
10803
|
+
if (this._status === "connecting")
|
|
10804
|
+
reject(new Error(`closed_before_hello_${code}`));
|
|
10805
|
+
});
|
|
10806
|
+
ws.on("error", (err) => this.log("warn", "session_broker_ws_error", { err: err.message }));
|
|
10807
|
+
});
|
|
10808
|
+
}
|
|
10809
|
+
async close() {
|
|
10810
|
+
this.closed = true;
|
|
10811
|
+
if (this.reconnectTimer) {
|
|
10812
|
+
clearTimeout(this.reconnectTimer);
|
|
10813
|
+
this.reconnectTimer = null;
|
|
10814
|
+
}
|
|
10815
|
+
if (this.helloTimer) {
|
|
10816
|
+
clearTimeout(this.helloTimer);
|
|
10817
|
+
this.helloTimer = null;
|
|
10818
|
+
}
|
|
10819
|
+
try {
|
|
10820
|
+
this.ws?.close();
|
|
10821
|
+
} catch {}
|
|
10822
|
+
this.setStatus("closed");
|
|
10823
|
+
}
|
|
10824
|
+
}
|
|
10825
|
+
function defaultLog2(level, msg, meta) {
|
|
10826
|
+
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
10827
|
+
if (level === "info")
|
|
10828
|
+
process.stdout.write(line + `
|
|
10829
|
+
`);
|
|
10830
|
+
else
|
|
10831
|
+
process.stderr.write(line + `
|
|
10832
|
+
`);
|
|
10833
|
+
}
|
|
10834
|
+
var HELLO_ACK_TIMEOUT_MS3 = 5000, BACKOFF_CAPS_MS2;
|
|
10835
|
+
var init_session_broker = __esm(() => {
|
|
10836
|
+
init_session_hello_sig();
|
|
10837
|
+
BACKOFF_CAPS_MS2 = [1000, 2000, 4000, 8000, 16000, 30000];
|
|
10838
|
+
});
|
|
10839
|
+
|
|
10317
10840
|
// src/daemon/drain.ts
|
|
10318
10841
|
function startDrainWorker(opts) {
|
|
10319
|
-
const log2 = opts.log ??
|
|
10842
|
+
const log2 = opts.log ?? defaultLog3;
|
|
10320
10843
|
let stopped = false;
|
|
10321
10844
|
let wakeResolve = null;
|
|
10322
10845
|
let wakePromise = new Promise((r) => {
|
|
@@ -10457,10 +10980,10 @@ function bufferToHex(b) {
|
|
|
10457
10980
|
return s;
|
|
10458
10981
|
}
|
|
10459
10982
|
async function randomNonce2() {
|
|
10460
|
-
const { randomBytes:
|
|
10461
|
-
return
|
|
10983
|
+
const { randomBytes: randomBytes6 } = await import("node:crypto");
|
|
10984
|
+
return randomBytes6(24).toString("base64");
|
|
10462
10985
|
}
|
|
10463
|
-
function
|
|
10986
|
+
function defaultLog3(level, msg, meta) {
|
|
10464
10987
|
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
10465
10988
|
if (level === "info")
|
|
10466
10989
|
process.stdout.write(line + `
|
|
@@ -10580,7 +11103,7 @@ __export(exports_identity, {
|
|
|
10580
11103
|
checkFingerprint: () => checkFingerprint,
|
|
10581
11104
|
acceptCurrentHost: () => acceptCurrentHost
|
|
10582
11105
|
});
|
|
10583
|
-
import { existsSync as
|
|
11106
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "node:fs";
|
|
10584
11107
|
import { join as join7 } from "node:path";
|
|
10585
11108
|
import { createHash as createHash2 } from "node:crypto";
|
|
10586
11109
|
import { networkInterfaces } from "node:os";
|
|
@@ -10601,13 +11124,13 @@ function computeCurrentFingerprint() {
|
|
|
10601
11124
|
}
|
|
10602
11125
|
function checkFingerprint() {
|
|
10603
11126
|
const current = computeCurrentFingerprint();
|
|
10604
|
-
if (!
|
|
10605
|
-
|
|
11127
|
+
if (!existsSync10(path())) {
|
|
11128
|
+
writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
|
|
10606
11129
|
return { result: "first_run", current };
|
|
10607
11130
|
}
|
|
10608
11131
|
let stored;
|
|
10609
11132
|
try {
|
|
10610
|
-
stored = JSON.parse(
|
|
11133
|
+
stored = JSON.parse(readFileSync9(path(), "utf8"));
|
|
10611
11134
|
} catch {
|
|
10612
11135
|
return { result: "unavailable", current };
|
|
10613
11136
|
}
|
|
@@ -10617,14 +11140,14 @@ function checkFingerprint() {
|
|
|
10617
11140
|
}
|
|
10618
11141
|
function acceptCurrentHost() {
|
|
10619
11142
|
const current = computeCurrentFingerprint();
|
|
10620
|
-
|
|
11143
|
+
writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
|
|
10621
11144
|
return current;
|
|
10622
11145
|
}
|
|
10623
11146
|
function readHostId() {
|
|
10624
11147
|
if (process.platform === "linux") {
|
|
10625
11148
|
for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
10626
11149
|
try {
|
|
10627
|
-
const raw =
|
|
11150
|
+
const raw = readFileSync9(p, "utf8").trim();
|
|
10628
11151
|
if (raw)
|
|
10629
11152
|
return `linux:${raw}`;
|
|
10630
11153
|
} catch {}
|
|
@@ -10669,16 +11192,16 @@ var init_identity = __esm(() => {
|
|
|
10669
11192
|
});
|
|
10670
11193
|
|
|
10671
11194
|
// src/daemon/run.ts
|
|
10672
|
-
import { existsSync as
|
|
11195
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync10 } from "node:fs";
|
|
10673
11196
|
function detectContainer() {
|
|
10674
11197
|
if (process.env.KUBERNETES_SERVICE_HOST)
|
|
10675
11198
|
return true;
|
|
10676
11199
|
if (process.env.CONTAINER === "1")
|
|
10677
11200
|
return true;
|
|
10678
11201
|
try {
|
|
10679
|
-
if (
|
|
11202
|
+
if (existsSync11("/.dockerenv"))
|
|
10680
11203
|
return true;
|
|
10681
|
-
const cg =
|
|
11204
|
+
const cg = readFileSync10("/proc/1/cgroup", "utf8");
|
|
10682
11205
|
if (/(docker|kubepods|containerd)/.test(cg))
|
|
10683
11206
|
return true;
|
|
10684
11207
|
} catch {}
|
|
@@ -10803,6 +11326,57 @@ async function runDaemon(opts = {}) {
|
|
|
10803
11326
|
}
|
|
10804
11327
|
let drain = null;
|
|
10805
11328
|
drain = startDrainWorker({ db: outboxDb, brokers });
|
|
11329
|
+
const sessionBrokers = new Map;
|
|
11330
|
+
setRegistryHooks({
|
|
11331
|
+
onRegister: (info) => {
|
|
11332
|
+
if (!info.presence)
|
|
11333
|
+
return;
|
|
11334
|
+
const meshConfig = meshConfigs.get(info.mesh);
|
|
11335
|
+
if (!meshConfig) {
|
|
11336
|
+
process.stderr.write(JSON.stringify({
|
|
11337
|
+
level: "warn",
|
|
11338
|
+
msg: "session_broker_no_mesh_config",
|
|
11339
|
+
mesh: info.mesh,
|
|
11340
|
+
ts: new Date().toISOString()
|
|
11341
|
+
}) + `
|
|
11342
|
+
`);
|
|
11343
|
+
return;
|
|
11344
|
+
}
|
|
11345
|
+
const prior = sessionBrokers.get(info.token);
|
|
11346
|
+
if (prior) {
|
|
11347
|
+
sessionBrokers.delete(info.token);
|
|
11348
|
+
prior.close().catch(() => {});
|
|
11349
|
+
}
|
|
11350
|
+
const client = new SessionBrokerClient({
|
|
11351
|
+
mesh: meshConfig,
|
|
11352
|
+
sessionPubkey: info.presence.sessionPubkey,
|
|
11353
|
+
sessionSecretKey: info.presence.sessionSecretKey,
|
|
11354
|
+
parentAttestation: info.presence.parentAttestation,
|
|
11355
|
+
sessionId: info.sessionId,
|
|
11356
|
+
displayName: info.displayName,
|
|
11357
|
+
...info.role ? { role: info.role } : {},
|
|
11358
|
+
...info.cwd ? { cwd: info.cwd } : {},
|
|
11359
|
+
pid: info.pid
|
|
11360
|
+
});
|
|
11361
|
+
sessionBrokers.set(info.token, client);
|
|
11362
|
+
client.connect().catch((err) => process.stderr.write(JSON.stringify({
|
|
11363
|
+
level: "warn",
|
|
11364
|
+
msg: "session_broker_connect_failed",
|
|
11365
|
+
mesh: info.mesh,
|
|
11366
|
+
err: String(err),
|
|
11367
|
+
ts: new Date().toISOString()
|
|
11368
|
+
}) + `
|
|
11369
|
+
`));
|
|
11370
|
+
},
|
|
11371
|
+
onDeregister: (info) => {
|
|
11372
|
+
const client = sessionBrokers.get(info.token);
|
|
11373
|
+
if (!client)
|
|
11374
|
+
return;
|
|
11375
|
+
sessionBrokers.delete(info.token);
|
|
11376
|
+
client.close().catch(() => {});
|
|
11377
|
+
}
|
|
11378
|
+
});
|
|
11379
|
+
startReaper();
|
|
10806
11380
|
const ipc2 = startIpcServer({
|
|
10807
11381
|
localToken,
|
|
10808
11382
|
tcpEnabled,
|
|
@@ -10845,6 +11419,12 @@ async function runDaemon(opts = {}) {
|
|
|
10845
11419
|
await b.close();
|
|
10846
11420
|
} catch {}
|
|
10847
11421
|
}
|
|
11422
|
+
for (const b of sessionBrokers.values()) {
|
|
11423
|
+
try {
|
|
11424
|
+
await b.close();
|
|
11425
|
+
} catch {}
|
|
11426
|
+
}
|
|
11427
|
+
sessionBrokers.clear();
|
|
10848
11428
|
await ipc2.close();
|
|
10849
11429
|
try {
|
|
10850
11430
|
outboxDb.close();
|
|
@@ -10864,7 +11444,9 @@ var init_run = __esm(() => {
|
|
|
10864
11444
|
init_lock();
|
|
10865
11445
|
init_local_token();
|
|
10866
11446
|
init_server();
|
|
11447
|
+
init_session_registry();
|
|
10867
11448
|
init_broker();
|
|
11449
|
+
init_session_broker();
|
|
10868
11450
|
init_drain();
|
|
10869
11451
|
init_inbound();
|
|
10870
11452
|
init_identity();
|
|
@@ -10879,7 +11461,7 @@ __export(exports_service_install, {
|
|
|
10879
11461
|
installService: () => installService,
|
|
10880
11462
|
detectPlatform: () => detectPlatform
|
|
10881
11463
|
});
|
|
10882
|
-
import { existsSync as
|
|
11464
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync11, unlinkSync as unlinkSync5, readFileSync as readFileSync11 } from "node:fs";
|
|
10883
11465
|
import { execSync as execSync2 } from "node:child_process";
|
|
10884
11466
|
import { homedir as homedir5 } from "node:os";
|
|
10885
11467
|
import { join as join8, dirname as dirname5 } from "node:path";
|
|
@@ -10900,7 +11482,7 @@ function installService(args) {
|
|
|
10900
11482
|
if (isCi() && !args.allowCi) {
|
|
10901
11483
|
throw new Error("Refusing to install persistent service in CI; pass --allow-ci-persistent to override.");
|
|
10902
11484
|
}
|
|
10903
|
-
if (!
|
|
11485
|
+
if (!existsSync12(args.binaryPath)) {
|
|
10904
11486
|
throw new Error(`binary not found at ${args.binaryPath}`);
|
|
10905
11487
|
}
|
|
10906
11488
|
mkdirSync7(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
|
|
@@ -10916,7 +11498,7 @@ function uninstallService() {
|
|
|
10916
11498
|
try {
|
|
10917
11499
|
execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL}`, { stdio: "ignore" });
|
|
10918
11500
|
} catch {}
|
|
10919
|
-
if (
|
|
11501
|
+
if (existsSync12(p)) {
|
|
10920
11502
|
unlinkSync5(p);
|
|
10921
11503
|
removed.push(p);
|
|
10922
11504
|
}
|
|
@@ -10925,7 +11507,7 @@ function uninstallService() {
|
|
|
10925
11507
|
try {
|
|
10926
11508
|
execSync2(`systemctl --user disable --now ${SYSTEMD_UNIT}`, { stdio: "ignore" });
|
|
10927
11509
|
} catch {}
|
|
10928
|
-
if (
|
|
11510
|
+
if (existsSync12(p)) {
|
|
10929
11511
|
unlinkSync5(p);
|
|
10930
11512
|
removed.push(p);
|
|
10931
11513
|
}
|
|
@@ -10978,7 +11560,7 @@ function installDarwin(args) {
|
|
|
10978
11560
|
</dict>
|
|
10979
11561
|
</plist>
|
|
10980
11562
|
`;
|
|
10981
|
-
|
|
11563
|
+
writeFileSync11(plist, xml, { mode: 420 });
|
|
10982
11564
|
return {
|
|
10983
11565
|
platform: "darwin",
|
|
10984
11566
|
unitPath: plist,
|
|
@@ -11015,7 +11597,7 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
|
|
11015
11597
|
[Install]
|
|
11016
11598
|
WantedBy=default.target
|
|
11017
11599
|
`;
|
|
11018
|
-
|
|
11600
|
+
writeFileSync11(unit, content, { mode: 420 });
|
|
11019
11601
|
return {
|
|
11020
11602
|
platform: "linux",
|
|
11021
11603
|
unitPath: unit,
|
|
@@ -11035,10 +11617,10 @@ function readInstalledUnit() {
|
|
|
11035
11617
|
if (!platform5)
|
|
11036
11618
|
return { platform: null, path: null, content: null };
|
|
11037
11619
|
const path2 = platform5 === "darwin" ? darwinPlistPath() : linuxUnitPath();
|
|
11038
|
-
if (!
|
|
11620
|
+
if (!existsSync12(path2))
|
|
11039
11621
|
return { platform: platform5, path: null, content: null };
|
|
11040
11622
|
try {
|
|
11041
|
-
return { platform: platform5, path: path2, content:
|
|
11623
|
+
return { platform: platform5, path: path2, content: readFileSync11(path2, "utf8") };
|
|
11042
11624
|
} catch {
|
|
11043
11625
|
return { platform: platform5, path: path2, content: null };
|
|
11044
11626
|
}
|
|
@@ -11380,19 +11962,19 @@ __export(exports_install, {
|
|
|
11380
11962
|
import {
|
|
11381
11963
|
chmodSync as chmodSync4,
|
|
11382
11964
|
copyFileSync,
|
|
11383
|
-
existsSync as
|
|
11965
|
+
existsSync as existsSync13,
|
|
11384
11966
|
mkdirSync as mkdirSync8,
|
|
11385
|
-
readFileSync as
|
|
11386
|
-
writeFileSync as
|
|
11967
|
+
readFileSync as readFileSync12,
|
|
11968
|
+
writeFileSync as writeFileSync12
|
|
11387
11969
|
} from "node:fs";
|
|
11388
11970
|
import { homedir as homedir6, platform as platform5 } from "node:os";
|
|
11389
11971
|
import { dirname as dirname6, join as join9, resolve } from "node:path";
|
|
11390
11972
|
import { fileURLToPath } from "node:url";
|
|
11391
11973
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
11392
11974
|
function readClaudeConfig() {
|
|
11393
|
-
if (!
|
|
11975
|
+
if (!existsSync13(CLAUDE_CONFIG))
|
|
11394
11976
|
return {};
|
|
11395
|
-
const text =
|
|
11977
|
+
const text = readFileSync12(CLAUDE_CONFIG, "utf-8").trim();
|
|
11396
11978
|
if (!text)
|
|
11397
11979
|
return {};
|
|
11398
11980
|
try {
|
|
@@ -11402,7 +11984,7 @@ function readClaudeConfig() {
|
|
|
11402
11984
|
}
|
|
11403
11985
|
}
|
|
11404
11986
|
function backupClaudeConfig() {
|
|
11405
|
-
if (!
|
|
11987
|
+
if (!existsSync13(CLAUDE_CONFIG))
|
|
11406
11988
|
return;
|
|
11407
11989
|
const backupDir = join9(dirname6(CLAUDE_CONFIG), ".claude", "backups");
|
|
11408
11990
|
mkdirSync8(backupDir, { recursive: true });
|
|
@@ -11431,7 +12013,7 @@ function patchMcpServer(entry) {
|
|
|
11431
12013
|
return action;
|
|
11432
12014
|
}
|
|
11433
12015
|
function removeMcpServer() {
|
|
11434
|
-
if (!
|
|
12016
|
+
if (!existsSync13(CLAUDE_CONFIG))
|
|
11435
12017
|
return false;
|
|
11436
12018
|
backupClaudeConfig();
|
|
11437
12019
|
const cfg = readClaudeConfig();
|
|
@@ -11445,7 +12027,7 @@ function removeMcpServer() {
|
|
|
11445
12027
|
}
|
|
11446
12028
|
function flushClaudeConfig(obj) {
|
|
11447
12029
|
mkdirSync8(dirname6(CLAUDE_CONFIG), { recursive: true });
|
|
11448
|
-
|
|
12030
|
+
writeFileSync12(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
|
|
11449
12031
|
`, "utf-8");
|
|
11450
12032
|
try {
|
|
11451
12033
|
chmodSync4(CLAUDE_CONFIG, 384);
|
|
@@ -11468,7 +12050,7 @@ function resolveBundledSkillsDir() {
|
|
|
11468
12050
|
const here = fileURLToPath(import.meta.url);
|
|
11469
12051
|
const pkgRoot = resolve(dirname6(here), "..", "..");
|
|
11470
12052
|
const skillsDir = join9(pkgRoot, "skills");
|
|
11471
|
-
if (
|
|
12053
|
+
if (existsSync13(skillsDir))
|
|
11472
12054
|
return skillsDir;
|
|
11473
12055
|
return null;
|
|
11474
12056
|
}
|
|
@@ -11503,7 +12085,7 @@ function uninstallSkills() {
|
|
|
11503
12085
|
if (!entry.isDirectory())
|
|
11504
12086
|
continue;
|
|
11505
12087
|
const dstDir = join9(CLAUDE_SKILLS_ROOT, entry.name);
|
|
11506
|
-
if (
|
|
12088
|
+
if (existsSync13(dstDir)) {
|
|
11507
12089
|
try {
|
|
11508
12090
|
fs.rmSync(dstDir, { recursive: true, force: true });
|
|
11509
12091
|
removed.push(entry.name);
|
|
@@ -11528,9 +12110,9 @@ function entriesEqual(a, b) {
|
|
|
11528
12110
|
return a.command === b.command && JSON.stringify(a.args ?? []) === JSON.stringify(b.args ?? []);
|
|
11529
12111
|
}
|
|
11530
12112
|
function readClaudeSettings() {
|
|
11531
|
-
if (!
|
|
12113
|
+
if (!existsSync13(CLAUDE_SETTINGS))
|
|
11532
12114
|
return {};
|
|
11533
|
-
const text =
|
|
12115
|
+
const text = readFileSync12(CLAUDE_SETTINGS, "utf-8").trim();
|
|
11534
12116
|
if (!text)
|
|
11535
12117
|
return {};
|
|
11536
12118
|
try {
|
|
@@ -11541,7 +12123,7 @@ function readClaudeSettings() {
|
|
|
11541
12123
|
}
|
|
11542
12124
|
function writeClaudeSettings(obj) {
|
|
11543
12125
|
mkdirSync8(dirname6(CLAUDE_SETTINGS), { recursive: true });
|
|
11544
|
-
|
|
12126
|
+
writeFileSync12(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
|
|
11545
12127
|
`, "utf-8");
|
|
11546
12128
|
}
|
|
11547
12129
|
function installAllowedTools() {
|
|
@@ -11555,7 +12137,7 @@ function installAllowedTools() {
|
|
|
11555
12137
|
return { added: toAdd, unchanged: CLAUDEMESH_TOOLS.length - toAdd.length };
|
|
11556
12138
|
}
|
|
11557
12139
|
function uninstallAllowedTools() {
|
|
11558
|
-
if (!
|
|
12140
|
+
if (!existsSync13(CLAUDE_SETTINGS))
|
|
11559
12141
|
return 0;
|
|
11560
12142
|
const settings = readClaudeSettings();
|
|
11561
12143
|
const existing = settings.allowedTools ?? [];
|
|
@@ -11570,11 +12152,11 @@ function uninstallAllowedTools() {
|
|
|
11570
12152
|
}
|
|
11571
12153
|
function installHooks() {
|
|
11572
12154
|
const settings = readClaudeSettings();
|
|
11573
|
-
const
|
|
12155
|
+
const hooks2 = (settings.hooks ??= {}) ?? {};
|
|
11574
12156
|
let added = 0;
|
|
11575
12157
|
let unchanged = 0;
|
|
11576
12158
|
const ensure = (event, command) => {
|
|
11577
|
-
const list =
|
|
12159
|
+
const list = hooks2[event] ??= [];
|
|
11578
12160
|
const alreadyPresent = list.some((entry) => (entry.hooks ?? []).some((h) => h.command === command));
|
|
11579
12161
|
if (alreadyPresent) {
|
|
11580
12162
|
unchanged += 1;
|
|
@@ -11585,32 +12167,32 @@ function installHooks() {
|
|
|
11585
12167
|
};
|
|
11586
12168
|
ensure("Stop", HOOK_COMMAND_STOP);
|
|
11587
12169
|
ensure("UserPromptSubmit", HOOK_COMMAND_USER_PROMPT);
|
|
11588
|
-
settings.hooks =
|
|
12170
|
+
settings.hooks = hooks2;
|
|
11589
12171
|
writeClaudeSettings(settings);
|
|
11590
12172
|
return { added, unchanged };
|
|
11591
12173
|
}
|
|
11592
12174
|
function uninstallHooks() {
|
|
11593
|
-
if (!
|
|
12175
|
+
if (!existsSync13(CLAUDE_SETTINGS))
|
|
11594
12176
|
return 0;
|
|
11595
12177
|
const settings = readClaudeSettings();
|
|
11596
|
-
const
|
|
11597
|
-
if (!
|
|
12178
|
+
const hooks2 = settings.hooks;
|
|
12179
|
+
if (!hooks2)
|
|
11598
12180
|
return 0;
|
|
11599
12181
|
let removed = 0;
|
|
11600
|
-
for (const event of Object.keys(
|
|
12182
|
+
for (const event of Object.keys(hooks2)) {
|
|
11601
12183
|
const kept = [];
|
|
11602
|
-
for (const entry of
|
|
12184
|
+
for (const entry of hooks2[event] ?? []) {
|
|
11603
12185
|
const filtered = (entry.hooks ?? []).filter((h) => !(h.command ?? "").includes(HOOK_MARKER));
|
|
11604
12186
|
removed += (entry.hooks ?? []).length - filtered.length;
|
|
11605
12187
|
if (filtered.length > 0)
|
|
11606
12188
|
kept.push({ ...entry, hooks: filtered });
|
|
11607
12189
|
}
|
|
11608
12190
|
if (kept.length === 0)
|
|
11609
|
-
delete
|
|
12191
|
+
delete hooks2[event];
|
|
11610
12192
|
else
|
|
11611
|
-
|
|
12193
|
+
hooks2[event] = kept;
|
|
11612
12194
|
}
|
|
11613
|
-
settings.hooks =
|
|
12195
|
+
settings.hooks = hooks2;
|
|
11614
12196
|
writeClaudeSettings(settings);
|
|
11615
12197
|
return removed;
|
|
11616
12198
|
}
|
|
@@ -11640,7 +12222,7 @@ function runInstall(args = []) {
|
|
|
11640
12222
|
render.err("`bun` is not on PATH.", "Install Bun first: https://bun.com");
|
|
11641
12223
|
process.exit(1);
|
|
11642
12224
|
}
|
|
11643
|
-
if (!
|
|
12225
|
+
if (!existsSync13(entry)) {
|
|
11644
12226
|
render.err(`MCP entry not found at ${entry}`);
|
|
11645
12227
|
process.exit(1);
|
|
11646
12228
|
}
|
|
@@ -11885,7 +12467,7 @@ var exports_uninstall = {};
|
|
|
11885
12467
|
__export(exports_uninstall, {
|
|
11886
12468
|
uninstall: () => uninstall
|
|
11887
12469
|
});
|
|
11888
|
-
import { readFileSync as
|
|
12470
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync14, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
|
|
11889
12471
|
import { join as join10, dirname as dirname7 } from "node:path";
|
|
11890
12472
|
import { homedir as homedir7 } from "node:os";
|
|
11891
12473
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -11893,32 +12475,32 @@ function bundledSkillsDir() {
|
|
|
11893
12475
|
const here = fileURLToPath2(import.meta.url);
|
|
11894
12476
|
const pkgRoot = join10(dirname7(here), "..", "..");
|
|
11895
12477
|
const skillsDir = join10(pkgRoot, "skills");
|
|
11896
|
-
return
|
|
12478
|
+
return existsSync14(skillsDir) ? skillsDir : null;
|
|
11897
12479
|
}
|
|
11898
12480
|
async function uninstall() {
|
|
11899
12481
|
let removed = 0;
|
|
11900
|
-
if (
|
|
12482
|
+
if (existsSync14(PATHS.CLAUDE_JSON)) {
|
|
11901
12483
|
try {
|
|
11902
|
-
const raw =
|
|
12484
|
+
const raw = readFileSync13(PATHS.CLAUDE_JSON, "utf-8");
|
|
11903
12485
|
const config = JSON.parse(raw);
|
|
11904
12486
|
const servers = config.mcpServers;
|
|
11905
12487
|
if (servers && "claudemesh" in servers) {
|
|
11906
12488
|
delete servers.claudemesh;
|
|
11907
|
-
|
|
12489
|
+
writeFileSync13(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
|
|
11908
12490
|
`, "utf-8");
|
|
11909
12491
|
render.ok("removed MCP server", dim("~/.claude.json"));
|
|
11910
12492
|
removed++;
|
|
11911
12493
|
}
|
|
11912
12494
|
} catch {}
|
|
11913
12495
|
}
|
|
11914
|
-
if (
|
|
12496
|
+
if (existsSync14(PATHS.CLAUDE_SETTINGS)) {
|
|
11915
12497
|
try {
|
|
11916
|
-
const raw =
|
|
12498
|
+
const raw = readFileSync13(PATHS.CLAUDE_SETTINGS, "utf-8");
|
|
11917
12499
|
const config = JSON.parse(raw);
|
|
11918
|
-
const
|
|
11919
|
-
if (
|
|
12500
|
+
const hooks2 = config.hooks;
|
|
12501
|
+
if (hooks2) {
|
|
11920
12502
|
let removedHooks = 0;
|
|
11921
|
-
for (const [event, entries] of Object.entries(
|
|
12503
|
+
for (const [event, entries] of Object.entries(hooks2)) {
|
|
11922
12504
|
if (!Array.isArray(entries))
|
|
11923
12505
|
continue;
|
|
11924
12506
|
const filtered = entries.filter((h) => {
|
|
@@ -11928,13 +12510,13 @@ async function uninstall() {
|
|
|
11928
12510
|
if (filtered.length < entries.length) {
|
|
11929
12511
|
removedHooks += entries.length - filtered.length;
|
|
11930
12512
|
if (filtered.length === 0)
|
|
11931
|
-
delete
|
|
12513
|
+
delete hooks2[event];
|
|
11932
12514
|
else
|
|
11933
|
-
|
|
12515
|
+
hooks2[event] = filtered;
|
|
11934
12516
|
}
|
|
11935
12517
|
}
|
|
11936
12518
|
if (removedHooks > 0) {
|
|
11937
|
-
|
|
12519
|
+
writeFileSync13(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
|
|
11938
12520
|
`, "utf-8");
|
|
11939
12521
|
render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
|
|
11940
12522
|
removed++;
|
|
@@ -11950,7 +12532,7 @@ async function uninstall() {
|
|
|
11950
12532
|
if (!entry.isDirectory())
|
|
11951
12533
|
continue;
|
|
11952
12534
|
const dst = join10(CLAUDE_SKILLS_ROOT2, entry.name);
|
|
11953
|
-
if (
|
|
12535
|
+
if (existsSync14(dst)) {
|
|
11954
12536
|
try {
|
|
11955
12537
|
rmSync2(dst, { recursive: true, force: true });
|
|
11956
12538
|
removedSkills.push(entry.name);
|
|
@@ -11982,7 +12564,7 @@ var exports_doctor = {};
|
|
|
11982
12564
|
__export(exports_doctor, {
|
|
11983
12565
|
runDoctor: () => runDoctor
|
|
11984
12566
|
});
|
|
11985
|
-
import { existsSync as
|
|
12567
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, statSync as statSync3 } from "node:fs";
|
|
11986
12568
|
import { homedir as homedir8, platform as platform6 } from "node:os";
|
|
11987
12569
|
import { join as join11 } from "node:path";
|
|
11988
12570
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
@@ -12009,7 +12591,7 @@ function checkClaudeOnPath() {
|
|
|
12009
12591
|
}
|
|
12010
12592
|
function checkMcpRegistered() {
|
|
12011
12593
|
const claudeConfig = join11(homedir8(), ".claude.json");
|
|
12012
|
-
if (!
|
|
12594
|
+
if (!existsSync15(claudeConfig)) {
|
|
12013
12595
|
return {
|
|
12014
12596
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
12015
12597
|
pass: false,
|
|
@@ -12017,7 +12599,7 @@ function checkMcpRegistered() {
|
|
|
12017
12599
|
};
|
|
12018
12600
|
}
|
|
12019
12601
|
try {
|
|
12020
|
-
const cfg = JSON.parse(
|
|
12602
|
+
const cfg = JSON.parse(readFileSync14(claudeConfig, "utf-8"));
|
|
12021
12603
|
const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
|
|
12022
12604
|
return {
|
|
12023
12605
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
@@ -12035,7 +12617,7 @@ function checkMcpRegistered() {
|
|
|
12035
12617
|
}
|
|
12036
12618
|
function checkHooksRegistered() {
|
|
12037
12619
|
const settings = join11(homedir8(), ".claude", "settings.json");
|
|
12038
|
-
if (!
|
|
12620
|
+
if (!existsSync15(settings)) {
|
|
12039
12621
|
return {
|
|
12040
12622
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
12041
12623
|
pass: false,
|
|
@@ -12043,7 +12625,7 @@ function checkHooksRegistered() {
|
|
|
12043
12625
|
};
|
|
12044
12626
|
}
|
|
12045
12627
|
try {
|
|
12046
|
-
const raw =
|
|
12628
|
+
const raw = readFileSync14(settings, "utf-8");
|
|
12047
12629
|
const has = raw.includes("claudemesh hook ");
|
|
12048
12630
|
return {
|
|
12049
12631
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
@@ -12060,7 +12642,7 @@ function checkHooksRegistered() {
|
|
|
12060
12642
|
}
|
|
12061
12643
|
function checkConfigFile() {
|
|
12062
12644
|
const path2 = getConfigPath();
|
|
12063
|
-
if (!
|
|
12645
|
+
if (!existsSync15(path2)) {
|
|
12064
12646
|
return {
|
|
12065
12647
|
name: "~/.claudemesh/config.json exists and parses",
|
|
12066
12648
|
pass: true,
|
|
@@ -12132,8 +12714,8 @@ async function checkBrokerWs() {
|
|
|
12132
12714
|
const wsUrl = URLS.BROKER;
|
|
12133
12715
|
const start = Date.now();
|
|
12134
12716
|
try {
|
|
12135
|
-
const
|
|
12136
|
-
const ws = new
|
|
12717
|
+
const WebSocket4 = (await import("ws")).default;
|
|
12718
|
+
const ws = new WebSocket4(wsUrl);
|
|
12137
12719
|
const result = await new Promise((resolve2) => {
|
|
12138
12720
|
const timer = setTimeout(() => {
|
|
12139
12721
|
try {
|
|
@@ -12243,12 +12825,12 @@ var exports_status = {};
|
|
|
12243
12825
|
__export(exports_status, {
|
|
12244
12826
|
runStatus: () => runStatus2
|
|
12245
12827
|
});
|
|
12246
|
-
import { statSync as statSync4, existsSync as
|
|
12247
|
-
import
|
|
12828
|
+
import { statSync as statSync4, existsSync as existsSync16 } from "node:fs";
|
|
12829
|
+
import WebSocket4 from "ws";
|
|
12248
12830
|
async function probeBroker(url, timeoutMs = 4000) {
|
|
12249
12831
|
return new Promise((resolve2) => {
|
|
12250
12832
|
const started = Date.now();
|
|
12251
|
-
const ws = new
|
|
12833
|
+
const ws = new WebSocket4(url);
|
|
12252
12834
|
const timer = setTimeout(() => {
|
|
12253
12835
|
try {
|
|
12254
12836
|
ws.terminate();
|
|
@@ -12273,7 +12855,7 @@ async function runStatus2() {
|
|
|
12273
12855
|
render.section(`status (v${VERSION})`);
|
|
12274
12856
|
const configPath = getConfigPath();
|
|
12275
12857
|
let configPermsNote = "missing";
|
|
12276
|
-
if (
|
|
12858
|
+
if (existsSync16(configPath)) {
|
|
12277
12859
|
const mode = (statSync4(configPath).mode & 511).toString(8).padStart(4, "0");
|
|
12278
12860
|
configPermsNote = mode === "0600" ? `${mode}` : `${mode} — expected 0600`;
|
|
12279
12861
|
}
|
|
@@ -12419,13 +13001,13 @@ var init_check_claude_binary = __esm(() => {
|
|
|
12419
13001
|
});
|
|
12420
13002
|
|
|
12421
13003
|
// src/services/health/check-mcp-registered.ts
|
|
12422
|
-
import { existsSync as
|
|
13004
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
|
|
12423
13005
|
function checkMcpRegistered2() {
|
|
12424
13006
|
try {
|
|
12425
|
-
if (!
|
|
13007
|
+
if (!existsSync17(PATHS.CLAUDE_JSON)) {
|
|
12426
13008
|
return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
|
|
12427
13009
|
}
|
|
12428
|
-
const raw =
|
|
13010
|
+
const raw = readFileSync15(PATHS.CLAUDE_JSON, "utf-8");
|
|
12429
13011
|
const config = JSON.parse(raw);
|
|
12430
13012
|
if (config.mcpServers && "claudemesh" in config.mcpServers) {
|
|
12431
13013
|
return { name: "mcp-registered", ok: true, message: "MCP server registered" };
|
|
@@ -12440,13 +13022,13 @@ var init_check_mcp_registered = __esm(() => {
|
|
|
12440
13022
|
});
|
|
12441
13023
|
|
|
12442
13024
|
// src/services/health/check-hooks-registered.ts
|
|
12443
|
-
import { existsSync as
|
|
13025
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
|
|
12444
13026
|
function checkHooksRegistered2() {
|
|
12445
13027
|
try {
|
|
12446
|
-
if (!
|
|
13028
|
+
if (!existsSync18(PATHS.CLAUDE_SETTINGS)) {
|
|
12447
13029
|
return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
|
|
12448
13030
|
}
|
|
12449
|
-
const raw =
|
|
13031
|
+
const raw = readFileSync16(PATHS.CLAUDE_SETTINGS, "utf-8");
|
|
12450
13032
|
const config = JSON.parse(raw);
|
|
12451
13033
|
if (config.hooks) {
|
|
12452
13034
|
return { name: "hooks-registered", ok: true, message: "Hooks configured" };
|
|
@@ -12461,10 +13043,10 @@ var init_check_hooks_registered = __esm(() => {
|
|
|
12461
13043
|
});
|
|
12462
13044
|
|
|
12463
13045
|
// src/services/health/check-config-perms.ts
|
|
12464
|
-
import { existsSync as
|
|
13046
|
+
import { existsSync as existsSync19, statSync as statSync5 } from "node:fs";
|
|
12465
13047
|
function checkConfigPerms() {
|
|
12466
13048
|
const configFile = PATHS.CONFIG_FILE;
|
|
12467
|
-
if (!
|
|
13049
|
+
if (!existsSync19(configFile)) {
|
|
12468
13050
|
return { name: "config-perms", ok: true, message: "No config file yet (first run)" };
|
|
12469
13051
|
}
|
|
12470
13052
|
try {
|
|
@@ -12482,13 +13064,13 @@ var init_check_config_perms = __esm(() => {
|
|
|
12482
13064
|
});
|
|
12483
13065
|
|
|
12484
13066
|
// src/services/health/check-keypairs-valid.ts
|
|
12485
|
-
import { existsSync as
|
|
13067
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
|
|
12486
13068
|
function checkKeypairsValid() {
|
|
12487
|
-
if (!
|
|
13069
|
+
if (!existsSync20(PATHS.CONFIG_FILE)) {
|
|
12488
13070
|
return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
|
|
12489
13071
|
}
|
|
12490
13072
|
try {
|
|
12491
|
-
const raw =
|
|
13073
|
+
const raw = readFileSync17(PATHS.CONFIG_FILE, "utf-8");
|
|
12492
13074
|
const config = JSON.parse(raw);
|
|
12493
13075
|
const meshes = config.meshes ?? [];
|
|
12494
13076
|
if (meshes.length === 0) {
|
|
@@ -12969,7 +13551,7 @@ __export(exports_url_handler, {
|
|
|
12969
13551
|
runUrlHandler: () => runUrlHandler
|
|
12970
13552
|
});
|
|
12971
13553
|
import { platform as platform7, homedir as homedir9 } from "node:os";
|
|
12972
|
-
import { existsSync as
|
|
13554
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
|
|
12973
13555
|
import { join as join12 } from "node:path";
|
|
12974
13556
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
12975
13557
|
function resolveClaudemeshBin() {
|
|
@@ -13003,7 +13585,7 @@ function installDarwin2() {
|
|
|
13003
13585
|
</array>
|
|
13004
13586
|
</dict>
|
|
13005
13587
|
</plist>`;
|
|
13006
|
-
|
|
13588
|
+
writeFileSync14(join12(contents, "Info.plist"), plist);
|
|
13007
13589
|
const shim = `#!/bin/sh
|
|
13008
13590
|
URL="$1"
|
|
13009
13591
|
CODE=\${URL#claudemesh://}
|
|
@@ -13018,7 +13600,7 @@ end tell
|
|
|
13018
13600
|
EOF
|
|
13019
13601
|
`;
|
|
13020
13602
|
const shimPath = join12(macOS, "open-url");
|
|
13021
|
-
|
|
13603
|
+
writeFileSync14(shimPath, shim);
|
|
13022
13604
|
chmodSync5(shimPath, 493);
|
|
13023
13605
|
const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
|
|
13024
13606
|
if (lsreg.status !== 0) {
|
|
@@ -13042,7 +13624,7 @@ MimeType=x-scheme-handler/claudemesh;
|
|
|
13042
13624
|
NoDisplay=true
|
|
13043
13625
|
`;
|
|
13044
13626
|
const desktopPath = join12(appsDir, "claudemesh.desktop");
|
|
13045
|
-
|
|
13627
|
+
writeFileSync14(desktopPath, desktop);
|
|
13046
13628
|
const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
|
|
13047
13629
|
if (xdg1.status !== 0) {
|
|
13048
13630
|
render.warn("xdg-mime not available — skipped mime default registration");
|
|
@@ -13065,7 +13647,7 @@ function installWindows() {
|
|
|
13065
13647
|
`@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
|
|
13066
13648
|
];
|
|
13067
13649
|
const regPath = join12(homedir9(), "claudemesh-handler.reg");
|
|
13068
|
-
|
|
13650
|
+
writeFileSync14(regPath, lines.join(`\r
|
|
13069
13651
|
`));
|
|
13070
13652
|
const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
|
|
13071
13653
|
if (res.status !== 0) {
|
|
@@ -13077,14 +13659,14 @@ function installWindows() {
|
|
|
13077
13659
|
}
|
|
13078
13660
|
function uninstallDarwin() {
|
|
13079
13661
|
const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
|
|
13080
|
-
if (
|
|
13662
|
+
if (existsSync21(appDir))
|
|
13081
13663
|
rmSync3(appDir, { recursive: true, force: true });
|
|
13082
13664
|
render.ok("removed claudemesh:// handler on macOS");
|
|
13083
13665
|
return EXIT.SUCCESS;
|
|
13084
13666
|
}
|
|
13085
13667
|
function uninstallLinux() {
|
|
13086
13668
|
const desktopPath = join12(homedir9(), ".local", "share", "applications", "claudemesh.desktop");
|
|
13087
|
-
if (
|
|
13669
|
+
if (existsSync21(desktopPath))
|
|
13088
13670
|
rmSync3(desktopPath, { force: true });
|
|
13089
13671
|
render.ok("removed claudemesh:// handler on Linux");
|
|
13090
13672
|
return EXIT.SUCCESS;
|
|
@@ -13129,7 +13711,7 @@ var exports_status_line = {};
|
|
|
13129
13711
|
__export(exports_status_line, {
|
|
13130
13712
|
runStatusLine: () => runStatusLine
|
|
13131
13713
|
});
|
|
13132
|
-
import { existsSync as
|
|
13714
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
|
|
13133
13715
|
import { join as join13 } from "node:path";
|
|
13134
13716
|
import { homedir as homedir10 } from "node:os";
|
|
13135
13717
|
async function runStatusLine() {
|
|
@@ -13141,9 +13723,9 @@ async function runStatusLine() {
|
|
|
13141
13723
|
}
|
|
13142
13724
|
const cachePath = join13(homedir10(), ".claudemesh", "peer-cache.json");
|
|
13143
13725
|
let cache = {};
|
|
13144
|
-
if (
|
|
13726
|
+
if (existsSync22(cachePath)) {
|
|
13145
13727
|
try {
|
|
13146
|
-
cache = JSON.parse(
|
|
13728
|
+
cache = JSON.parse(readFileSync18(cachePath, "utf-8"));
|
|
13147
13729
|
} catch {}
|
|
13148
13730
|
}
|
|
13149
13731
|
const pick = config.meshes[0];
|
|
@@ -13174,7 +13756,7 @@ __export(exports_backup, {
|
|
|
13174
13756
|
runRestore: () => runRestore,
|
|
13175
13757
|
runBackup: () => runBackup
|
|
13176
13758
|
});
|
|
13177
|
-
import { readFileSync as
|
|
13759
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, existsSync as existsSync23 } from "node:fs";
|
|
13178
13760
|
import { createInterface as createInterface11 } from "node:readline";
|
|
13179
13761
|
function readHidden(prompt5) {
|
|
13180
13762
|
return new Promise((resolve2) => {
|
|
@@ -13216,11 +13798,11 @@ async function deriveKey(pass, salt, s) {
|
|
|
13216
13798
|
}
|
|
13217
13799
|
async function runBackup(outPath) {
|
|
13218
13800
|
const configPath = getConfigPath();
|
|
13219
|
-
if (!
|
|
13801
|
+
if (!existsSync23(configPath)) {
|
|
13220
13802
|
console.error(" No config found — nothing to back up. Join a mesh first.");
|
|
13221
13803
|
return EXIT.NOT_FOUND;
|
|
13222
13804
|
}
|
|
13223
|
-
const plaintext =
|
|
13805
|
+
const plaintext = readFileSync19(configPath);
|
|
13224
13806
|
const pass = await readHidden(" Passphrase (min 12 chars): ");
|
|
13225
13807
|
if (pass.length < 12) {
|
|
13226
13808
|
console.error(" ✗ Passphrase too short.");
|
|
@@ -13238,7 +13820,7 @@ async function runBackup(outPath) {
|
|
|
13238
13820
|
const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
|
|
13239
13821
|
const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
|
|
13240
13822
|
const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
|
|
13241
|
-
|
|
13823
|
+
writeFileSync15(file, blob, { mode: 384 });
|
|
13242
13824
|
console.log(`
|
|
13243
13825
|
✓ Backup saved: ${file}`);
|
|
13244
13826
|
console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
|
|
@@ -13250,11 +13832,11 @@ async function runRestore(inPath) {
|
|
|
13250
13832
|
console.error(" Usage: claudemesh restore <backup-file>");
|
|
13251
13833
|
return EXIT.INVALID_ARGS;
|
|
13252
13834
|
}
|
|
13253
|
-
if (!
|
|
13835
|
+
if (!existsSync23(inPath)) {
|
|
13254
13836
|
console.error(` ✗ File not found: ${inPath}`);
|
|
13255
13837
|
return EXIT.NOT_FOUND;
|
|
13256
13838
|
}
|
|
13257
|
-
const blob =
|
|
13839
|
+
const blob = readFileSync19(inPath);
|
|
13258
13840
|
if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
|
|
13259
13841
|
console.error(" ✗ Not a claudemesh backup file (bad magic).");
|
|
13260
13842
|
return EXIT.INVALID_ARGS;
|
|
@@ -13273,12 +13855,12 @@ async function runRestore(inPath) {
|
|
|
13273
13855
|
return EXIT.INTERNAL_ERROR;
|
|
13274
13856
|
}
|
|
13275
13857
|
const configPath = getConfigPath();
|
|
13276
|
-
if (
|
|
13858
|
+
if (existsSync23(configPath)) {
|
|
13277
13859
|
const backupOld = `${configPath}.before-restore.${Date.now()}`;
|
|
13278
|
-
|
|
13860
|
+
writeFileSync15(backupOld, readFileSync19(configPath), { mode: 384 });
|
|
13279
13861
|
console.log(` ↻ Existing config saved to ${backupOld}`);
|
|
13280
13862
|
}
|
|
13281
|
-
|
|
13863
|
+
writeFileSync15(configPath, Buffer.from(plaintext), { mode: 384 });
|
|
13282
13864
|
console.log(`
|
|
13283
13865
|
✓ Config restored to ${configPath}`);
|
|
13284
13866
|
console.log(" Run `claudemesh list` to verify your meshes.\n");
|
|
@@ -13298,7 +13880,7 @@ __export(exports_upgrade, {
|
|
|
13298
13880
|
runUpgrade: () => runUpgrade
|
|
13299
13881
|
});
|
|
13300
13882
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
13301
|
-
import { existsSync as
|
|
13883
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
13302
13884
|
import { dirname as dirname8, join as join14, resolve as resolve2 } from "node:path";
|
|
13303
13885
|
async function latestVersion() {
|
|
13304
13886
|
try {
|
|
@@ -13313,14 +13895,14 @@ async function latestVersion() {
|
|
|
13313
13895
|
}
|
|
13314
13896
|
function findNpm() {
|
|
13315
13897
|
const portable = join14(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
|
|
13316
|
-
if (
|
|
13898
|
+
if (existsSync24(portable)) {
|
|
13317
13899
|
return { npm: portable, prefix: join14(process.env.HOME ?? "", ".claudemesh") };
|
|
13318
13900
|
}
|
|
13319
13901
|
let cur = resolve2(process.argv[1] ?? ".");
|
|
13320
13902
|
for (let i = 0;i < 6; i++) {
|
|
13321
13903
|
cur = dirname8(cur);
|
|
13322
13904
|
const candidate = join14(cur, "bin", "npm");
|
|
13323
|
-
if (
|
|
13905
|
+
if (existsSync24(candidate))
|
|
13324
13906
|
return { npm: candidate };
|
|
13325
13907
|
}
|
|
13326
13908
|
return { npm: "npm" };
|
|
@@ -13382,7 +13964,7 @@ __export(exports_grants, {
|
|
|
13382
13964
|
runBlock: () => runBlock,
|
|
13383
13965
|
isAllowed: () => isAllowed
|
|
13384
13966
|
});
|
|
13385
|
-
import { existsSync as
|
|
13967
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "node:fs";
|
|
13386
13968
|
import { homedir as homedir11 } from "node:os";
|
|
13387
13969
|
import { join as join15 } from "node:path";
|
|
13388
13970
|
async function syncToBroker(meshSlug, grants) {
|
|
@@ -13402,19 +13984,19 @@ async function syncToBroker(meshSlug, grants) {
|
|
|
13402
13984
|
}
|
|
13403
13985
|
}
|
|
13404
13986
|
function readGrants() {
|
|
13405
|
-
if (!
|
|
13987
|
+
if (!existsSync25(GRANT_FILE))
|
|
13406
13988
|
return {};
|
|
13407
13989
|
try {
|
|
13408
|
-
return JSON.parse(
|
|
13990
|
+
return JSON.parse(readFileSync20(GRANT_FILE, "utf-8"));
|
|
13409
13991
|
} catch {
|
|
13410
13992
|
return {};
|
|
13411
13993
|
}
|
|
13412
13994
|
}
|
|
13413
13995
|
function writeGrants(g) {
|
|
13414
13996
|
const dir = join15(homedir11(), ".claudemesh");
|
|
13415
|
-
if (!
|
|
13997
|
+
if (!existsSync25(dir))
|
|
13416
13998
|
mkdirSync10(dir, { recursive: true });
|
|
13417
|
-
|
|
13999
|
+
writeFileSync16(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
|
|
13418
14000
|
}
|
|
13419
14001
|
function resolveCaps(input) {
|
|
13420
14002
|
if (input.includes("all"))
|
|
@@ -14269,17 +14851,17 @@ async function runUnwatch(id, opts) {
|
|
|
14269
14851
|
}
|
|
14270
14852
|
async function runWebhookList(opts) {
|
|
14271
14853
|
return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
14272
|
-
const
|
|
14854
|
+
const hooks2 = await client.listWebhooks();
|
|
14273
14855
|
if (opts.json) {
|
|
14274
|
-
emitJson(
|
|
14856
|
+
emitJson(hooks2);
|
|
14275
14857
|
return EXIT.SUCCESS;
|
|
14276
14858
|
}
|
|
14277
|
-
if (
|
|
14859
|
+
if (hooks2.length === 0) {
|
|
14278
14860
|
render.info(dim("(no webhooks)"));
|
|
14279
14861
|
return EXIT.SUCCESS;
|
|
14280
14862
|
}
|
|
14281
|
-
render.section(`webhooks (${
|
|
14282
|
-
for (const h of
|
|
14863
|
+
render.section(`webhooks (${hooks2.length})`);
|
|
14864
|
+
for (const h of hooks2) {
|
|
14283
14865
|
const dot = h.active ? "●" : dim("○");
|
|
14284
14866
|
process.stdout.write(` ${dot} ${bold(h.name)} ${dim("· " + h.url)}
|
|
14285
14867
|
`);
|
|
@@ -15250,9 +15832,9 @@ __export(exports_file, {
|
|
|
15250
15832
|
runFileShare: () => runFileShare,
|
|
15251
15833
|
runFileGet: () => runFileGet
|
|
15252
15834
|
});
|
|
15253
|
-
import { hostname as
|
|
15835
|
+
import { hostname as osHostname2 } from "node:os";
|
|
15254
15836
|
import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
|
|
15255
|
-
import { statSync as statSync7, existsSync as
|
|
15837
|
+
import { statSync as statSync7, existsSync as existsSync26, writeFileSync as writeFileSync17, mkdirSync as mkdirSync11 } from "node:fs";
|
|
15256
15838
|
function emitJson2(data) {
|
|
15257
15839
|
console.log(JSON.stringify(data, null, 2));
|
|
15258
15840
|
}
|
|
@@ -15269,7 +15851,7 @@ async function runFileShare(filePath, opts) {
|
|
|
15269
15851
|
return EXIT.INVALID_ARGS;
|
|
15270
15852
|
}
|
|
15271
15853
|
const absPath = resolvePath(filePath);
|
|
15272
|
-
if (!
|
|
15854
|
+
if (!existsSync26(absPath)) {
|
|
15273
15855
|
render.err(`File not found: ${absPath}`);
|
|
15274
15856
|
return EXIT.INVALID_ARGS;
|
|
15275
15857
|
}
|
|
@@ -15282,7 +15864,7 @@ async function runFileShare(filePath, opts) {
|
|
|
15282
15864
|
return await withMesh({ meshSlug: opts.mesh ?? null }, async (client, mesh) => {
|
|
15283
15865
|
if (opts.to && !opts.upload) {
|
|
15284
15866
|
const peers = await client.listPeers();
|
|
15285
|
-
const myHost =
|
|
15867
|
+
const myHost = osHostname2();
|
|
15286
15868
|
const target = peers.find((p) => {
|
|
15287
15869
|
if (!p.hostname || p.hostname !== myHost)
|
|
15288
15870
|
return false;
|
|
@@ -15349,7 +15931,7 @@ async function runFileGet(fileId, opts) {
|
|
|
15349
15931
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
15350
15932
|
const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
|
|
15351
15933
|
mkdirSync11(dirname9(outPath), { recursive: true });
|
|
15352
|
-
|
|
15934
|
+
writeFileSync17(outPath, buf);
|
|
15353
15935
|
if (opts.json) {
|
|
15354
15936
|
emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
|
|
15355
15937
|
} else {
|
|
@@ -15444,7 +16026,7 @@ var require_client = __commonJS((exports) => {
|
|
|
15444
16026
|
var ws_1 = __importDefault(__require("ws"));
|
|
15445
16027
|
var crypto_js_1 = require_crypto();
|
|
15446
16028
|
var MAX_QUEUED2 = 100;
|
|
15447
|
-
var
|
|
16029
|
+
var HELLO_ACK_TIMEOUT_MS4 = 5000;
|
|
15448
16030
|
var BACKOFF_CAPS2 = [1000, 2000, 4000, 8000, 16000, 30000];
|
|
15449
16031
|
|
|
15450
16032
|
class MeshClient extends node_events_1.EventEmitter {
|
|
@@ -15509,7 +16091,7 @@ var require_client = __commonJS((exports) => {
|
|
|
15509
16091
|
this.debug("hello_ack timeout");
|
|
15510
16092
|
ws.close();
|
|
15511
16093
|
reject(new Error("hello_ack timeout"));
|
|
15512
|
-
},
|
|
16094
|
+
}, HELLO_ACK_TIMEOUT_MS4);
|
|
15513
16095
|
};
|
|
15514
16096
|
const onMessage = (raw) => {
|
|
15515
16097
|
let msg;
|
|
@@ -15959,7 +16541,7 @@ __export(exports_bridge, {
|
|
|
15959
16541
|
runBridge: () => runBridge,
|
|
15960
16542
|
bridgeConfigTemplate: () => bridgeConfigTemplate
|
|
15961
16543
|
});
|
|
15962
|
-
import { readFileSync as
|
|
16544
|
+
import { readFileSync as readFileSync21, existsSync as existsSync27 } from "node:fs";
|
|
15963
16545
|
function parseConfig(text) {
|
|
15964
16546
|
const trimmed = text.trim();
|
|
15965
16547
|
if (trimmed.startsWith("{"))
|
|
@@ -16003,13 +16585,13 @@ async function runBridge(configPath) {
|
|
|
16003
16585
|
render.err("Usage: claudemesh bridge run <config.yaml>");
|
|
16004
16586
|
return EXIT.INVALID_ARGS;
|
|
16005
16587
|
}
|
|
16006
|
-
if (!
|
|
16588
|
+
if (!existsSync27(configPath)) {
|
|
16007
16589
|
render.err(`config file not found: ${configPath}`);
|
|
16008
16590
|
return EXIT.NOT_FOUND;
|
|
16009
16591
|
}
|
|
16010
16592
|
let cfg;
|
|
16011
16593
|
try {
|
|
16012
|
-
cfg = parseConfig(
|
|
16594
|
+
cfg = parseConfig(readFileSync21(configPath, "utf-8"));
|
|
16013
16595
|
} catch (e) {
|
|
16014
16596
|
render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
16015
16597
|
return EXIT.INVALID_ARGS;
|
|
@@ -16413,9 +16995,9 @@ function cacheKey(apiKeySecret, topicName) {
|
|
|
16413
16995
|
async function getTopicKey(args) {
|
|
16414
16996
|
const cacheId = cacheKey(args.apiKeySecret, args.topicName);
|
|
16415
16997
|
if (!args.fresh) {
|
|
16416
|
-
const
|
|
16417
|
-
if (
|
|
16418
|
-
return { ok: true, topicKey:
|
|
16998
|
+
const cached3 = cache.get(cacheId);
|
|
16999
|
+
if (cached3)
|
|
17000
|
+
return { ok: true, topicKey: cached3.topicKey };
|
|
16419
17001
|
}
|
|
16420
17002
|
let sealed;
|
|
16421
17003
|
try {
|
|
@@ -16983,11 +17565,11 @@ import {
|
|
|
16983
17565
|
ListResourcesRequestSchema,
|
|
16984
17566
|
ReadResourceRequestSchema
|
|
16985
17567
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
16986
|
-
import { existsSync as
|
|
17568
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
16987
17569
|
import { request as httpRequest2 } from "node:http";
|
|
16988
17570
|
async function daemonReady() {
|
|
16989
17571
|
for (let i = 0;i < DAEMON_BOOT_RETRIES; i++) {
|
|
16990
|
-
if (
|
|
17572
|
+
if (existsSync28(DAEMON_PATHS.SOCK_FILE))
|
|
16991
17573
|
return true;
|
|
16992
17574
|
await new Promise((r) => setTimeout(r, DAEMON_BOOT_RETRY_MS));
|
|
16993
17575
|
}
|
|
@@ -17317,9 +17899,9 @@ async function startServiceProxy(serviceName) {
|
|
|
17317
17899
|
const fetched = await client.getServiceTools(serviceName);
|
|
17318
17900
|
tools = fetched;
|
|
17319
17901
|
} catch {
|
|
17320
|
-
const
|
|
17321
|
-
if (
|
|
17322
|
-
tools =
|
|
17902
|
+
const cached3 = client.serviceCatalog.find((s) => s.name === serviceName);
|
|
17903
|
+
if (cached3)
|
|
17904
|
+
tools = cached3.tools;
|
|
17323
17905
|
}
|
|
17324
17906
|
if (tools.length === 0) {
|
|
17325
17907
|
process.stderr.write(`[mesh:${serviceName}] no tools found — service may not be running
|
|
@@ -19289,4 +19871,4 @@ main().catch((err) => {
|
|
|
19289
19871
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
19290
19872
|
});
|
|
19291
19873
|
|
|
19292
|
-
//# debugId=
|
|
19874
|
+
//# debugId=A7687DD2912DA01C64756E2164756E21
|