claudemesh-cli 1.27.3 → 1.29.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 +476 -352
- package/dist/entrypoints/cli.js.map +18 -16
- package/dist/entrypoints/mcp.js +2 -2
- package/dist/entrypoints/mcp.js.map +1 -1
- package/package.json +1 -1
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.
|
|
106
|
+
var URLS, VERSION = "1.29.0", env;
|
|
107
107
|
var init_urls = __esm(() => {
|
|
108
108
|
URLS = {
|
|
109
109
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -150,6 +150,32 @@ function normaliseInviteUrl(input, host = "claudemesh.com") {
|
|
|
150
150
|
return trimmed;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
// src/services/daemon/policy.ts
|
|
154
|
+
function readEnvDefault() {
|
|
155
|
+
if (process.env.CLAUDEMESH_NO_DAEMON === "1")
|
|
156
|
+
return { mode: "no-daemon" };
|
|
157
|
+
if (process.env.CLAUDEMESH_STRICT_DAEMON === "1")
|
|
158
|
+
return { mode: "strict" };
|
|
159
|
+
return { mode: "auto" };
|
|
160
|
+
}
|
|
161
|
+
function setDaemonPolicy(mode) {
|
|
162
|
+
policy = { mode };
|
|
163
|
+
}
|
|
164
|
+
function getDaemonPolicy() {
|
|
165
|
+
return policy;
|
|
166
|
+
}
|
|
167
|
+
function policyFromFlags(flags) {
|
|
168
|
+
if (flags["no-daemon"])
|
|
169
|
+
return "no-daemon";
|
|
170
|
+
if (flags.strict)
|
|
171
|
+
return "strict";
|
|
172
|
+
return readEnvDefault().mode;
|
|
173
|
+
}
|
|
174
|
+
var policy;
|
|
175
|
+
var init_policy = __esm(() => {
|
|
176
|
+
policy = readEnvDefault();
|
|
177
|
+
});
|
|
178
|
+
|
|
153
179
|
// src/constants/paths.ts
|
|
154
180
|
import { homedir as homedir2 } from "node:os";
|
|
155
181
|
import { join as join2 } from "node:path";
|
|
@@ -3642,7 +3668,50 @@ var init_local_token = __esm(() => {
|
|
|
3642
3668
|
init_paths2();
|
|
3643
3669
|
});
|
|
3644
3670
|
|
|
3671
|
+
// src/services/session/token.ts
|
|
3672
|
+
var exports_token = {};
|
|
3673
|
+
__export(exports_token, {
|
|
3674
|
+
readSessionTokenFromEnv: () => readSessionTokenFromEnv,
|
|
3675
|
+
mintSessionToken: () => mintSessionToken,
|
|
3676
|
+
TOKEN_FILE_ENV: () => TOKEN_FILE_ENV
|
|
3677
|
+
});
|
|
3678
|
+
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
3679
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
3680
|
+
function mintSessionToken(dir, fileName = "session-token") {
|
|
3681
|
+
const token = randomBytes5(32).toString("hex");
|
|
3682
|
+
const filePath = `${dir}/${fileName}`;
|
|
3683
|
+
writeFileSync5(filePath, token, { mode: 384 });
|
|
3684
|
+
return { token, filePath };
|
|
3685
|
+
}
|
|
3686
|
+
function readSessionTokenFromEnv(env2 = process.env) {
|
|
3687
|
+
const direct = env2.CLAUDEMESH_IPC_TOKEN;
|
|
3688
|
+
if (direct && /^[0-9a-f]{64}$/i.test(direct))
|
|
3689
|
+
return direct.toLowerCase();
|
|
3690
|
+
const path = env2[ENV_TOKEN_FILE];
|
|
3691
|
+
if (!path)
|
|
3692
|
+
return null;
|
|
3693
|
+
try {
|
|
3694
|
+
if (!existsSync5(path))
|
|
3695
|
+
return null;
|
|
3696
|
+
const raw = readFileSync5(path, "utf8").trim();
|
|
3697
|
+
if (/^[0-9a-f]{64}$/i.test(raw))
|
|
3698
|
+
return raw.toLowerCase();
|
|
3699
|
+
return null;
|
|
3700
|
+
} catch {
|
|
3701
|
+
return null;
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
var ENV_TOKEN_FILE = "CLAUDEMESH_IPC_TOKEN_FILE", TOKEN_FILE_ENV;
|
|
3705
|
+
var init_token = __esm(() => {
|
|
3706
|
+
TOKEN_FILE_ENV = ENV_TOKEN_FILE;
|
|
3707
|
+
});
|
|
3708
|
+
|
|
3645
3709
|
// src/daemon/ipc/client.ts
|
|
3710
|
+
var exports_client = {};
|
|
3711
|
+
__export(exports_client, {
|
|
3712
|
+
ipc: () => ipc,
|
|
3713
|
+
IpcError: () => IpcError
|
|
3714
|
+
});
|
|
3646
3715
|
import { request as httpRequest } from "node:http";
|
|
3647
3716
|
async function ipc(opts) {
|
|
3648
3717
|
const useTcp = !!opts.preferTcp;
|
|
@@ -3662,6 +3731,11 @@ async function ipc(opts) {
|
|
|
3662
3731
|
throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
|
|
3663
3732
|
headers.authorization = `Bearer ${tok}`;
|
|
3664
3733
|
}
|
|
3734
|
+
if (!useTcp) {
|
|
3735
|
+
const sessionTok = readSessionTokenFromEnv();
|
|
3736
|
+
if (sessionTok)
|
|
3737
|
+
headers.authorization = `ClaudeMesh-Session ${sessionTok}`;
|
|
3738
|
+
}
|
|
3665
3739
|
return new Promise((resolve, reject) => {
|
|
3666
3740
|
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
3741
|
const chunks = [];
|
|
@@ -3686,6 +3760,7 @@ var IpcError;
|
|
|
3686
3760
|
var init_client3 = __esm(() => {
|
|
3687
3761
|
init_paths2();
|
|
3688
3762
|
init_local_token();
|
|
3763
|
+
init_token();
|
|
3689
3764
|
IpcError = class IpcError extends Error {
|
|
3690
3765
|
status;
|
|
3691
3766
|
payload;
|
|
@@ -3703,7 +3778,7 @@ __export(exports_lifecycle, {
|
|
|
3703
3778
|
ensureDaemonReady: () => ensureDaemonReady,
|
|
3704
3779
|
_resetDaemonReadyCache: () => _resetDaemonReadyCache
|
|
3705
3780
|
});
|
|
3706
|
-
import { existsSync as
|
|
3781
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
3707
3782
|
import { join as join4 } from "node:path";
|
|
3708
3783
|
async function ensureDaemonReady(opts = {}) {
|
|
3709
3784
|
if (lastResultThisProcess && (lastResultThisProcess.state === "up" || lastResultThisProcess.state === "started")) {
|
|
@@ -3744,7 +3819,7 @@ async function runEnsureDaemon(opts) {
|
|
|
3744
3819
|
return { state: "spawn-failed", durationMs: Date.now() - t0, reason: spawnRes.reason };
|
|
3745
3820
|
}
|
|
3746
3821
|
async function probeDaemon() {
|
|
3747
|
-
if (!
|
|
3822
|
+
if (!existsSync6(DAEMON_PATHS.SOCK_FILE))
|
|
3748
3823
|
return "absent";
|
|
3749
3824
|
try {
|
|
3750
3825
|
const res = await ipc({ path: "/v1/version", timeoutMs: PROBE_TIMEOUT_MS });
|
|
@@ -3777,7 +3852,7 @@ function recentSpawnFailureFresh() {
|
|
|
3777
3852
|
}
|
|
3778
3853
|
function markSpawnFailure() {
|
|
3779
3854
|
try {
|
|
3780
|
-
|
|
3855
|
+
writeFileSync6(SPAWN_FAIL_FILE(), String(Date.now()), { mode: 384 });
|
|
3781
3856
|
} catch {}
|
|
3782
3857
|
}
|
|
3783
3858
|
function clearSpawnFailure() {
|
|
@@ -3814,9 +3889,9 @@ async function spawnDaemon(opts) {
|
|
|
3814
3889
|
}
|
|
3815
3890
|
async function acquireOrShareLock(_opts) {
|
|
3816
3891
|
const lockPath = SPAWN_LOCK_FILE();
|
|
3817
|
-
if (
|
|
3892
|
+
if (existsSync6(lockPath)) {
|
|
3818
3893
|
try {
|
|
3819
|
-
const pidStr =
|
|
3894
|
+
const pidStr = readFileSync6(lockPath, "utf8").trim();
|
|
3820
3895
|
const pid = Number.parseInt(pidStr, 10);
|
|
3821
3896
|
if (Number.isFinite(pid) && pid > 0) {
|
|
3822
3897
|
try {
|
|
@@ -3827,7 +3902,7 @@ async function acquireOrShareLock(_opts) {
|
|
|
3827
3902
|
} catch {}
|
|
3828
3903
|
}
|
|
3829
3904
|
try {
|
|
3830
|
-
|
|
3905
|
+
writeFileSync6(lockPath, String(process.pid), { mode: 384 });
|
|
3831
3906
|
} catch {}
|
|
3832
3907
|
return "acquired";
|
|
3833
3908
|
}
|
|
@@ -3839,7 +3914,7 @@ function releaseLock() {
|
|
|
3839
3914
|
async function pollForSocket(budgetMs) {
|
|
3840
3915
|
const start = Date.now();
|
|
3841
3916
|
while (Date.now() - start < budgetMs) {
|
|
3842
|
-
if (
|
|
3917
|
+
if (existsSync6(DAEMON_PATHS.SOCK_FILE)) {
|
|
3843
3918
|
const probe = await probeDaemon();
|
|
3844
3919
|
if (probe === "up")
|
|
3845
3920
|
return { ok: true };
|
|
@@ -3873,7 +3948,7 @@ __export(exports_launch, {
|
|
|
3873
3948
|
});
|
|
3874
3949
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
3875
3950
|
import { randomUUID } from "node:crypto";
|
|
3876
|
-
import { mkdtempSync, writeFileSync as
|
|
3951
|
+
import { mkdtempSync, writeFileSync as writeFileSync7, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
3877
3952
|
import { tmpdir, hostname as hostname2, homedir as homedir3 } from "node:os";
|
|
3878
3953
|
import { join as join5 } from "node:path";
|
|
3879
3954
|
import { createInterface as createInterface4 } from "node:readline";
|
|
@@ -4222,8 +4297,8 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4222
4297
|
await ensureDaemonRunning(mesh.slug, args.quiet);
|
|
4223
4298
|
try {
|
|
4224
4299
|
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4225
|
-
if (
|
|
4226
|
-
const claudeConfig = JSON.parse(
|
|
4300
|
+
if (existsSync7(claudeConfigPath)) {
|
|
4301
|
+
const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
|
|
4227
4302
|
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
4228
4303
|
let cleaned = 0;
|
|
4229
4304
|
for (const key of Object.keys(mcpServers)) {
|
|
@@ -4241,7 +4316,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4241
4316
|
}
|
|
4242
4317
|
if (cleaned > 0) {
|
|
4243
4318
|
claudeConfig.mcpServers = mcpServers;
|
|
4244
|
-
|
|
4319
|
+
writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4245
4320
|
`, "utf-8");
|
|
4246
4321
|
}
|
|
4247
4322
|
}
|
|
@@ -4267,8 +4342,37 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4267
4342
|
...parsedGroups.length > 0 ? { groups: parsedGroups } : {},
|
|
4268
4343
|
messageMode
|
|
4269
4344
|
};
|
|
4270
|
-
|
|
4345
|
+
writeFileSync7(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
|
|
4271
4346
|
`, "utf-8");
|
|
4347
|
+
let sessionTokenFilePath = null;
|
|
4348
|
+
let sessionTokenForCleanup = null;
|
|
4349
|
+
try {
|
|
4350
|
+
const { mintSessionToken: mintSessionToken2, TOKEN_FILE_ENV: TOKEN_FILE_ENV2 } = await Promise.resolve().then(() => (init_token(), exports_token));
|
|
4351
|
+
const minted = mintSessionToken2(tmpDir);
|
|
4352
|
+
sessionTokenFilePath = minted.filePath;
|
|
4353
|
+
sessionTokenForCleanup = minted.token;
|
|
4354
|
+
const { ipc: ipc2 } = await Promise.resolve().then(() => (init_client3(), exports_client));
|
|
4355
|
+
const sessionIdForRegister = claudeSessionId ?? randomUUID();
|
|
4356
|
+
await ipc2({
|
|
4357
|
+
method: "POST",
|
|
4358
|
+
path: "/v1/sessions/register",
|
|
4359
|
+
timeoutMs: 3000,
|
|
4360
|
+
body: {
|
|
4361
|
+
token: minted.token,
|
|
4362
|
+
session_id: sessionIdForRegister,
|
|
4363
|
+
mesh: mesh.slug,
|
|
4364
|
+
display_name: displayName,
|
|
4365
|
+
pid: process.pid,
|
|
4366
|
+
cwd: process.cwd(),
|
|
4367
|
+
...role ? { role } : {},
|
|
4368
|
+
...parsedGroups.length > 0 ? { groups: parsedGroups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`) } : {}
|
|
4369
|
+
}
|
|
4370
|
+
}).catch(() => null);
|
|
4371
|
+
process._claudemeshTokenEnv = {
|
|
4372
|
+
name: TOKEN_FILE_ENV2,
|
|
4373
|
+
value: minted.filePath
|
|
4374
|
+
};
|
|
4375
|
+
} catch {}
|
|
4272
4376
|
if (!args.quiet) {
|
|
4273
4377
|
printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
|
|
4274
4378
|
}
|
|
@@ -4277,7 +4381,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4277
4381
|
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4278
4382
|
let claudeConfig = {};
|
|
4279
4383
|
try {
|
|
4280
|
-
claudeConfig = JSON.parse(
|
|
4384
|
+
claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
|
|
4281
4385
|
} catch {
|
|
4282
4386
|
claudeConfig = {};
|
|
4283
4387
|
}
|
|
@@ -4304,7 +4408,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4304
4408
|
meshMcpEntries.push({ key: entryKey, entry });
|
|
4305
4409
|
}
|
|
4306
4410
|
claudeConfig.mcpServers = mcpServers;
|
|
4307
|
-
|
|
4411
|
+
writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4308
4412
|
`, "utf-8");
|
|
4309
4413
|
if (!args.quiet && meshMcpEntries.length > 0) {
|
|
4310
4414
|
console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
|
|
@@ -4346,7 +4450,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4346
4450
|
join5(homedir3(), ".claude", "bin", "claude")
|
|
4347
4451
|
];
|
|
4348
4452
|
for (const c of candidates) {
|
|
4349
|
-
if (
|
|
4453
|
+
if (existsSync7(c)) {
|
|
4350
4454
|
claudeBin = c;
|
|
4351
4455
|
break;
|
|
4352
4456
|
}
|
|
@@ -4356,13 +4460,13 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4356
4460
|
if (meshMcpEntries.length > 0) {
|
|
4357
4461
|
try {
|
|
4358
4462
|
const claudeConfigPath = join5(homedir3(), ".claude.json");
|
|
4359
|
-
const claudeConfig = JSON.parse(
|
|
4463
|
+
const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
|
|
4360
4464
|
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
4361
4465
|
for (const { key } of meshMcpEntries) {
|
|
4362
4466
|
delete mcpServers[key];
|
|
4363
4467
|
}
|
|
4364
4468
|
claudeConfig.mcpServers = mcpServers;
|
|
4365
|
-
|
|
4469
|
+
writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
4366
4470
|
`, "utf-8");
|
|
4367
4471
|
} catch {}
|
|
4368
4472
|
}
|
|
@@ -4392,6 +4496,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
4392
4496
|
CLAUDEMESH_CONFIG_DIR: tmpDir,
|
|
4393
4497
|
CLAUDEMESH_DISPLAY_NAME: displayName,
|
|
4394
4498
|
...claudeSessionId ? { CLAUDEMESH_SESSION_ID: claudeSessionId } : {},
|
|
4499
|
+
...sessionTokenFilePath ? { CLAUDEMESH_IPC_TOKEN_FILE: sessionTokenFilePath } : {},
|
|
4395
4500
|
MCP_TIMEOUT: process.env.MCP_TIMEOUT ?? "30000",
|
|
4396
4501
|
MAX_MCP_OUTPUT_TOKENS: process.env.MAX_MCP_OUTPUT_TOKENS ?? "50000",
|
|
4397
4502
|
...role ? { CLAUDEMESH_ROLE: role } : {}
|
|
@@ -5059,7 +5164,7 @@ __export(exports_join, {
|
|
|
5059
5164
|
runJoin: () => runJoin
|
|
5060
5165
|
});
|
|
5061
5166
|
import sodium3 from "libsodium-wrappers";
|
|
5062
|
-
import { writeFileSync as
|
|
5167
|
+
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "node:fs";
|
|
5063
5168
|
import { join as join6, dirname as dirname3 } from "node:path";
|
|
5064
5169
|
import { homedir as homedir4, hostname as hostname3 } from "node:os";
|
|
5065
5170
|
function deriveAppBaseUrl() {
|
|
@@ -5184,7 +5289,7 @@ async function runJoin(args) {
|
|
|
5184
5289
|
const inviteFile = join6(configDir, `invite-${payload.mesh_slug}.txt`);
|
|
5185
5290
|
try {
|
|
5186
5291
|
mkdirSync4(dirname3(inviteFile), { recursive: true });
|
|
5187
|
-
|
|
5292
|
+
writeFileSync8(inviteFile, link, "utf-8");
|
|
5188
5293
|
} catch {}
|
|
5189
5294
|
console.log("");
|
|
5190
5295
|
console.log(`✓ Joined "${payload.mesh_slug}" as ${displayName}${enroll.alreadyMember ? " (already a member — re-enrolled with same pubkey)" : ""}`);
|
|
@@ -6699,6 +6804,12 @@ async function pickMesh(meshes) {
|
|
|
6699
6804
|
});
|
|
6700
6805
|
}
|
|
6701
6806
|
async function withMesh(opts, fn) {
|
|
6807
|
+
if (getDaemonPolicy().mode === "strict") {
|
|
6808
|
+
console.error(`
|
|
6809
|
+
✘ daemon not reachable — --strict refuses cold-path fallback.
|
|
6810
|
+
` + " run `claudemesh daemon up` (or `claudemesh doctor`) and retry.\n");
|
|
6811
|
+
process.exit(1);
|
|
6812
|
+
}
|
|
6702
6813
|
const config = readConfig();
|
|
6703
6814
|
if (config.meshes.length === 0) {
|
|
6704
6815
|
console.error("No meshes joined. Run `claudemesh join <url>` first.");
|
|
@@ -6749,6 +6860,7 @@ async function withMesh(opts, fn) {
|
|
|
6749
6860
|
var init_connect = __esm(() => {
|
|
6750
6861
|
init_facade8();
|
|
6751
6862
|
init_facade();
|
|
6863
|
+
init_policy();
|
|
6752
6864
|
});
|
|
6753
6865
|
|
|
6754
6866
|
// src/commands/info.ts
|
|
@@ -7385,107 +7497,6 @@ var init_ban = __esm(() => {
|
|
|
7385
7497
|
init_exit_codes();
|
|
7386
7498
|
});
|
|
7387
7499
|
|
|
7388
|
-
// src/services/bridge/protocol.ts
|
|
7389
|
-
import { homedir as homedir5 } from "node:os";
|
|
7390
|
-
import { join as join7 } from "node:path";
|
|
7391
|
-
function socketPath(meshSlug) {
|
|
7392
|
-
return join7(homedir5(), ".claudemesh", "sockets", `${meshSlug}.sock`);
|
|
7393
|
-
}
|
|
7394
|
-
function frame(obj) {
|
|
7395
|
-
return JSON.stringify(obj) + `
|
|
7396
|
-
`;
|
|
7397
|
-
}
|
|
7398
|
-
|
|
7399
|
-
class LineParser {
|
|
7400
|
-
buf = "";
|
|
7401
|
-
feed(chunk) {
|
|
7402
|
-
this.buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
7403
|
-
const lines = [];
|
|
7404
|
-
let nl = this.buf.indexOf(`
|
|
7405
|
-
`);
|
|
7406
|
-
while (nl !== -1) {
|
|
7407
|
-
lines.push(this.buf.slice(0, nl));
|
|
7408
|
-
this.buf = this.buf.slice(nl + 1);
|
|
7409
|
-
nl = this.buf.indexOf(`
|
|
7410
|
-
`);
|
|
7411
|
-
}
|
|
7412
|
-
return lines;
|
|
7413
|
-
}
|
|
7414
|
-
}
|
|
7415
|
-
var init_protocol = () => {};
|
|
7416
|
-
|
|
7417
|
-
// src/services/bridge/client.ts
|
|
7418
|
-
import { createConnection } from "node:net";
|
|
7419
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
7420
|
-
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
7421
|
-
async function tryBridge(meshSlug, verb, args = {}, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
7422
|
-
const path = socketPath(meshSlug);
|
|
7423
|
-
if (!existsSync7(path))
|
|
7424
|
-
return null;
|
|
7425
|
-
return new Promise((resolve) => {
|
|
7426
|
-
const id = randomUUID2();
|
|
7427
|
-
const req = { id, verb, args };
|
|
7428
|
-
const parser = new LineParser;
|
|
7429
|
-
let settled = false;
|
|
7430
|
-
const finish = (value) => {
|
|
7431
|
-
if (settled)
|
|
7432
|
-
return;
|
|
7433
|
-
settled = true;
|
|
7434
|
-
try {
|
|
7435
|
-
socket.destroy();
|
|
7436
|
-
} catch {}
|
|
7437
|
-
clearTimeout(timer);
|
|
7438
|
-
resolve(value);
|
|
7439
|
-
};
|
|
7440
|
-
const socket = createConnection({ path });
|
|
7441
|
-
const timer = setTimeout(() => {
|
|
7442
|
-
finish(null);
|
|
7443
|
-
}, timeoutMs);
|
|
7444
|
-
socket.on("connect", () => {
|
|
7445
|
-
try {
|
|
7446
|
-
socket.write(frame(req));
|
|
7447
|
-
} catch {
|
|
7448
|
-
finish(null);
|
|
7449
|
-
}
|
|
7450
|
-
});
|
|
7451
|
-
socket.on("data", (chunk) => {
|
|
7452
|
-
const lines = parser.feed(chunk);
|
|
7453
|
-
for (const line of lines) {
|
|
7454
|
-
if (!line.trim())
|
|
7455
|
-
continue;
|
|
7456
|
-
let res;
|
|
7457
|
-
try {
|
|
7458
|
-
res = JSON.parse(line);
|
|
7459
|
-
} catch {
|
|
7460
|
-
continue;
|
|
7461
|
-
}
|
|
7462
|
-
if (res.id !== id)
|
|
7463
|
-
continue;
|
|
7464
|
-
if (res.ok)
|
|
7465
|
-
finish({ ok: true, result: res.result });
|
|
7466
|
-
else
|
|
7467
|
-
finish({ ok: false, error: res.error });
|
|
7468
|
-
return;
|
|
7469
|
-
}
|
|
7470
|
-
});
|
|
7471
|
-
socket.on("error", (err) => {
|
|
7472
|
-
const code = err.code;
|
|
7473
|
-
if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EPERM") {
|
|
7474
|
-
finish(null);
|
|
7475
|
-
} else {
|
|
7476
|
-
finish(null);
|
|
7477
|
-
}
|
|
7478
|
-
});
|
|
7479
|
-
socket.on("close", () => {
|
|
7480
|
-
finish(null);
|
|
7481
|
-
});
|
|
7482
|
-
});
|
|
7483
|
-
}
|
|
7484
|
-
var DEFAULT_TIMEOUT_MS = 5000;
|
|
7485
|
-
var init_client4 = __esm(() => {
|
|
7486
|
-
init_protocol();
|
|
7487
|
-
});
|
|
7488
|
-
|
|
7489
7500
|
// src/ui/warnings.ts
|
|
7490
7501
|
function warnDaemonState(res, opts = {}) {
|
|
7491
7502
|
if (alreadyWarned)
|
|
@@ -7494,6 +7505,8 @@ function warnDaemonState(res, opts = {}) {
|
|
|
7494
7505
|
return false;
|
|
7495
7506
|
if (res.state === "up")
|
|
7496
7507
|
return false;
|
|
7508
|
+
if (getDaemonPolicy().mode === "strict" && res.state !== "started")
|
|
7509
|
+
return false;
|
|
7497
7510
|
alreadyWarned = true;
|
|
7498
7511
|
const tag = (label) => `[claudemesh] ${label}`;
|
|
7499
7512
|
const hint = (s) => dim(s);
|
|
@@ -7519,6 +7532,7 @@ function warnDaemonState(res, opts = {}) {
|
|
|
7519
7532
|
}
|
|
7520
7533
|
var alreadyWarned = false;
|
|
7521
7534
|
var init_warnings = __esm(() => {
|
|
7535
|
+
init_policy();
|
|
7522
7536
|
init_styles();
|
|
7523
7537
|
});
|
|
7524
7538
|
|
|
@@ -7540,7 +7554,10 @@ function meshQuery(mesh) {
|
|
|
7540
7554
|
return mesh ? `?mesh=${encodeURIComponent(mesh)}` : "";
|
|
7541
7555
|
}
|
|
7542
7556
|
async function daemonReachable() {
|
|
7543
|
-
const
|
|
7557
|
+
const policy2 = getDaemonPolicy();
|
|
7558
|
+
if (policy2.mode === "no-daemon")
|
|
7559
|
+
return false;
|
|
7560
|
+
const res = await ensureDaemonReady({ noAutoSpawn: false });
|
|
7544
7561
|
warnDaemonState(res, {});
|
|
7545
7562
|
return res.state === "up" || res.state === "started";
|
|
7546
7563
|
}
|
|
@@ -7718,9 +7735,49 @@ async function trySendViaDaemon(args) {
|
|
|
7718
7735
|
var init_daemon_route = __esm(() => {
|
|
7719
7736
|
init_client3();
|
|
7720
7737
|
init_lifecycle();
|
|
7738
|
+
init_policy();
|
|
7721
7739
|
init_warnings();
|
|
7722
7740
|
});
|
|
7723
7741
|
|
|
7742
|
+
// src/services/session/resolve.ts
|
|
7743
|
+
var exports_resolve = {};
|
|
7744
|
+
__export(exports_resolve, {
|
|
7745
|
+
getSessionInfo: () => getSessionInfo,
|
|
7746
|
+
_resetSessionCache: () => _resetSessionCache
|
|
7747
|
+
});
|
|
7748
|
+
async function getSessionInfo() {
|
|
7749
|
+
if (cached !== undefined)
|
|
7750
|
+
return cached;
|
|
7751
|
+
const tok = readSessionTokenFromEnv();
|
|
7752
|
+
if (!tok) {
|
|
7753
|
+
cached = null;
|
|
7754
|
+
return null;
|
|
7755
|
+
}
|
|
7756
|
+
try {
|
|
7757
|
+
const res = await ipc({
|
|
7758
|
+
path: "/v1/sessions/me",
|
|
7759
|
+
timeoutMs: 1500
|
|
7760
|
+
});
|
|
7761
|
+
if (res.status !== 200 || !res.body.session) {
|
|
7762
|
+
cached = null;
|
|
7763
|
+
return null;
|
|
7764
|
+
}
|
|
7765
|
+
cached = res.body.session;
|
|
7766
|
+
return cached;
|
|
7767
|
+
} catch {
|
|
7768
|
+
cached = null;
|
|
7769
|
+
return null;
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7772
|
+
function _resetSessionCache() {
|
|
7773
|
+
cached = undefined;
|
|
7774
|
+
}
|
|
7775
|
+
var cached = undefined;
|
|
7776
|
+
var init_resolve = __esm(() => {
|
|
7777
|
+
init_client3();
|
|
7778
|
+
init_token();
|
|
7779
|
+
});
|
|
7780
|
+
|
|
7724
7781
|
// src/commands/peers.ts
|
|
7725
7782
|
var exports_peers = {};
|
|
7726
7783
|
__export(exports_peers, {
|
|
@@ -7745,11 +7802,6 @@ async function listPeersForMesh(slug) {
|
|
|
7745
7802
|
return dr.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
7746
7803
|
}
|
|
7747
7804
|
} catch {}
|
|
7748
|
-
const bridged = await tryBridge(slug, "peers");
|
|
7749
|
-
if (bridged && bridged.ok) {
|
|
7750
|
-
const peers = bridged.result;
|
|
7751
|
-
return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
|
|
7752
|
-
}
|
|
7753
7805
|
let result = [];
|
|
7754
7806
|
await withMesh({ meshSlug: slug }, async (client) => {
|
|
7755
7807
|
const all = await client.listPeers();
|
|
@@ -7765,7 +7817,14 @@ function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
|
|
|
7765
7817
|
}
|
|
7766
7818
|
async function runPeers(flags) {
|
|
7767
7819
|
const config = readConfig();
|
|
7768
|
-
|
|
7820
|
+
let slugs;
|
|
7821
|
+
if (flags.mesh) {
|
|
7822
|
+
slugs = [flags.mesh];
|
|
7823
|
+
} else {
|
|
7824
|
+
const { getSessionInfo: getSessionInfo2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
|
|
7825
|
+
const sess = await getSessionInfo2();
|
|
7826
|
+
slugs = sess ? [sess.mesh] : config.meshes.map((m) => m.slug);
|
|
7827
|
+
}
|
|
7769
7828
|
if (slugs.length === 0) {
|
|
7770
7829
|
render.err("No meshes joined.");
|
|
7771
7830
|
render.hint("claudemesh <invite-url> # join + launch");
|
|
@@ -7819,7 +7878,6 @@ var FIELD_ALIAS;
|
|
|
7819
7878
|
var init_peers = __esm(() => {
|
|
7820
7879
|
init_connect();
|
|
7821
7880
|
init_facade();
|
|
7822
|
-
init_client4();
|
|
7823
7881
|
init_render();
|
|
7824
7882
|
init_styles();
|
|
7825
7883
|
FIELD_ALIAS = {
|
|
@@ -7865,26 +7923,6 @@ async function runSend(flags, to, message) {
|
|
|
7865
7923
|
process.exit(1);
|
|
7866
7924
|
}
|
|
7867
7925
|
}
|
|
7868
|
-
if (meshSlug) {
|
|
7869
|
-
const bridged = await tryBridge(meshSlug, "send", { to, message, priority });
|
|
7870
|
-
if (bridged !== null) {
|
|
7871
|
-
if (bridged.ok) {
|
|
7872
|
-
const r = bridged.result;
|
|
7873
|
-
if (flags.json) {
|
|
7874
|
-
console.log(JSON.stringify({ ok: true, messageId: r.messageId, target: to }));
|
|
7875
|
-
} else {
|
|
7876
|
-
render.ok(`sent to ${to}`, r.messageId ? dim(r.messageId.slice(0, 8)) : undefined);
|
|
7877
|
-
}
|
|
7878
|
-
return;
|
|
7879
|
-
}
|
|
7880
|
-
if (flags.json) {
|
|
7881
|
-
console.log(JSON.stringify({ ok: false, error: bridged.error }));
|
|
7882
|
-
} else {
|
|
7883
|
-
render.err(`send failed: ${bridged.error}`);
|
|
7884
|
-
}
|
|
7885
|
-
process.exit(1);
|
|
7886
|
-
}
|
|
7887
|
-
}
|
|
7888
7926
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
7889
7927
|
let targetSpec = to;
|
|
7890
7928
|
if (to.startsWith("#") && !/^#[0-9a-z_-]{20,}$/i.test(to)) {
|
|
@@ -7927,7 +7965,6 @@ async function runSend(flags, to, message) {
|
|
|
7927
7965
|
var init_send = __esm(() => {
|
|
7928
7966
|
init_connect();
|
|
7929
7967
|
init_facade();
|
|
7930
|
-
init_client4();
|
|
7931
7968
|
init_daemon_route();
|
|
7932
7969
|
init_render();
|
|
7933
7970
|
init_styles();
|
|
@@ -8255,33 +8292,12 @@ __export(exports_broker_actions, {
|
|
|
8255
8292
|
runForget: () => runForget,
|
|
8256
8293
|
runClock: () => runClock
|
|
8257
8294
|
});
|
|
8258
|
-
function unambiguousMesh(opts) {
|
|
8259
|
-
if (opts.mesh)
|
|
8260
|
-
return opts.mesh;
|
|
8261
|
-
const config = readConfig();
|
|
8262
|
-
return config.meshes.length === 1 ? config.meshes[0].slug : null;
|
|
8263
|
-
}
|
|
8264
8295
|
async function runStatusSet(state, opts) {
|
|
8265
8296
|
const valid = ["idle", "working", "dnd"];
|
|
8266
8297
|
if (!valid.includes(state)) {
|
|
8267
8298
|
render.err(`Invalid status: ${state}`, `must be one of: ${valid.join(", ")}`);
|
|
8268
8299
|
return EXIT.INVALID_ARGS;
|
|
8269
8300
|
}
|
|
8270
|
-
const meshSlug = unambiguousMesh(opts);
|
|
8271
|
-
if (meshSlug) {
|
|
8272
|
-
const bridged = await tryBridge(meshSlug, "status_set", { status: state });
|
|
8273
|
-
if (bridged !== null) {
|
|
8274
|
-
if (bridged.ok) {
|
|
8275
|
-
if (opts.json)
|
|
8276
|
-
console.log(JSON.stringify({ status: state }));
|
|
8277
|
-
else
|
|
8278
|
-
render.ok(`status set to ${bold(state)}`);
|
|
8279
|
-
return EXIT.SUCCESS;
|
|
8280
|
-
}
|
|
8281
|
-
render.err(bridged.error);
|
|
8282
|
-
return EXIT.INTERNAL_ERROR;
|
|
8283
|
-
}
|
|
8284
|
-
}
|
|
8285
8301
|
await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
8286
8302
|
await client.setStatus(state);
|
|
8287
8303
|
});
|
|
@@ -8296,21 +8312,6 @@ async function runSummary(text, opts) {
|
|
|
8296
8312
|
render.err("Usage: claudemesh summary <text>");
|
|
8297
8313
|
return EXIT.INVALID_ARGS;
|
|
8298
8314
|
}
|
|
8299
|
-
const meshSlug = unambiguousMesh(opts);
|
|
8300
|
-
if (meshSlug) {
|
|
8301
|
-
const bridged = await tryBridge(meshSlug, "summary", { summary: text });
|
|
8302
|
-
if (bridged !== null) {
|
|
8303
|
-
if (bridged.ok) {
|
|
8304
|
-
if (opts.json)
|
|
8305
|
-
console.log(JSON.stringify({ summary: text }));
|
|
8306
|
-
else
|
|
8307
|
-
render.ok("summary set", dim(text));
|
|
8308
|
-
return EXIT.SUCCESS;
|
|
8309
|
-
}
|
|
8310
|
-
render.err(bridged.error);
|
|
8311
|
-
return EXIT.INTERNAL_ERROR;
|
|
8312
|
-
}
|
|
8313
|
-
}
|
|
8314
8315
|
await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
8315
8316
|
await client.setSummary(text);
|
|
8316
8317
|
});
|
|
@@ -8330,21 +8331,6 @@ async function runVisible(value, opts) {
|
|
|
8330
8331
|
render.err("Usage: claudemesh visible <true|false>");
|
|
8331
8332
|
return EXIT.INVALID_ARGS;
|
|
8332
8333
|
}
|
|
8333
|
-
const meshSlug = unambiguousMesh(opts);
|
|
8334
|
-
if (meshSlug) {
|
|
8335
|
-
const bridged = await tryBridge(meshSlug, "visible", { visible });
|
|
8336
|
-
if (bridged !== null) {
|
|
8337
|
-
if (bridged.ok) {
|
|
8338
|
-
if (opts.json)
|
|
8339
|
-
console.log(JSON.stringify({ visible }));
|
|
8340
|
-
else
|
|
8341
|
-
render.ok(visible ? "you are now visible to peers" : "you are now hidden", visible ? undefined : "direct messages still reach you");
|
|
8342
|
-
return EXIT.SUCCESS;
|
|
8343
|
-
}
|
|
8344
|
-
render.err(bridged.error);
|
|
8345
|
-
return EXIT.INTERNAL_ERROR;
|
|
8346
|
-
}
|
|
8347
|
-
}
|
|
8348
8334
|
await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
8349
8335
|
await client.setVisible(visible);
|
|
8350
8336
|
});
|
|
@@ -8574,8 +8560,6 @@ async function runTaskComplete(id, result, opts) {
|
|
|
8574
8560
|
}
|
|
8575
8561
|
var init_broker_actions = __esm(() => {
|
|
8576
8562
|
init_connect();
|
|
8577
|
-
init_facade();
|
|
8578
|
-
init_client4();
|
|
8579
8563
|
init_daemon_route();
|
|
8580
8564
|
init_render();
|
|
8581
8565
|
init_styles();
|
|
@@ -8810,12 +8794,12 @@ var init_whoami = __esm(() => {
|
|
|
8810
8794
|
});
|
|
8811
8795
|
|
|
8812
8796
|
// src/daemon/lock.ts
|
|
8813
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as
|
|
8797
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
|
|
8814
8798
|
import { dirname as dirname4 } from "node:path";
|
|
8815
8799
|
function acquireSingletonLock() {
|
|
8816
8800
|
mkdirSync5(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
|
|
8817
8801
|
if (existsSync8(DAEMON_PATHS.PID_FILE)) {
|
|
8818
|
-
const raw =
|
|
8802
|
+
const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8819
8803
|
const oldPid = Number.parseInt(raw, 10);
|
|
8820
8804
|
if (Number.isFinite(oldPid) && oldPid > 0 && isProcessAlive(oldPid)) {
|
|
8821
8805
|
return { result: "already-running", pid: oldPid };
|
|
@@ -8823,22 +8807,22 @@ function acquireSingletonLock() {
|
|
|
8823
8807
|
try {
|
|
8824
8808
|
unlinkSync3(DAEMON_PATHS.PID_FILE);
|
|
8825
8809
|
} catch {}
|
|
8826
|
-
|
|
8810
|
+
writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
|
|
8827
8811
|
return { result: "stale", pid: process.pid };
|
|
8828
8812
|
}
|
|
8829
|
-
|
|
8813
|
+
writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
|
|
8830
8814
|
return { result: "acquired", pid: process.pid };
|
|
8831
8815
|
}
|
|
8832
8816
|
function releaseSingletonLock() {
|
|
8833
8817
|
try {
|
|
8834
|
-
const raw =
|
|
8818
|
+
const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8835
8819
|
if (Number.parseInt(raw, 10) === process.pid)
|
|
8836
8820
|
unlinkSync3(DAEMON_PATHS.PID_FILE);
|
|
8837
8821
|
} catch {}
|
|
8838
8822
|
}
|
|
8839
8823
|
function readRunningPid() {
|
|
8840
8824
|
try {
|
|
8841
|
-
const raw =
|
|
8825
|
+
const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
|
|
8842
8826
|
const pid = Number.parseInt(raw, 10);
|
|
8843
8827
|
if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
|
|
8844
8828
|
return pid;
|
|
@@ -8984,17 +8968,17 @@ function requeueDeadOrPending(db, args) {
|
|
|
8984
8968
|
|
|
8985
8969
|
// src/daemon/db/sqlite.ts
|
|
8986
8970
|
async function loadSqlite() {
|
|
8987
|
-
if (
|
|
8988
|
-
return
|
|
8971
|
+
if (cached2)
|
|
8972
|
+
return cached2;
|
|
8989
8973
|
try {
|
|
8990
8974
|
const mod = await import("node:sqlite");
|
|
8991
|
-
|
|
8992
|
-
return
|
|
8975
|
+
cached2 = mod.DatabaseSync;
|
|
8976
|
+
return cached2;
|
|
8993
8977
|
} catch (nodeErr) {
|
|
8994
8978
|
try {
|
|
8995
8979
|
const bunMod = await import("bun:sqlite");
|
|
8996
|
-
|
|
8997
|
-
return
|
|
8980
|
+
cached2 = bunMod.Database;
|
|
8981
|
+
return cached2;
|
|
8998
8982
|
} catch {
|
|
8999
8983
|
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)}`;
|
|
9000
8984
|
throw new Error(msg);
|
|
@@ -9025,7 +9009,7 @@ function inImmediateTx(db, fn) {
|
|
|
9025
9009
|
throw err;
|
|
9026
9010
|
}
|
|
9027
9011
|
}
|
|
9028
|
-
var
|
|
9012
|
+
var cached2 = null;
|
|
9029
9013
|
|
|
9030
9014
|
// src/daemon/fingerprint.ts
|
|
9031
9015
|
import { createHash } from "node:crypto";
|
|
@@ -9074,10 +9058,10 @@ var init_fingerprint = __esm(() => {
|
|
|
9074
9058
|
});
|
|
9075
9059
|
|
|
9076
9060
|
// src/daemon/ipc/handlers/send.ts
|
|
9077
|
-
import { randomUUID as
|
|
9061
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
9078
9062
|
function acceptSend(req, deps) {
|
|
9079
9063
|
const now = (deps.now ?? Date.now)();
|
|
9080
|
-
const newId = deps.newId ??
|
|
9064
|
+
const newId = deps.newId ?? randomUUID2;
|
|
9081
9065
|
const clientId = req.client_message_id?.trim() || ulidLike(newId);
|
|
9082
9066
|
const body = Buffer.from(req.message, "utf8");
|
|
9083
9067
|
const fingerprint = computeRequestFingerprint({
|
|
@@ -9268,11 +9252,72 @@ function bindSseStream(res, bus) {
|
|
|
9268
9252
|
return cleanup;
|
|
9269
9253
|
}
|
|
9270
9254
|
|
|
9255
|
+
// src/daemon/session-registry.ts
|
|
9256
|
+
function startReaper() {
|
|
9257
|
+
if (reaperHandle)
|
|
9258
|
+
return;
|
|
9259
|
+
reaperHandle = setInterval(reapDead, REAPER_INTERVAL_MS).unref?.() ?? reaperHandle;
|
|
9260
|
+
}
|
|
9261
|
+
function registerSession(info) {
|
|
9262
|
+
const priorToken = bySessionId.get(info.sessionId);
|
|
9263
|
+
if (priorToken && priorToken !== info.token)
|
|
9264
|
+
byToken.delete(priorToken);
|
|
9265
|
+
const stored = { ...info, registeredAt: Date.now() };
|
|
9266
|
+
byToken.set(info.token, stored);
|
|
9267
|
+
bySessionId.set(info.sessionId, info.token);
|
|
9268
|
+
return stored;
|
|
9269
|
+
}
|
|
9270
|
+
function deregisterByToken(token) {
|
|
9271
|
+
const entry = byToken.get(token);
|
|
9272
|
+
if (!entry)
|
|
9273
|
+
return false;
|
|
9274
|
+
byToken.delete(token);
|
|
9275
|
+
if (bySessionId.get(entry.sessionId) === token)
|
|
9276
|
+
bySessionId.delete(entry.sessionId);
|
|
9277
|
+
return true;
|
|
9278
|
+
}
|
|
9279
|
+
function resolveToken(token) {
|
|
9280
|
+
const entry = byToken.get(token);
|
|
9281
|
+
if (!entry)
|
|
9282
|
+
return null;
|
|
9283
|
+
if (Date.now() - entry.registeredAt > TTL_MS) {
|
|
9284
|
+
deregisterByToken(token);
|
|
9285
|
+
return null;
|
|
9286
|
+
}
|
|
9287
|
+
return entry;
|
|
9288
|
+
}
|
|
9289
|
+
function listSessions() {
|
|
9290
|
+
return [...byToken.values()];
|
|
9291
|
+
}
|
|
9292
|
+
function reapDead() {
|
|
9293
|
+
const dead = [];
|
|
9294
|
+
for (const [token, info] of byToken.entries()) {
|
|
9295
|
+
if (Date.now() - info.registeredAt > TTL_MS) {
|
|
9296
|
+
dead.push(token);
|
|
9297
|
+
continue;
|
|
9298
|
+
}
|
|
9299
|
+
try {
|
|
9300
|
+
process.kill(info.pid, 0);
|
|
9301
|
+
} catch {
|
|
9302
|
+
dead.push(token);
|
|
9303
|
+
}
|
|
9304
|
+
}
|
|
9305
|
+
for (const t of dead)
|
|
9306
|
+
deregisterByToken(t);
|
|
9307
|
+
}
|
|
9308
|
+
var TTL_MS, REAPER_INTERVAL_MS, byToken, bySessionId, reaperHandle = null;
|
|
9309
|
+
var init_session_registry = __esm(() => {
|
|
9310
|
+
TTL_MS = 24 * 60 * 60 * 1000;
|
|
9311
|
+
REAPER_INTERVAL_MS = 30 * 1000;
|
|
9312
|
+
byToken = new Map;
|
|
9313
|
+
bySessionId = new Map;
|
|
9314
|
+
});
|
|
9315
|
+
|
|
9271
9316
|
// src/daemon/ipc/server.ts
|
|
9272
9317
|
import { createServer as createServer2 } from "node:http";
|
|
9273
9318
|
import { chmodSync as chmodSync3, existsSync as existsSync9, unlinkSync as unlinkSync4 } from "node:fs";
|
|
9274
9319
|
import { timingSafeEqual } from "node:crypto";
|
|
9275
|
-
import { randomUUID as
|
|
9320
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
9276
9321
|
function startIpcServer(opts) {
|
|
9277
9322
|
const log2 = opts.log ?? defaultLogger;
|
|
9278
9323
|
const handler = makeHandler({
|
|
@@ -9372,11 +9417,19 @@ function makeHandler(opts) {
|
|
|
9372
9417
|
return;
|
|
9373
9418
|
}
|
|
9374
9419
|
}
|
|
9420
|
+
let session = null;
|
|
9421
|
+
{
|
|
9422
|
+
const authz = req.headers.authorization ?? "";
|
|
9423
|
+
const sm = /^ClaudeMesh-Session\s+([0-9a-f]{64})$/i.exec(authz.trim());
|
|
9424
|
+
if (sm && sm[1])
|
|
9425
|
+
session = resolveToken(sm[1].toLowerCase());
|
|
9426
|
+
}
|
|
9427
|
+
const meshFromCtx = (explicit) => explicit && explicit.trim() ? explicit : session?.mesh ?? null;
|
|
9375
9428
|
if (req.method === "GET" && url.pathname === "/v1/version") {
|
|
9376
9429
|
respond(res, 200, {
|
|
9377
9430
|
daemon_version: VERSION,
|
|
9378
9431
|
ipc_api: "v1",
|
|
9379
|
-
ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory"],
|
|
9432
|
+
ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory", "sessions"],
|
|
9380
9433
|
schema_version: 1
|
|
9381
9434
|
});
|
|
9382
9435
|
return;
|
|
@@ -9385,6 +9438,70 @@ function makeHandler(opts) {
|
|
|
9385
9438
|
respond(res, 200, { ok: true, pid: process.pid });
|
|
9386
9439
|
return;
|
|
9387
9440
|
}
|
|
9441
|
+
if (req.method === "POST" && url.pathname === "/v1/sessions/register") {
|
|
9442
|
+
try {
|
|
9443
|
+
const body = await readJsonBody(req, 64 * 1024);
|
|
9444
|
+
if (!body) {
|
|
9445
|
+
respond(res, 400, { error: "missing body" });
|
|
9446
|
+
return;
|
|
9447
|
+
}
|
|
9448
|
+
const token = typeof body.token === "string" ? body.token : "";
|
|
9449
|
+
if (!/^[0-9a-f]{64}$/i.test(token)) {
|
|
9450
|
+
respond(res, 400, { error: "token must be 64 hex chars" });
|
|
9451
|
+
return;
|
|
9452
|
+
}
|
|
9453
|
+
const sessionId = typeof body.session_id === "string" ? body.session_id : "";
|
|
9454
|
+
const mesh = typeof body.mesh === "string" ? body.mesh : "";
|
|
9455
|
+
const displayName = typeof body.display_name === "string" ? body.display_name : "";
|
|
9456
|
+
const pid = typeof body.pid === "number" ? body.pid : 0;
|
|
9457
|
+
if (!sessionId || !mesh || !displayName || !pid) {
|
|
9458
|
+
respond(res, 400, { error: "session_id, mesh, display_name, pid all required" });
|
|
9459
|
+
return;
|
|
9460
|
+
}
|
|
9461
|
+
const cwd = typeof body.cwd === "string" ? body.cwd : undefined;
|
|
9462
|
+
const role = typeof body.role === "string" ? body.role : undefined;
|
|
9463
|
+
const groups = Array.isArray(body.groups) ? body.groups.filter((g) => typeof g === "string") : undefined;
|
|
9464
|
+
const stored = registerSession({
|
|
9465
|
+
token: token.toLowerCase(),
|
|
9466
|
+
sessionId,
|
|
9467
|
+
mesh,
|
|
9468
|
+
displayName,
|
|
9469
|
+
pid,
|
|
9470
|
+
cwd,
|
|
9471
|
+
role,
|
|
9472
|
+
groups
|
|
9473
|
+
});
|
|
9474
|
+
opts.log("info", "session_registered", { sessionId, mesh, pid });
|
|
9475
|
+
respond(res, 200, { ok: true, registered_at: stored.registeredAt });
|
|
9476
|
+
} catch (e) {
|
|
9477
|
+
respond(res, 400, { error: String(e) });
|
|
9478
|
+
}
|
|
9479
|
+
return;
|
|
9480
|
+
}
|
|
9481
|
+
if (req.method === "DELETE" && url.pathname.startsWith("/v1/sessions/")) {
|
|
9482
|
+
const tail = url.pathname.slice("/v1/sessions/".length);
|
|
9483
|
+
if (!/^[0-9a-f]{64}$/i.test(tail)) {
|
|
9484
|
+
respond(res, 400, { error: "invalid token" });
|
|
9485
|
+
return;
|
|
9486
|
+
}
|
|
9487
|
+
const ok = deregisterByToken(tail.toLowerCase());
|
|
9488
|
+
respond(res, ok ? 200 : 404, { ok, token_prefix: tail.slice(0, 8) });
|
|
9489
|
+
return;
|
|
9490
|
+
}
|
|
9491
|
+
if (req.method === "GET" && url.pathname === "/v1/sessions/me") {
|
|
9492
|
+
if (!session) {
|
|
9493
|
+
respond(res, 401, { error: "no session token" });
|
|
9494
|
+
return;
|
|
9495
|
+
}
|
|
9496
|
+
const { token, ...redacted } = session;
|
|
9497
|
+
respond(res, 200, { session: { ...redacted, token_prefix: token.slice(0, 8) } });
|
|
9498
|
+
return;
|
|
9499
|
+
}
|
|
9500
|
+
if (req.method === "GET" && url.pathname === "/v1/sessions") {
|
|
9501
|
+
const all = listSessions().map(({ token, ...rest }) => ({ ...rest, token_prefix: token.slice(0, 8) }));
|
|
9502
|
+
respond(res, 200, { sessions: all });
|
|
9503
|
+
return;
|
|
9504
|
+
}
|
|
9388
9505
|
if (req.method === "GET" && url.pathname === "/v1/events") {
|
|
9389
9506
|
if (!opts.bus) {
|
|
9390
9507
|
respond(res, 503, { error: "event bus not initialised" });
|
|
@@ -9398,7 +9515,7 @@ function makeHandler(opts) {
|
|
|
9398
9515
|
respond(res, 503, { error: "broker not initialised" });
|
|
9399
9516
|
return;
|
|
9400
9517
|
}
|
|
9401
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9518
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9402
9519
|
try {
|
|
9403
9520
|
const all = [];
|
|
9404
9521
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
@@ -9423,7 +9540,7 @@ function makeHandler(opts) {
|
|
|
9423
9540
|
respond(res, 503, { error: "broker not initialised" });
|
|
9424
9541
|
return;
|
|
9425
9542
|
}
|
|
9426
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9543
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9427
9544
|
const key = url.searchParams.get("key");
|
|
9428
9545
|
try {
|
|
9429
9546
|
if (key) {
|
|
@@ -9464,7 +9581,7 @@ function makeHandler(opts) {
|
|
|
9464
9581
|
respond(res, 400, { error: "missing 'key' (string)" });
|
|
9465
9582
|
return;
|
|
9466
9583
|
}
|
|
9467
|
-
const requested = (typeof body.mesh === "string" ? body.mesh : null)
|
|
9584
|
+
const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : null);
|
|
9468
9585
|
let chosen = requested;
|
|
9469
9586
|
if (!chosen && opts.brokers.size === 1)
|
|
9470
9587
|
chosen = opts.brokers.keys().next().value;
|
|
@@ -9490,7 +9607,7 @@ function makeHandler(opts) {
|
|
|
9490
9607
|
return;
|
|
9491
9608
|
}
|
|
9492
9609
|
const query = url.searchParams.get("q") ?? "";
|
|
9493
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9610
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9494
9611
|
try {
|
|
9495
9612
|
const all = [];
|
|
9496
9613
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
@@ -9517,7 +9634,7 @@ function makeHandler(opts) {
|
|
|
9517
9634
|
respond(res, 400, { error: "missing 'content' (string)" });
|
|
9518
9635
|
return;
|
|
9519
9636
|
}
|
|
9520
|
-
const requested = (typeof body.mesh === "string" ? body.mesh : null)
|
|
9637
|
+
const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : null);
|
|
9521
9638
|
let chosen = requested;
|
|
9522
9639
|
if (!chosen && opts.brokers.size === 1)
|
|
9523
9640
|
chosen = opts.brokers.keys().next().value;
|
|
@@ -9575,7 +9692,7 @@ function makeHandler(opts) {
|
|
|
9575
9692
|
return;
|
|
9576
9693
|
}
|
|
9577
9694
|
const query = url.searchParams.get("query") ?? undefined;
|
|
9578
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9695
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9579
9696
|
try {
|
|
9580
9697
|
const all = [];
|
|
9581
9698
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
@@ -9605,7 +9722,7 @@ function makeHandler(opts) {
|
|
|
9605
9722
|
respond(res, 400, { error: "missing skill name" });
|
|
9606
9723
|
return;
|
|
9607
9724
|
}
|
|
9608
|
-
const filterMesh = url.searchParams.get("mesh") ?? undefined;
|
|
9725
|
+
const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
|
|
9609
9726
|
try {
|
|
9610
9727
|
for (const [slug, b] of opts.brokers.entries()) {
|
|
9611
9728
|
if (filterMesh && filterMesh !== slug)
|
|
@@ -9633,7 +9750,7 @@ function makeHandler(opts) {
|
|
|
9633
9750
|
respond(res, 400, { error: "expected JSON object" });
|
|
9634
9751
|
return;
|
|
9635
9752
|
}
|
|
9636
|
-
const requested = (typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh"))
|
|
9753
|
+
const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh"));
|
|
9637
9754
|
const targets = requested ? [opts.brokers.get(requested)].filter(Boolean) : [...opts.brokers.values()];
|
|
9638
9755
|
if (targets.length === 0) {
|
|
9639
9756
|
respond(res, 404, { error: "mesh_not_attached", mesh: requested });
|
|
@@ -9743,11 +9860,11 @@ function makeHandler(opts) {
|
|
|
9743
9860
|
respond(res, 400, { error: "missing 'id'" });
|
|
9744
9861
|
return;
|
|
9745
9862
|
}
|
|
9746
|
-
const newId = typeof body.new_client_message_id === "string" && body.new_client_message_id.trim() ? body.new_client_message_id.trim() :
|
|
9863
|
+
const newId = typeof body.new_client_message_id === "string" && body.new_client_message_id.trim() ? body.new_client_message_id.trim() : randomUUID3();
|
|
9747
9864
|
const result = requeueDeadOrPending(opts.outboxDb, {
|
|
9748
9865
|
id: body.id,
|
|
9749
9866
|
newClientMessageId: newId,
|
|
9750
|
-
newRowId:
|
|
9867
|
+
newRowId: randomUUID3(),
|
|
9751
9868
|
now: Date.now(),
|
|
9752
9869
|
abortedBy: typeof body.aborted_by === "string" ? body.aborted_by : "operator"
|
|
9753
9870
|
});
|
|
@@ -9917,16 +10034,16 @@ function parseSendRequest(body, idempotencyHeader) {
|
|
|
9917
10034
|
}
|
|
9918
10035
|
async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
|
|
9919
10036
|
const { encryptDirect: encryptDirect2 } = await Promise.resolve().then(() => (init_box(), exports_box));
|
|
9920
|
-
const { randomBytes:
|
|
10037
|
+
const { randomBytes: randomBytes6 } = await import("node:crypto");
|
|
9921
10038
|
const to = req.to.trim();
|
|
9922
10039
|
if (to.startsWith("#") && /^#[0-9a-z_-]{20,}$/i.test(to)) {
|
|
9923
10040
|
const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
|
|
9924
|
-
const nonce =
|
|
10041
|
+
const nonce = randomBytes6(24).toString("base64");
|
|
9925
10042
|
return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
|
|
9926
10043
|
}
|
|
9927
10044
|
if (to.startsWith("@") || to === "*") {
|
|
9928
10045
|
const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
|
|
9929
|
-
const nonce =
|
|
10046
|
+
const nonce = randomBytes6(24).toString("base64");
|
|
9930
10047
|
return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
|
|
9931
10048
|
}
|
|
9932
10049
|
if (/^[0-9a-f]{64}$/i.test(to)) {
|
|
@@ -9967,6 +10084,7 @@ function respond(res, status, body) {
|
|
|
9967
10084
|
var init_server = __esm(() => {
|
|
9968
10085
|
init_paths2();
|
|
9969
10086
|
init_send2();
|
|
10087
|
+
init_session_registry();
|
|
9970
10088
|
init_urls();
|
|
9971
10089
|
});
|
|
9972
10090
|
|
|
@@ -10598,8 +10716,8 @@ function bufferToHex(b) {
|
|
|
10598
10716
|
return s;
|
|
10599
10717
|
}
|
|
10600
10718
|
async function randomNonce2() {
|
|
10601
|
-
const { randomBytes:
|
|
10602
|
-
return
|
|
10719
|
+
const { randomBytes: randomBytes6 } = await import("node:crypto");
|
|
10720
|
+
return randomBytes6(24).toString("base64");
|
|
10603
10721
|
}
|
|
10604
10722
|
function defaultLog2(level, msg, meta) {
|
|
10605
10723
|
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
@@ -10614,7 +10732,7 @@ var POLL_INTERVAL_MS = 500, MAX_ATTEMPTS_PER_ROW = 25, BACKOFF_BASE_MS = 500, BA
|
|
|
10614
10732
|
var init_drain = () => {};
|
|
10615
10733
|
|
|
10616
10734
|
// src/daemon/inbound.ts
|
|
10617
|
-
import { randomUUID as
|
|
10735
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
10618
10736
|
async function handleBrokerPush(msg, ctx) {
|
|
10619
10737
|
if (msg.subtype === "system" && typeof msg.event === "string") {
|
|
10620
10738
|
ctx.bus.publish(mapSystemEventKind(msg.event), {
|
|
@@ -10637,14 +10755,14 @@ async function handleBrokerPush(msg, ctx) {
|
|
|
10637
10755
|
const createdAt = stringOrNull(msg.createdAt);
|
|
10638
10756
|
const priority = stringOrNull(msg.priority) ?? "next";
|
|
10639
10757
|
const subtype = stringOrNull(msg.subtype);
|
|
10640
|
-
const clientMessageId = stringOrNull(msg.client_message_id) ?? brokerMessageId ??
|
|
10758
|
+
const clientMessageId = stringOrNull(msg.client_message_id) ?? brokerMessageId ?? randomUUID4();
|
|
10641
10759
|
const body = await decryptOrFallback({
|
|
10642
10760
|
ciphertext,
|
|
10643
10761
|
nonce,
|
|
10644
10762
|
senderPubkey,
|
|
10645
10763
|
ctx
|
|
10646
10764
|
});
|
|
10647
|
-
const id =
|
|
10765
|
+
const id = randomUUID4();
|
|
10648
10766
|
const inserted = insertIfNew(ctx.db, {
|
|
10649
10767
|
id,
|
|
10650
10768
|
client_message_id: clientMessageId,
|
|
@@ -10721,12 +10839,12 @@ __export(exports_identity, {
|
|
|
10721
10839
|
checkFingerprint: () => checkFingerprint,
|
|
10722
10840
|
acceptCurrentHost: () => acceptCurrentHost
|
|
10723
10841
|
});
|
|
10724
|
-
import { existsSync as existsSync10, readFileSync as
|
|
10725
|
-
import { join as
|
|
10842
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "node:fs";
|
|
10843
|
+
import { join as join7 } from "node:path";
|
|
10726
10844
|
import { createHash as createHash2 } from "node:crypto";
|
|
10727
10845
|
import { networkInterfaces } from "node:os";
|
|
10728
10846
|
function path() {
|
|
10729
|
-
return
|
|
10847
|
+
return join7(DAEMON_PATHS.DAEMON_DIR, FILE_NAME);
|
|
10730
10848
|
}
|
|
10731
10849
|
function computeCurrentFingerprint() {
|
|
10732
10850
|
const host_id = readHostId() ?? "";
|
|
@@ -10743,12 +10861,12 @@ function computeCurrentFingerprint() {
|
|
|
10743
10861
|
function checkFingerprint() {
|
|
10744
10862
|
const current = computeCurrentFingerprint();
|
|
10745
10863
|
if (!existsSync10(path())) {
|
|
10746
|
-
|
|
10864
|
+
writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
|
|
10747
10865
|
return { result: "first_run", current };
|
|
10748
10866
|
}
|
|
10749
10867
|
let stored;
|
|
10750
10868
|
try {
|
|
10751
|
-
stored = JSON.parse(
|
|
10869
|
+
stored = JSON.parse(readFileSync9(path(), "utf8"));
|
|
10752
10870
|
} catch {
|
|
10753
10871
|
return { result: "unavailable", current };
|
|
10754
10872
|
}
|
|
@@ -10758,14 +10876,14 @@ function checkFingerprint() {
|
|
|
10758
10876
|
}
|
|
10759
10877
|
function acceptCurrentHost() {
|
|
10760
10878
|
const current = computeCurrentFingerprint();
|
|
10761
|
-
|
|
10879
|
+
writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
|
|
10762
10880
|
return current;
|
|
10763
10881
|
}
|
|
10764
10882
|
function readHostId() {
|
|
10765
10883
|
if (process.platform === "linux") {
|
|
10766
10884
|
for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
10767
10885
|
try {
|
|
10768
|
-
const raw =
|
|
10886
|
+
const raw = readFileSync9(p, "utf8").trim();
|
|
10769
10887
|
if (raw)
|
|
10770
10888
|
return `linux:${raw}`;
|
|
10771
10889
|
} catch {}
|
|
@@ -10810,7 +10928,7 @@ var init_identity = __esm(() => {
|
|
|
10810
10928
|
});
|
|
10811
10929
|
|
|
10812
10930
|
// src/daemon/run.ts
|
|
10813
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as
|
|
10931
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync10 } from "node:fs";
|
|
10814
10932
|
function detectContainer() {
|
|
10815
10933
|
if (process.env.KUBERNETES_SERVICE_HOST)
|
|
10816
10934
|
return true;
|
|
@@ -10819,7 +10937,7 @@ function detectContainer() {
|
|
|
10819
10937
|
try {
|
|
10820
10938
|
if (existsSync11("/.dockerenv"))
|
|
10821
10939
|
return true;
|
|
10822
|
-
const cg =
|
|
10940
|
+
const cg = readFileSync10("/proc/1/cgroup", "utf8");
|
|
10823
10941
|
if (/(docker|kubepods|containerd)/.test(cg))
|
|
10824
10942
|
return true;
|
|
10825
10943
|
} catch {}
|
|
@@ -10838,10 +10956,10 @@ async function runDaemon(opts = {}) {
|
|
|
10838
10956
|
`);
|
|
10839
10957
|
}
|
|
10840
10958
|
const fpCheck = checkFingerprint();
|
|
10841
|
-
const
|
|
10959
|
+
const policy2 = opts.clonePolicy ?? "refuse";
|
|
10842
10960
|
if (fpCheck.result === "mismatch") {
|
|
10843
10961
|
const msg = `host_fingerprint mismatch: this daemon dir was started on a different host.`;
|
|
10844
|
-
if (
|
|
10962
|
+
if (policy2 === "refuse") {
|
|
10845
10963
|
process.stderr.write(`${msg}
|
|
10846
10964
|
`);
|
|
10847
10965
|
process.stderr.write(` stored host_id: ${fpCheck.stored?.host_id}
|
|
@@ -10855,7 +10973,7 @@ async function runDaemon(opts = {}) {
|
|
|
10855
10973
|
releaseSingletonLock();
|
|
10856
10974
|
return 4;
|
|
10857
10975
|
}
|
|
10858
|
-
if (
|
|
10976
|
+
if (policy2 === "warn") {
|
|
10859
10977
|
process.stderr.write(`WARN: ${msg} (continuing per [clone] policy=warn)
|
|
10860
10978
|
`);
|
|
10861
10979
|
}
|
|
@@ -10944,6 +11062,7 @@ async function runDaemon(opts = {}) {
|
|
|
10944
11062
|
}
|
|
10945
11063
|
let drain = null;
|
|
10946
11064
|
drain = startDrainWorker({ db: outboxDb, brokers });
|
|
11065
|
+
startReaper();
|
|
10947
11066
|
const ipc2 = startIpcServer({
|
|
10948
11067
|
localToken,
|
|
10949
11068
|
tcpEnabled,
|
|
@@ -11005,6 +11124,7 @@ var init_run = __esm(() => {
|
|
|
11005
11124
|
init_lock();
|
|
11006
11125
|
init_local_token();
|
|
11007
11126
|
init_server();
|
|
11127
|
+
init_session_registry();
|
|
11008
11128
|
init_broker();
|
|
11009
11129
|
init_drain();
|
|
11010
11130
|
init_inbound();
|
|
@@ -11020,10 +11140,10 @@ __export(exports_service_install, {
|
|
|
11020
11140
|
installService: () => installService,
|
|
11021
11141
|
detectPlatform: () => detectPlatform
|
|
11022
11142
|
});
|
|
11023
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as
|
|
11143
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync11, unlinkSync as unlinkSync5, readFileSync as readFileSync11 } from "node:fs";
|
|
11024
11144
|
import { execSync as execSync2 } from "node:child_process";
|
|
11025
|
-
import { homedir as
|
|
11026
|
-
import { join as
|
|
11145
|
+
import { homedir as homedir5 } from "node:os";
|
|
11146
|
+
import { join as join8, dirname as dirname5 } from "node:path";
|
|
11027
11147
|
function detectPlatform() {
|
|
11028
11148
|
if (process.platform === "darwin")
|
|
11029
11149
|
return "darwin";
|
|
@@ -11074,7 +11194,7 @@ function uninstallService() {
|
|
|
11074
11194
|
return { platform: platform5, removed };
|
|
11075
11195
|
}
|
|
11076
11196
|
function darwinPlistPath() {
|
|
11077
|
-
return
|
|
11197
|
+
return join8(homedir5(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
|
|
11078
11198
|
}
|
|
11079
11199
|
function installDarwin(args) {
|
|
11080
11200
|
const plist = darwinPlistPath();
|
|
@@ -11108,18 +11228,18 @@ function installDarwin(args) {
|
|
|
11108
11228
|
<key>StandardErrorPath</key>
|
|
11109
11229
|
<string>${escapeXml(log2)}</string>
|
|
11110
11230
|
<key>WorkingDirectory</key>
|
|
11111
|
-
<string>${escapeXml(
|
|
11231
|
+
<string>${escapeXml(homedir5())}</string>
|
|
11112
11232
|
<key>EnvironmentVariables</key>
|
|
11113
11233
|
<dict>
|
|
11114
11234
|
<key>HOME</key>
|
|
11115
|
-
<string>${escapeXml(
|
|
11235
|
+
<string>${escapeXml(homedir5())}</string>
|
|
11116
11236
|
<key>PATH</key>
|
|
11117
11237
|
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
11118
11238
|
</dict>
|
|
11119
11239
|
</dict>
|
|
11120
11240
|
</plist>
|
|
11121
11241
|
`;
|
|
11122
|
-
|
|
11242
|
+
writeFileSync11(plist, xml, { mode: 420 });
|
|
11123
11243
|
return {
|
|
11124
11244
|
platform: "darwin",
|
|
11125
11245
|
unitPath: plist,
|
|
@@ -11127,7 +11247,7 @@ function installDarwin(args) {
|
|
|
11127
11247
|
};
|
|
11128
11248
|
}
|
|
11129
11249
|
function linuxUnitPath() {
|
|
11130
|
-
return
|
|
11250
|
+
return join8(homedir5(), ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
11131
11251
|
}
|
|
11132
11252
|
function installLinux(args) {
|
|
11133
11253
|
const unit = linuxUnitPath();
|
|
@@ -11156,7 +11276,7 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
|
|
|
11156
11276
|
[Install]
|
|
11157
11277
|
WantedBy=default.target
|
|
11158
11278
|
`;
|
|
11159
|
-
|
|
11279
|
+
writeFileSync11(unit, content, { mode: 420 });
|
|
11160
11280
|
return {
|
|
11161
11281
|
platform: "linux",
|
|
11162
11282
|
unitPath: unit,
|
|
@@ -11179,7 +11299,7 @@ function readInstalledUnit() {
|
|
|
11179
11299
|
if (!existsSync12(path2))
|
|
11180
11300
|
return { platform: platform5, path: null, content: null };
|
|
11181
11301
|
try {
|
|
11182
|
-
return { platform: platform5, path: path2, content:
|
|
11302
|
+
return { platform: platform5, path: path2, content: readFileSync11(path2, "utf8") };
|
|
11183
11303
|
} catch {
|
|
11184
11304
|
return { platform: platform5, path: path2, content: null };
|
|
11185
11305
|
}
|
|
@@ -11523,17 +11643,17 @@ import {
|
|
|
11523
11643
|
copyFileSync,
|
|
11524
11644
|
existsSync as existsSync13,
|
|
11525
11645
|
mkdirSync as mkdirSync8,
|
|
11526
|
-
readFileSync as
|
|
11527
|
-
writeFileSync as
|
|
11646
|
+
readFileSync as readFileSync12,
|
|
11647
|
+
writeFileSync as writeFileSync12
|
|
11528
11648
|
} from "node:fs";
|
|
11529
|
-
import { homedir as
|
|
11530
|
-
import { dirname as dirname6, join as
|
|
11649
|
+
import { homedir as homedir6, platform as platform5 } from "node:os";
|
|
11650
|
+
import { dirname as dirname6, join as join9, resolve } from "node:path";
|
|
11531
11651
|
import { fileURLToPath } from "node:url";
|
|
11532
11652
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
11533
11653
|
function readClaudeConfig() {
|
|
11534
11654
|
if (!existsSync13(CLAUDE_CONFIG))
|
|
11535
11655
|
return {};
|
|
11536
|
-
const text =
|
|
11656
|
+
const text = readFileSync12(CLAUDE_CONFIG, "utf-8").trim();
|
|
11537
11657
|
if (!text)
|
|
11538
11658
|
return {};
|
|
11539
11659
|
try {
|
|
@@ -11545,10 +11665,10 @@ function readClaudeConfig() {
|
|
|
11545
11665
|
function backupClaudeConfig() {
|
|
11546
11666
|
if (!existsSync13(CLAUDE_CONFIG))
|
|
11547
11667
|
return;
|
|
11548
|
-
const backupDir =
|
|
11668
|
+
const backupDir = join9(dirname6(CLAUDE_CONFIG), ".claude", "backups");
|
|
11549
11669
|
mkdirSync8(backupDir, { recursive: true });
|
|
11550
11670
|
const ts = Date.now();
|
|
11551
|
-
const dest =
|
|
11671
|
+
const dest = join9(backupDir, `.claude.json.pre-claudemesh.${ts}`);
|
|
11552
11672
|
copyFileSync(CLAUDE_CONFIG, dest);
|
|
11553
11673
|
}
|
|
11554
11674
|
function patchMcpServer(entry) {
|
|
@@ -11586,7 +11706,7 @@ function removeMcpServer() {
|
|
|
11586
11706
|
}
|
|
11587
11707
|
function flushClaudeConfig(obj) {
|
|
11588
11708
|
mkdirSync8(dirname6(CLAUDE_CONFIG), { recursive: true });
|
|
11589
|
-
|
|
11709
|
+
writeFileSync12(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
|
|
11590
11710
|
`, "utf-8");
|
|
11591
11711
|
try {
|
|
11592
11712
|
chmodSync4(CLAUDE_CONFIG, 384);
|
|
@@ -11608,7 +11728,7 @@ function resolveEntry() {
|
|
|
11608
11728
|
function resolveBundledSkillsDir() {
|
|
11609
11729
|
const here = fileURLToPath(import.meta.url);
|
|
11610
11730
|
const pkgRoot = resolve(dirname6(here), "..", "..");
|
|
11611
|
-
const skillsDir =
|
|
11731
|
+
const skillsDir = join9(pkgRoot, "skills");
|
|
11612
11732
|
if (existsSync13(skillsDir))
|
|
11613
11733
|
return skillsDir;
|
|
11614
11734
|
return null;
|
|
@@ -11622,13 +11742,13 @@ function installSkills() {
|
|
|
11622
11742
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
11623
11743
|
if (!entry.isDirectory())
|
|
11624
11744
|
continue;
|
|
11625
|
-
const srcDir =
|
|
11626
|
-
const dstDir =
|
|
11745
|
+
const srcDir = join9(src, entry.name);
|
|
11746
|
+
const dstDir = join9(CLAUDE_SKILLS_ROOT, entry.name);
|
|
11627
11747
|
mkdirSync8(dstDir, { recursive: true });
|
|
11628
11748
|
for (const file of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
11629
11749
|
if (!file.isFile())
|
|
11630
11750
|
continue;
|
|
11631
|
-
copyFileSync(
|
|
11751
|
+
copyFileSync(join9(srcDir, file.name), join9(dstDir, file.name));
|
|
11632
11752
|
}
|
|
11633
11753
|
installed.push(entry.name);
|
|
11634
11754
|
}
|
|
@@ -11643,7 +11763,7 @@ function uninstallSkills() {
|
|
|
11643
11763
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
11644
11764
|
if (!entry.isDirectory())
|
|
11645
11765
|
continue;
|
|
11646
|
-
const dstDir =
|
|
11766
|
+
const dstDir = join9(CLAUDE_SKILLS_ROOT, entry.name);
|
|
11647
11767
|
if (existsSync13(dstDir)) {
|
|
11648
11768
|
try {
|
|
11649
11769
|
fs.rmSync(dstDir, { recursive: true, force: true });
|
|
@@ -11671,7 +11791,7 @@ function entriesEqual(a, b) {
|
|
|
11671
11791
|
function readClaudeSettings() {
|
|
11672
11792
|
if (!existsSync13(CLAUDE_SETTINGS))
|
|
11673
11793
|
return {};
|
|
11674
|
-
const text =
|
|
11794
|
+
const text = readFileSync12(CLAUDE_SETTINGS, "utf-8").trim();
|
|
11675
11795
|
if (!text)
|
|
11676
11796
|
return {};
|
|
11677
11797
|
try {
|
|
@@ -11682,7 +11802,7 @@ function readClaudeSettings() {
|
|
|
11682
11802
|
}
|
|
11683
11803
|
function writeClaudeSettings(obj) {
|
|
11684
11804
|
mkdirSync8(dirname6(CLAUDE_SETTINGS), { recursive: true });
|
|
11685
|
-
|
|
11805
|
+
writeFileSync12(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
|
|
11686
11806
|
`, "utf-8");
|
|
11687
11807
|
}
|
|
11688
11808
|
function installAllowedTools() {
|
|
@@ -11832,7 +11952,7 @@ function runInstall(args = []) {
|
|
|
11832
11952
|
const installed = installSkills();
|
|
11833
11953
|
if (installed.length > 0) {
|
|
11834
11954
|
render.ok(`Claude skill${installed.length === 1 ? "" : "s"} installed`, installed.join(", "));
|
|
11835
|
-
render.info(dim(` ${
|
|
11955
|
+
render.info(dim(` ${join9(CLAUDE_SKILLS_ROOT, installed[0])}/SKILL.md`));
|
|
11836
11956
|
}
|
|
11837
11957
|
} catch (e) {
|
|
11838
11958
|
render.warn(`skill install failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
@@ -11969,9 +12089,9 @@ var init_install = __esm(() => {
|
|
|
11969
12089
|
init_facade();
|
|
11970
12090
|
init_render();
|
|
11971
12091
|
init_styles();
|
|
11972
|
-
CLAUDE_CONFIG =
|
|
11973
|
-
CLAUDE_SETTINGS =
|
|
11974
|
-
CLAUDE_SKILLS_ROOT =
|
|
12092
|
+
CLAUDE_CONFIG = join9(homedir6(), ".claude.json");
|
|
12093
|
+
CLAUDE_SETTINGS = join9(homedir6(), ".claude", "settings.json");
|
|
12094
|
+
CLAUDE_SKILLS_ROOT = join9(homedir6(), ".claude", "skills");
|
|
11975
12095
|
CLAUDEMESH_TOOLS = [
|
|
11976
12096
|
"mcp__claudemesh__cancel_scheduled",
|
|
11977
12097
|
"mcp__claudemesh__check_messages",
|
|
@@ -12026,26 +12146,26 @@ var exports_uninstall = {};
|
|
|
12026
12146
|
__export(exports_uninstall, {
|
|
12027
12147
|
uninstall: () => uninstall
|
|
12028
12148
|
});
|
|
12029
|
-
import { readFileSync as
|
|
12030
|
-
import { join as
|
|
12031
|
-
import { homedir as
|
|
12149
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync14, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
|
|
12150
|
+
import { join as join10, dirname as dirname7 } from "node:path";
|
|
12151
|
+
import { homedir as homedir7 } from "node:os";
|
|
12032
12152
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
12033
12153
|
function bundledSkillsDir() {
|
|
12034
12154
|
const here = fileURLToPath2(import.meta.url);
|
|
12035
|
-
const pkgRoot =
|
|
12036
|
-
const skillsDir =
|
|
12155
|
+
const pkgRoot = join10(dirname7(here), "..", "..");
|
|
12156
|
+
const skillsDir = join10(pkgRoot, "skills");
|
|
12037
12157
|
return existsSync14(skillsDir) ? skillsDir : null;
|
|
12038
12158
|
}
|
|
12039
12159
|
async function uninstall() {
|
|
12040
12160
|
let removed = 0;
|
|
12041
12161
|
if (existsSync14(PATHS.CLAUDE_JSON)) {
|
|
12042
12162
|
try {
|
|
12043
|
-
const raw =
|
|
12163
|
+
const raw = readFileSync13(PATHS.CLAUDE_JSON, "utf-8");
|
|
12044
12164
|
const config = JSON.parse(raw);
|
|
12045
12165
|
const servers = config.mcpServers;
|
|
12046
12166
|
if (servers && "claudemesh" in servers) {
|
|
12047
12167
|
delete servers.claudemesh;
|
|
12048
|
-
|
|
12168
|
+
writeFileSync13(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
|
|
12049
12169
|
`, "utf-8");
|
|
12050
12170
|
render.ok("removed MCP server", dim("~/.claude.json"));
|
|
12051
12171
|
removed++;
|
|
@@ -12054,7 +12174,7 @@ async function uninstall() {
|
|
|
12054
12174
|
}
|
|
12055
12175
|
if (existsSync14(PATHS.CLAUDE_SETTINGS)) {
|
|
12056
12176
|
try {
|
|
12057
|
-
const raw =
|
|
12177
|
+
const raw = readFileSync13(PATHS.CLAUDE_SETTINGS, "utf-8");
|
|
12058
12178
|
const config = JSON.parse(raw);
|
|
12059
12179
|
const hooks = config.hooks;
|
|
12060
12180
|
if (hooks) {
|
|
@@ -12075,7 +12195,7 @@ async function uninstall() {
|
|
|
12075
12195
|
}
|
|
12076
12196
|
}
|
|
12077
12197
|
if (removedHooks > 0) {
|
|
12078
|
-
|
|
12198
|
+
writeFileSync13(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
|
|
12079
12199
|
`, "utf-8");
|
|
12080
12200
|
render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
|
|
12081
12201
|
removed++;
|
|
@@ -12090,7 +12210,7 @@ async function uninstall() {
|
|
|
12090
12210
|
for (const entry of readdirSync2(src, { withFileTypes: true })) {
|
|
12091
12211
|
if (!entry.isDirectory())
|
|
12092
12212
|
continue;
|
|
12093
|
-
const dst =
|
|
12213
|
+
const dst = join10(CLAUDE_SKILLS_ROOT2, entry.name);
|
|
12094
12214
|
if (existsSync14(dst)) {
|
|
12095
12215
|
try {
|
|
12096
12216
|
rmSync2(dst, { recursive: true, force: true });
|
|
@@ -12115,7 +12235,7 @@ var init_uninstall = __esm(() => {
|
|
|
12115
12235
|
init_render();
|
|
12116
12236
|
init_styles();
|
|
12117
12237
|
init_exit_codes();
|
|
12118
|
-
CLAUDE_SKILLS_ROOT2 =
|
|
12238
|
+
CLAUDE_SKILLS_ROOT2 = join10(homedir7(), ".claude", "skills");
|
|
12119
12239
|
});
|
|
12120
12240
|
|
|
12121
12241
|
// src/commands/doctor.ts
|
|
@@ -12123,9 +12243,9 @@ var exports_doctor = {};
|
|
|
12123
12243
|
__export(exports_doctor, {
|
|
12124
12244
|
runDoctor: () => runDoctor
|
|
12125
12245
|
});
|
|
12126
|
-
import { existsSync as existsSync15, readFileSync as
|
|
12127
|
-
import { homedir as
|
|
12128
|
-
import { join as
|
|
12246
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, statSync as statSync3 } from "node:fs";
|
|
12247
|
+
import { homedir as homedir8, platform as platform6 } from "node:os";
|
|
12248
|
+
import { join as join11 } from "node:path";
|
|
12129
12249
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
12130
12250
|
function checkNode() {
|
|
12131
12251
|
const major = Number(process.versions.node.split(".")[0]);
|
|
@@ -12149,7 +12269,7 @@ function checkClaudeOnPath() {
|
|
|
12149
12269
|
};
|
|
12150
12270
|
}
|
|
12151
12271
|
function checkMcpRegistered() {
|
|
12152
|
-
const claudeConfig =
|
|
12272
|
+
const claudeConfig = join11(homedir8(), ".claude.json");
|
|
12153
12273
|
if (!existsSync15(claudeConfig)) {
|
|
12154
12274
|
return {
|
|
12155
12275
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
@@ -12158,7 +12278,7 @@ function checkMcpRegistered() {
|
|
|
12158
12278
|
};
|
|
12159
12279
|
}
|
|
12160
12280
|
try {
|
|
12161
|
-
const cfg = JSON.parse(
|
|
12281
|
+
const cfg = JSON.parse(readFileSync14(claudeConfig, "utf-8"));
|
|
12162
12282
|
const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
|
|
12163
12283
|
return {
|
|
12164
12284
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
@@ -12175,7 +12295,7 @@ function checkMcpRegistered() {
|
|
|
12175
12295
|
}
|
|
12176
12296
|
}
|
|
12177
12297
|
function checkHooksRegistered() {
|
|
12178
|
-
const settings =
|
|
12298
|
+
const settings = join11(homedir8(), ".claude", "settings.json");
|
|
12179
12299
|
if (!existsSync15(settings)) {
|
|
12180
12300
|
return {
|
|
12181
12301
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
@@ -12184,7 +12304,7 @@ function checkHooksRegistered() {
|
|
|
12184
12304
|
};
|
|
12185
12305
|
}
|
|
12186
12306
|
try {
|
|
12187
|
-
const raw =
|
|
12307
|
+
const raw = readFileSync14(settings, "utf-8");
|
|
12188
12308
|
const has = raw.includes("claudemesh hook ");
|
|
12189
12309
|
return {
|
|
12190
12310
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
@@ -12560,13 +12680,13 @@ var init_check_claude_binary = __esm(() => {
|
|
|
12560
12680
|
});
|
|
12561
12681
|
|
|
12562
12682
|
// src/services/health/check-mcp-registered.ts
|
|
12563
|
-
import { existsSync as existsSync17, readFileSync as
|
|
12683
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
|
|
12564
12684
|
function checkMcpRegistered2() {
|
|
12565
12685
|
try {
|
|
12566
12686
|
if (!existsSync17(PATHS.CLAUDE_JSON)) {
|
|
12567
12687
|
return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
|
|
12568
12688
|
}
|
|
12569
|
-
const raw =
|
|
12689
|
+
const raw = readFileSync15(PATHS.CLAUDE_JSON, "utf-8");
|
|
12570
12690
|
const config = JSON.parse(raw);
|
|
12571
12691
|
if (config.mcpServers && "claudemesh" in config.mcpServers) {
|
|
12572
12692
|
return { name: "mcp-registered", ok: true, message: "MCP server registered" };
|
|
@@ -12581,13 +12701,13 @@ var init_check_mcp_registered = __esm(() => {
|
|
|
12581
12701
|
});
|
|
12582
12702
|
|
|
12583
12703
|
// src/services/health/check-hooks-registered.ts
|
|
12584
|
-
import { existsSync as existsSync18, readFileSync as
|
|
12704
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
|
|
12585
12705
|
function checkHooksRegistered2() {
|
|
12586
12706
|
try {
|
|
12587
12707
|
if (!existsSync18(PATHS.CLAUDE_SETTINGS)) {
|
|
12588
12708
|
return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
|
|
12589
12709
|
}
|
|
12590
|
-
const raw =
|
|
12710
|
+
const raw = readFileSync16(PATHS.CLAUDE_SETTINGS, "utf-8");
|
|
12591
12711
|
const config = JSON.parse(raw);
|
|
12592
12712
|
if (config.hooks) {
|
|
12593
12713
|
return { name: "hooks-registered", ok: true, message: "Hooks configured" };
|
|
@@ -12623,13 +12743,13 @@ var init_check_config_perms = __esm(() => {
|
|
|
12623
12743
|
});
|
|
12624
12744
|
|
|
12625
12745
|
// src/services/health/check-keypairs-valid.ts
|
|
12626
|
-
import { existsSync as existsSync20, readFileSync as
|
|
12746
|
+
import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
|
|
12627
12747
|
function checkKeypairsValid() {
|
|
12628
12748
|
if (!existsSync20(PATHS.CONFIG_FILE)) {
|
|
12629
12749
|
return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
|
|
12630
12750
|
}
|
|
12631
12751
|
try {
|
|
12632
|
-
const raw =
|
|
12752
|
+
const raw = readFileSync17(PATHS.CONFIG_FILE, "utf-8");
|
|
12633
12753
|
const config = JSON.parse(raw);
|
|
12634
12754
|
const meshes = config.meshes ?? [];
|
|
12635
12755
|
if (meshes.length === 0) {
|
|
@@ -13109,18 +13229,18 @@ var exports_url_handler = {};
|
|
|
13109
13229
|
__export(exports_url_handler, {
|
|
13110
13230
|
runUrlHandler: () => runUrlHandler
|
|
13111
13231
|
});
|
|
13112
|
-
import { platform as platform7, homedir as
|
|
13113
|
-
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as
|
|
13114
|
-
import { join as
|
|
13232
|
+
import { platform as platform7, homedir as homedir9 } from "node:os";
|
|
13233
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
|
|
13234
|
+
import { join as join12 } from "node:path";
|
|
13115
13235
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
13116
13236
|
function resolveClaudemeshBin() {
|
|
13117
13237
|
return process.argv[1] ?? "claudemesh";
|
|
13118
13238
|
}
|
|
13119
13239
|
function installDarwin2() {
|
|
13120
13240
|
const binPath = resolveClaudemeshBin();
|
|
13121
|
-
const appDir =
|
|
13122
|
-
const contents =
|
|
13123
|
-
const macOS =
|
|
13241
|
+
const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
|
|
13242
|
+
const contents = join12(appDir, "Contents");
|
|
13243
|
+
const macOS = join12(contents, "MacOS");
|
|
13124
13244
|
mkdirSync9(macOS, { recursive: true });
|
|
13125
13245
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
13126
13246
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -13144,7 +13264,7 @@ function installDarwin2() {
|
|
|
13144
13264
|
</array>
|
|
13145
13265
|
</dict>
|
|
13146
13266
|
</plist>`;
|
|
13147
|
-
|
|
13267
|
+
writeFileSync14(join12(contents, "Info.plist"), plist);
|
|
13148
13268
|
const shim = `#!/bin/sh
|
|
13149
13269
|
URL="$1"
|
|
13150
13270
|
CODE=\${URL#claudemesh://}
|
|
@@ -13158,8 +13278,8 @@ tell application "Terminal"
|
|
|
13158
13278
|
end tell
|
|
13159
13279
|
EOF
|
|
13160
13280
|
`;
|
|
13161
|
-
const shimPath =
|
|
13162
|
-
|
|
13281
|
+
const shimPath = join12(macOS, "open-url");
|
|
13282
|
+
writeFileSync14(shimPath, shim);
|
|
13163
13283
|
chmodSync5(shimPath, 493);
|
|
13164
13284
|
const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
|
|
13165
13285
|
if (lsreg.status !== 0) {
|
|
@@ -13170,7 +13290,7 @@ EOF
|
|
|
13170
13290
|
}
|
|
13171
13291
|
function installLinux2() {
|
|
13172
13292
|
const binPath = resolveClaudemeshBin();
|
|
13173
|
-
const appsDir =
|
|
13293
|
+
const appsDir = join12(homedir9(), ".local", "share", "applications");
|
|
13174
13294
|
mkdirSync9(appsDir, { recursive: true });
|
|
13175
13295
|
const desktop = `[Desktop Entry]
|
|
13176
13296
|
Type=Application
|
|
@@ -13182,8 +13302,8 @@ Terminal=true
|
|
|
13182
13302
|
MimeType=x-scheme-handler/claudemesh;
|
|
13183
13303
|
NoDisplay=true
|
|
13184
13304
|
`;
|
|
13185
|
-
const desktopPath =
|
|
13186
|
-
|
|
13305
|
+
const desktopPath = join12(appsDir, "claudemesh.desktop");
|
|
13306
|
+
writeFileSync14(desktopPath, desktop);
|
|
13187
13307
|
const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
|
|
13188
13308
|
if (xdg1.status !== 0) {
|
|
13189
13309
|
render.warn("xdg-mime not available — skipped mime default registration");
|
|
@@ -13205,8 +13325,8 @@ function installWindows() {
|
|
|
13205
13325
|
`[HKEY_CURRENT_USER\\Software\\Classes\\claudemesh\\shell\\open\\command]`,
|
|
13206
13326
|
`@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
|
|
13207
13327
|
];
|
|
13208
|
-
const regPath =
|
|
13209
|
-
|
|
13328
|
+
const regPath = join12(homedir9(), "claudemesh-handler.reg");
|
|
13329
|
+
writeFileSync14(regPath, lines.join(`\r
|
|
13210
13330
|
`));
|
|
13211
13331
|
const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
|
|
13212
13332
|
if (res.status !== 0) {
|
|
@@ -13217,14 +13337,14 @@ function installWindows() {
|
|
|
13217
13337
|
return EXIT.SUCCESS;
|
|
13218
13338
|
}
|
|
13219
13339
|
function uninstallDarwin() {
|
|
13220
|
-
const appDir =
|
|
13340
|
+
const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
|
|
13221
13341
|
if (existsSync21(appDir))
|
|
13222
13342
|
rmSync3(appDir, { recursive: true, force: true });
|
|
13223
13343
|
render.ok("removed claudemesh:// handler on macOS");
|
|
13224
13344
|
return EXIT.SUCCESS;
|
|
13225
13345
|
}
|
|
13226
13346
|
function uninstallLinux() {
|
|
13227
|
-
const desktopPath =
|
|
13347
|
+
const desktopPath = join12(homedir9(), ".local", "share", "applications", "claudemesh.desktop");
|
|
13228
13348
|
if (existsSync21(desktopPath))
|
|
13229
13349
|
rmSync3(desktopPath, { force: true });
|
|
13230
13350
|
render.ok("removed claudemesh:// handler on Linux");
|
|
@@ -13270,9 +13390,9 @@ var exports_status_line = {};
|
|
|
13270
13390
|
__export(exports_status_line, {
|
|
13271
13391
|
runStatusLine: () => runStatusLine
|
|
13272
13392
|
});
|
|
13273
|
-
import { existsSync as existsSync22, readFileSync as
|
|
13274
|
-
import { join as
|
|
13275
|
-
import { homedir as
|
|
13393
|
+
import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
|
|
13394
|
+
import { join as join13 } from "node:path";
|
|
13395
|
+
import { homedir as homedir10 } from "node:os";
|
|
13276
13396
|
async function runStatusLine() {
|
|
13277
13397
|
try {
|
|
13278
13398
|
const config = readConfig();
|
|
@@ -13280,11 +13400,11 @@ async function runStatusLine() {
|
|
|
13280
13400
|
process.stdout.write("◇ claudemesh (not joined)");
|
|
13281
13401
|
return EXIT.SUCCESS;
|
|
13282
13402
|
}
|
|
13283
|
-
const cachePath =
|
|
13403
|
+
const cachePath = join13(homedir10(), ".claudemesh", "peer-cache.json");
|
|
13284
13404
|
let cache = {};
|
|
13285
13405
|
if (existsSync22(cachePath)) {
|
|
13286
13406
|
try {
|
|
13287
|
-
cache = JSON.parse(
|
|
13407
|
+
cache = JSON.parse(readFileSync18(cachePath, "utf-8"));
|
|
13288
13408
|
} catch {}
|
|
13289
13409
|
}
|
|
13290
13410
|
const pick = config.meshes[0];
|
|
@@ -13315,7 +13435,7 @@ __export(exports_backup, {
|
|
|
13315
13435
|
runRestore: () => runRestore,
|
|
13316
13436
|
runBackup: () => runBackup
|
|
13317
13437
|
});
|
|
13318
|
-
import { readFileSync as
|
|
13438
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, existsSync as existsSync23 } from "node:fs";
|
|
13319
13439
|
import { createInterface as createInterface11 } from "node:readline";
|
|
13320
13440
|
function readHidden(prompt5) {
|
|
13321
13441
|
return new Promise((resolve2) => {
|
|
@@ -13361,7 +13481,7 @@ async function runBackup(outPath) {
|
|
|
13361
13481
|
console.error(" No config found — nothing to back up. Join a mesh first.");
|
|
13362
13482
|
return EXIT.NOT_FOUND;
|
|
13363
13483
|
}
|
|
13364
|
-
const plaintext =
|
|
13484
|
+
const plaintext = readFileSync19(configPath);
|
|
13365
13485
|
const pass = await readHidden(" Passphrase (min 12 chars): ");
|
|
13366
13486
|
if (pass.length < 12) {
|
|
13367
13487
|
console.error(" ✗ Passphrase too short.");
|
|
@@ -13379,7 +13499,7 @@ async function runBackup(outPath) {
|
|
|
13379
13499
|
const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
|
|
13380
13500
|
const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
|
|
13381
13501
|
const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
|
|
13382
|
-
|
|
13502
|
+
writeFileSync15(file, blob, { mode: 384 });
|
|
13383
13503
|
console.log(`
|
|
13384
13504
|
✓ Backup saved: ${file}`);
|
|
13385
13505
|
console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
|
|
@@ -13395,7 +13515,7 @@ async function runRestore(inPath) {
|
|
|
13395
13515
|
console.error(` ✗ File not found: ${inPath}`);
|
|
13396
13516
|
return EXIT.NOT_FOUND;
|
|
13397
13517
|
}
|
|
13398
|
-
const blob =
|
|
13518
|
+
const blob = readFileSync19(inPath);
|
|
13399
13519
|
if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
|
|
13400
13520
|
console.error(" ✗ Not a claudemesh backup file (bad magic).");
|
|
13401
13521
|
return EXIT.INVALID_ARGS;
|
|
@@ -13416,10 +13536,10 @@ async function runRestore(inPath) {
|
|
|
13416
13536
|
const configPath = getConfigPath();
|
|
13417
13537
|
if (existsSync23(configPath)) {
|
|
13418
13538
|
const backupOld = `${configPath}.before-restore.${Date.now()}`;
|
|
13419
|
-
|
|
13539
|
+
writeFileSync15(backupOld, readFileSync19(configPath), { mode: 384 });
|
|
13420
13540
|
console.log(` ↻ Existing config saved to ${backupOld}`);
|
|
13421
13541
|
}
|
|
13422
|
-
|
|
13542
|
+
writeFileSync15(configPath, Buffer.from(plaintext), { mode: 384 });
|
|
13423
13543
|
console.log(`
|
|
13424
13544
|
✓ Config restored to ${configPath}`);
|
|
13425
13545
|
console.log(" Run `claudemesh list` to verify your meshes.\n");
|
|
@@ -13440,7 +13560,7 @@ __export(exports_upgrade, {
|
|
|
13440
13560
|
});
|
|
13441
13561
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
13442
13562
|
import { existsSync as existsSync24 } from "node:fs";
|
|
13443
|
-
import { dirname as dirname8, join as
|
|
13563
|
+
import { dirname as dirname8, join as join14, resolve as resolve2 } from "node:path";
|
|
13444
13564
|
async function latestVersion() {
|
|
13445
13565
|
try {
|
|
13446
13566
|
const res = await fetch(URLS.NPM_REGISTRY, { signal: AbortSignal.timeout(8000) });
|
|
@@ -13453,14 +13573,14 @@ async function latestVersion() {
|
|
|
13453
13573
|
}
|
|
13454
13574
|
}
|
|
13455
13575
|
function findNpm() {
|
|
13456
|
-
const portable =
|
|
13576
|
+
const portable = join14(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
|
|
13457
13577
|
if (existsSync24(portable)) {
|
|
13458
|
-
return { npm: portable, prefix:
|
|
13578
|
+
return { npm: portable, prefix: join14(process.env.HOME ?? "", ".claudemesh") };
|
|
13459
13579
|
}
|
|
13460
13580
|
let cur = resolve2(process.argv[1] ?? ".");
|
|
13461
13581
|
for (let i = 0;i < 6; i++) {
|
|
13462
13582
|
cur = dirname8(cur);
|
|
13463
|
-
const candidate =
|
|
13583
|
+
const candidate = join14(cur, "bin", "npm");
|
|
13464
13584
|
if (existsSync24(candidate))
|
|
13465
13585
|
return { npm: candidate };
|
|
13466
13586
|
}
|
|
@@ -13523,9 +13643,9 @@ __export(exports_grants, {
|
|
|
13523
13643
|
runBlock: () => runBlock,
|
|
13524
13644
|
isAllowed: () => isAllowed
|
|
13525
13645
|
});
|
|
13526
|
-
import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as
|
|
13527
|
-
import { homedir as
|
|
13528
|
-
import { join as
|
|
13646
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "node:fs";
|
|
13647
|
+
import { homedir as homedir11 } from "node:os";
|
|
13648
|
+
import { join as join15 } from "node:path";
|
|
13529
13649
|
async function syncToBroker(meshSlug, grants) {
|
|
13530
13650
|
const auth = getStoredToken();
|
|
13531
13651
|
if (!auth)
|
|
@@ -13546,16 +13666,16 @@ function readGrants() {
|
|
|
13546
13666
|
if (!existsSync25(GRANT_FILE))
|
|
13547
13667
|
return {};
|
|
13548
13668
|
try {
|
|
13549
|
-
return JSON.parse(
|
|
13669
|
+
return JSON.parse(readFileSync20(GRANT_FILE, "utf-8"));
|
|
13550
13670
|
} catch {
|
|
13551
13671
|
return {};
|
|
13552
13672
|
}
|
|
13553
13673
|
}
|
|
13554
13674
|
function writeGrants(g) {
|
|
13555
|
-
const dir =
|
|
13675
|
+
const dir = join15(homedir11(), ".claudemesh");
|
|
13556
13676
|
if (!existsSync25(dir))
|
|
13557
13677
|
mkdirSync10(dir, { recursive: true });
|
|
13558
|
-
|
|
13678
|
+
writeFileSync16(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
|
|
13559
13679
|
}
|
|
13560
13680
|
function resolveCaps(input) {
|
|
13561
13681
|
if (input.includes("all"))
|
|
@@ -13711,7 +13831,7 @@ var init_grants = __esm(() => {
|
|
|
13711
13831
|
BROKER_HTTP7 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
13712
13832
|
ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
|
|
13713
13833
|
DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
|
|
13714
|
-
GRANT_FILE =
|
|
13834
|
+
GRANT_FILE = join15(homedir11(), ".claudemesh", "grants.json");
|
|
13715
13835
|
});
|
|
13716
13836
|
|
|
13717
13837
|
// src/commands/profile.ts
|
|
@@ -15393,7 +15513,7 @@ __export(exports_file, {
|
|
|
15393
15513
|
});
|
|
15394
15514
|
import { hostname as osHostname } from "node:os";
|
|
15395
15515
|
import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
|
|
15396
|
-
import { statSync as statSync7, existsSync as existsSync26, writeFileSync as
|
|
15516
|
+
import { statSync as statSync7, existsSync as existsSync26, writeFileSync as writeFileSync17, mkdirSync as mkdirSync11 } from "node:fs";
|
|
15397
15517
|
function emitJson2(data) {
|
|
15398
15518
|
console.log(JSON.stringify(data, null, 2));
|
|
15399
15519
|
}
|
|
@@ -15490,7 +15610,7 @@ async function runFileGet(fileId, opts) {
|
|
|
15490
15610
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
15491
15611
|
const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
|
|
15492
15612
|
mkdirSync11(dirname9(outPath), { recursive: true });
|
|
15493
|
-
|
|
15613
|
+
writeFileSync17(outPath, buf);
|
|
15494
15614
|
if (opts.json) {
|
|
15495
15615
|
emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
|
|
15496
15616
|
} else {
|
|
@@ -16100,7 +16220,7 @@ __export(exports_bridge, {
|
|
|
16100
16220
|
runBridge: () => runBridge,
|
|
16101
16221
|
bridgeConfigTemplate: () => bridgeConfigTemplate
|
|
16102
16222
|
});
|
|
16103
|
-
import { readFileSync as
|
|
16223
|
+
import { readFileSync as readFileSync21, existsSync as existsSync27 } from "node:fs";
|
|
16104
16224
|
function parseConfig(text) {
|
|
16105
16225
|
const trimmed = text.trim();
|
|
16106
16226
|
if (trimmed.startsWith("{"))
|
|
@@ -16150,7 +16270,7 @@ async function runBridge(configPath) {
|
|
|
16150
16270
|
}
|
|
16151
16271
|
let cfg;
|
|
16152
16272
|
try {
|
|
16153
|
-
cfg = parseConfig(
|
|
16273
|
+
cfg = parseConfig(readFileSync21(configPath, "utf-8"));
|
|
16154
16274
|
} catch (e) {
|
|
16155
16275
|
render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
16156
16276
|
return EXIT.INVALID_ARGS;
|
|
@@ -16554,9 +16674,9 @@ function cacheKey(apiKeySecret, topicName) {
|
|
|
16554
16674
|
async function getTopicKey(args) {
|
|
16555
16675
|
const cacheId = cacheKey(args.apiKeySecret, args.topicName);
|
|
16556
16676
|
if (!args.fresh) {
|
|
16557
|
-
const
|
|
16558
|
-
if (
|
|
16559
|
-
return { ok: true, topicKey:
|
|
16677
|
+
const cached3 = cache.get(cacheId);
|
|
16678
|
+
if (cached3)
|
|
16679
|
+
return { ok: true, topicKey: cached3.topicKey };
|
|
16560
16680
|
}
|
|
16561
16681
|
let sealed;
|
|
16562
16682
|
try {
|
|
@@ -17458,9 +17578,9 @@ async function startServiceProxy(serviceName) {
|
|
|
17458
17578
|
const fetched = await client.getServiceTools(serviceName);
|
|
17459
17579
|
tools = fetched;
|
|
17460
17580
|
} catch {
|
|
17461
|
-
const
|
|
17462
|
-
if (
|
|
17463
|
-
tools =
|
|
17581
|
+
const cached3 = client.serviceCatalog.find((s) => s.name === serviceName);
|
|
17582
|
+
if (cached3)
|
|
17583
|
+
tools = cached3.tools;
|
|
17464
17584
|
}
|
|
17465
17585
|
if (tools.length === 0) {
|
|
17466
17586
|
process.stderr.write(`[mesh:${serviceName}] no tools found — service may not be running
|
|
@@ -18205,10 +18325,12 @@ async function gate(ctx, opts) {
|
|
|
18205
18325
|
}
|
|
18206
18326
|
|
|
18207
18327
|
// src/entrypoints/cli.ts
|
|
18328
|
+
init_policy();
|
|
18208
18329
|
init_styles();
|
|
18209
18330
|
installSignalHandlers();
|
|
18210
18331
|
installErrorHandlers();
|
|
18211
18332
|
var { command, positionals, flags } = parseArgv(process.argv);
|
|
18333
|
+
setDaemonPolicy(policyFromFlags(flags));
|
|
18212
18334
|
function resolveApprovalMode() {
|
|
18213
18335
|
const raw = flags["approval-mode"] ?? process.env.CLAUDEMESH_APPROVAL_MODE ?? null;
|
|
18214
18336
|
if (raw === "plan" || raw === "read-only" || raw === "write" || raw === "yolo")
|
|
@@ -18385,6 +18507,8 @@ Flags
|
|
|
18385
18507
|
--policy <path> override policy file
|
|
18386
18508
|
-y, --yes skip confirmations (= --approval-mode yolo)
|
|
18387
18509
|
-q, --quiet suppress non-essential output
|
|
18510
|
+
--strict require daemon for broker-touching verbs (no cold-path fallback)
|
|
18511
|
+
--no-daemon skip daemon entirely; open broker WS directly (CI / sandboxed scripts)
|
|
18388
18512
|
`;
|
|
18389
18513
|
function colorizeHelp(raw) {
|
|
18390
18514
|
const lines = raw.split(`
|
|
@@ -19426,4 +19550,4 @@ main().catch((err) => {
|
|
|
19426
19550
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
19427
19551
|
});
|
|
19428
19552
|
|
|
19429
|
-
//# debugId=
|
|
19553
|
+
//# debugId=FBD494B01BF81C7164756E2164756E21
|