claudemesh-cli 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -103,7 +103,7 @@ __export(exports_urls, {
103
103
  VERSION: () => VERSION,
104
104
  URLS: () => URLS
105
105
  });
106
- var URLS, VERSION = "1.25.0", env;
106
+ var URLS, VERSION = "1.26.0", env;
107
107
  var init_urls = __esm(() => {
108
108
  URLS = {
109
109
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -6944,7 +6944,8 @@ async function trySendViaDaemon(args) {
6944
6944
  to: args.to,
6945
6945
  message: args.message,
6946
6946
  priority: args.priority,
6947
- ...args.idempotencyKey ? { client_message_id: args.idempotencyKey } : {}
6947
+ ...args.idempotencyKey ? { client_message_id: args.idempotencyKey } : {},
6948
+ ...args.expectedMesh ? { mesh: args.expectedMesh } : {}
6948
6949
  }
6949
6950
  });
6950
6951
  if (res.status === 202 || res.status === 200) {
@@ -8908,10 +8909,9 @@ function startIpcServer(opts) {
8908
8909
  outboxDb: opts.outboxDb,
8909
8910
  inboxDb: opts.inboxDb,
8910
8911
  bus: opts.bus,
8911
- broker: opts.broker,
8912
- onPendingInserted: opts.onPendingInserted,
8913
- meshSecretKey: opts.meshSecretKey,
8914
- meshSlug: opts.meshSlug
8912
+ brokers: opts.brokers,
8913
+ meshConfigs: opts.meshConfigs,
8914
+ onPendingInserted: opts.onPendingInserted
8915
8915
  });
8916
8916
  if (existsSync9(DAEMON_PATHS.SOCK_FILE)) {
8917
8917
  try {
@@ -9021,34 +9021,58 @@ function makeHandler(opts) {
9021
9021
  return;
9022
9022
  }
9023
9023
  if (req.method === "GET" && url.pathname === "/v1/peers") {
9024
- if (!opts.broker) {
9024
+ if (!opts.brokers || opts.brokers.size === 0) {
9025
9025
  respond(res, 503, { error: "broker not initialised" });
9026
9026
  return;
9027
9027
  }
9028
+ const filterMesh = url.searchParams.get("mesh") ?? undefined;
9028
9029
  try {
9029
- const peers = await opts.broker.listPeers();
9030
- respond(res, 200, { peers });
9030
+ const all = [];
9031
+ for (const [slug, b] of opts.brokers.entries()) {
9032
+ if (filterMesh && filterMesh !== slug)
9033
+ continue;
9034
+ try {
9035
+ const peers = await b.listPeers();
9036
+ for (const p of peers)
9037
+ all.push({ ...p, mesh: slug });
9038
+ } catch (e) {
9039
+ opts.log("warn", "ipc_peers_broker_failed", { mesh: slug, err: String(e) });
9040
+ }
9041
+ }
9042
+ respond(res, 200, { peers: all });
9031
9043
  } catch (e) {
9032
9044
  respond(res, 502, { error: "broker_unreachable", detail: String(e) });
9033
9045
  }
9034
9046
  return;
9035
9047
  }
9036
9048
  if (req.method === "GET" && url.pathname === "/v1/skills") {
9037
- if (!opts.broker) {
9049
+ if (!opts.brokers || opts.brokers.size === 0) {
9038
9050
  respond(res, 503, { error: "broker not initialised" });
9039
9051
  return;
9040
9052
  }
9041
9053
  const query = url.searchParams.get("query") ?? undefined;
9054
+ const filterMesh = url.searchParams.get("mesh") ?? undefined;
9042
9055
  try {
9043
- const skills = await opts.broker.listSkills(query);
9044
- respond(res, 200, { skills });
9056
+ const all = [];
9057
+ for (const [slug, b] of opts.brokers.entries()) {
9058
+ if (filterMesh && filterMesh !== slug)
9059
+ continue;
9060
+ try {
9061
+ const skills = await b.listSkills(query);
9062
+ for (const s of skills)
9063
+ all.push({ ...s, mesh: slug });
9064
+ } catch (e) {
9065
+ opts.log("warn", "ipc_skills_broker_failed", { mesh: slug, err: String(e) });
9066
+ }
9067
+ }
9068
+ respond(res, 200, { skills: all });
9045
9069
  } catch (e) {
9046
9070
  respond(res, 502, { error: "broker_unreachable", detail: String(e) });
9047
9071
  }
9048
9072
  return;
9049
9073
  }
9050
9074
  if (req.method === "GET" && url.pathname.startsWith("/v1/skills/")) {
9051
- if (!opts.broker) {
9075
+ if (!opts.brokers || opts.brokers.size === 0) {
9052
9076
  respond(res, 503, { error: "broker not initialised" });
9053
9077
  return;
9054
9078
  }
@@ -9057,20 +9081,25 @@ function makeHandler(opts) {
9057
9081
  respond(res, 400, { error: "missing skill name" });
9058
9082
  return;
9059
9083
  }
9084
+ const filterMesh = url.searchParams.get("mesh") ?? undefined;
9060
9085
  try {
9061
- const skill = await opts.broker.getSkill(name);
9062
- if (!skill) {
9063
- respond(res, 404, { error: "skill_not_found", name });
9064
- return;
9086
+ for (const [slug, b] of opts.brokers.entries()) {
9087
+ if (filterMesh && filterMesh !== slug)
9088
+ continue;
9089
+ const skill = await b.getSkill(name).catch(() => null);
9090
+ if (skill) {
9091
+ respond(res, 200, { skill: { ...skill, mesh: slug } });
9092
+ return;
9093
+ }
9065
9094
  }
9066
- respond(res, 200, { skill });
9095
+ respond(res, 404, { error: "skill_not_found", name });
9067
9096
  } catch (e) {
9068
9097
  respond(res, 502, { error: "broker_unreachable", detail: String(e) });
9069
9098
  }
9070
9099
  return;
9071
9100
  }
9072
9101
  if (req.method === "POST" && url.pathname === "/v1/profile") {
9073
- if (!opts.broker) {
9102
+ if (!opts.brokers || opts.brokers.size === 0) {
9074
9103
  respond(res, 503, { error: "broker not initialised" });
9075
9104
  return;
9076
9105
  }
@@ -9080,26 +9109,34 @@ function makeHandler(opts) {
9080
9109
  respond(res, 400, { error: "expected JSON object" });
9081
9110
  return;
9082
9111
  }
9112
+ const requested = (typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh")) || null;
9113
+ const targets = requested ? [opts.brokers.get(requested)].filter(Boolean) : [...opts.brokers.values()];
9114
+ if (targets.length === 0) {
9115
+ respond(res, 404, { error: "mesh_not_attached", mesh: requested });
9116
+ return;
9117
+ }
9083
9118
  const updates = {};
9084
- if (typeof body.summary === "string")
9085
- opts.broker.setSummary(body.summary);
9086
- if (body.status === "idle" || body.status === "working" || body.status === "dnd")
9087
- opts.broker.setStatus(body.status);
9088
- if (typeof body.visible === "boolean")
9089
- opts.broker.setVisible(body.visible);
9090
- const profile = {};
9091
- if (typeof body.avatar === "string")
9092
- profile.avatar = body.avatar;
9093
- if (typeof body.title === "string")
9094
- profile.title = body.title;
9095
- if (typeof body.bio === "string")
9096
- profile.bio = body.bio;
9097
- if (Array.isArray(body.capabilities))
9098
- profile.capabilities = body.capabilities.filter((c) => typeof c === "string");
9099
- if (Object.keys(profile).length > 0)
9100
- opts.broker.setProfile(profile);
9119
+ for (const b of targets) {
9120
+ if (typeof body.summary === "string")
9121
+ b.setSummary(body.summary);
9122
+ if (body.status === "idle" || body.status === "working" || body.status === "dnd")
9123
+ b.setStatus(body.status);
9124
+ if (typeof body.visible === "boolean")
9125
+ b.setVisible(body.visible);
9126
+ const profile = {};
9127
+ if (typeof body.avatar === "string")
9128
+ profile.avatar = body.avatar;
9129
+ if (typeof body.title === "string")
9130
+ profile.title = body.title;
9131
+ if (typeof body.bio === "string")
9132
+ profile.bio = body.bio;
9133
+ if (Array.isArray(body.capabilities))
9134
+ profile.capabilities = body.capabilities.filter((c) => typeof c === "string");
9135
+ if (Object.keys(profile).length > 0)
9136
+ b.setProfile(profile);
9137
+ }
9101
9138
  Object.assign(updates, body);
9102
- respond(res, 200, { ok: true, applied: Object.keys(updates) });
9139
+ respond(res, 200, { ok: true, applied: Object.keys(updates), meshes: requested ? [requested] : [...opts.brokers.keys()] });
9103
9140
  } catch (e) {
9104
9141
  respond(res, 400, { error: String(e) });
9105
9142
  }
@@ -9217,9 +9254,27 @@ function makeHandler(opts) {
9217
9254
  respond(res, 400, { error: parsed.error });
9218
9255
  return;
9219
9256
  }
9220
- if (opts.broker && opts.meshSecretKey) {
9257
+ if (opts.brokers && opts.brokers.size > 0 && opts.meshConfigs) {
9258
+ let chosenSlug = parsed.req.mesh ?? null;
9259
+ if (!chosenSlug && opts.brokers.size === 1) {
9260
+ chosenSlug = opts.brokers.keys().next().value;
9261
+ }
9262
+ if (!chosenSlug) {
9263
+ respond(res, 400, {
9264
+ error: "mesh_required",
9265
+ detail: `daemon attached to ${opts.brokers.size} meshes; pass 'mesh' in request body`,
9266
+ attached: [...opts.brokers.keys()]
9267
+ });
9268
+ return;
9269
+ }
9270
+ const broker = opts.brokers.get(chosenSlug);
9271
+ const meshCfg = opts.meshConfigs.get(chosenSlug);
9272
+ if (!broker || !meshCfg) {
9273
+ respond(res, 404, { error: "mesh_not_attached", mesh: chosenSlug });
9274
+ return;
9275
+ }
9221
9276
  try {
9222
- const routed = await resolveAndEncrypt(parsed.req, opts.broker, opts.meshSecretKey, opts.meshSlug ?? null);
9277
+ const routed = await resolveAndEncrypt(parsed.req, broker, meshCfg.secretKey, chosenSlug);
9223
9278
  parsed.req.target_spec = routed.target_spec;
9224
9279
  parsed.req.ciphertext = routed.ciphertext;
9225
9280
  parsed.req.nonce = routed.nonce;
@@ -9321,6 +9376,7 @@ function parseSendRequest(body, idempotencyHeader) {
9321
9376
  const headerId = Array.isArray(idempotencyHeader) ? idempotencyHeader[0] : idempotencyHeader;
9322
9377
  const client_message_id = typeof b.client_message_id === "string" && b.client_message_id.trim() ? b.client_message_id.trim() : typeof headerId === "string" && headerId.trim() ? headerId.trim() : undefined;
9323
9378
  const reply_to_id = typeof b.reply_to_id === "string" ? b.reply_to_id : undefined;
9379
+ const mesh = typeof b.mesh === "string" ? b.mesh.trim() : undefined;
9324
9380
  return {
9325
9381
  req: {
9326
9382
  to,
@@ -9330,7 +9386,8 @@ function parseSendRequest(body, idempotencyHeader) {
9330
9386
  reply_to_id,
9331
9387
  client_message_id,
9332
9388
  destination_kind,
9333
- destination_ref
9389
+ destination_ref,
9390
+ mesh
9334
9391
  }
9335
9392
  };
9336
9393
  }
@@ -9796,6 +9853,17 @@ async function drainOnce(opts, log2) {
9796
9853
  if (markInflight(opts.db, row.id, now) === 0)
9797
9854
  continue;
9798
9855
  const fpHex = bufferToHex(row.request_fingerprint);
9856
+ let broker;
9857
+ if (row.mesh) {
9858
+ broker = opts.brokers.get(row.mesh);
9859
+ } else if (opts.brokers.size === 1) {
9860
+ broker = opts.brokers.values().next().value;
9861
+ }
9862
+ if (!broker) {
9863
+ log2("warn", "drain_no_broker_for_mesh", { id: row.id, mesh: row.mesh ?? "(null)" });
9864
+ markDead(opts.db, row.id, `no_broker_for_mesh:${row.mesh ?? "null"}`);
9865
+ continue;
9866
+ }
9799
9867
  let targetSpec;
9800
9868
  let nonce;
9801
9869
  let ciphertext;
@@ -9813,7 +9881,7 @@ async function drainOnce(opts, log2) {
9813
9881
  }
9814
9882
  let res;
9815
9883
  try {
9816
- res = await opts.broker.send({
9884
+ res = await broker.send({
9817
9885
  targetSpec,
9818
9886
  priority,
9819
9887
  nonce,
@@ -10159,10 +10227,10 @@ async function runDaemon(opts = {}) {
10159
10227
  }
10160
10228
  const bus = new EventBus;
10161
10229
  const cfg = readConfig();
10162
- let mesh = null;
10230
+ let meshes;
10163
10231
  if (opts.mesh) {
10164
- mesh = cfg.meshes.find((m) => m.slug === opts.mesh) ?? null;
10165
- if (!mesh) {
10232
+ const found = cfg.meshes.find((m) => m.slug === opts.mesh);
10233
+ if (!found) {
10166
10234
  process.stderr.write(`mesh not found: ${opts.mesh}
10167
10235
  `);
10168
10236
  process.stderr.write(`joined meshes: ${cfg.meshes.map((m) => m.slug).join(", ") || "(none)"}
@@ -10173,8 +10241,7 @@ async function runDaemon(opts = {}) {
10173
10241
  } catch {}
10174
10242
  return 2;
10175
10243
  }
10176
- } else if (cfg.meshes.length === 1) {
10177
- mesh = cfg.meshes[0];
10244
+ meshes = [found];
10178
10245
  } else if (cfg.meshes.length === 0) {
10179
10246
  process.stderr.write(`no mesh joined; run \`claudemesh join <invite-url>\` first
10180
10247
  `);
@@ -10184,43 +10251,41 @@ async function runDaemon(opts = {}) {
10184
10251
  } catch {}
10185
10252
  return 2;
10186
10253
  } else {
10187
- process.stderr.write(`multiple meshes joined; pass --mesh <slug>
10188
- `);
10189
- process.stderr.write(`available: ${cfg.meshes.map((m) => m.slug).join(", ")}
10190
- `);
10191
- releaseSingletonLock();
10192
- try {
10193
- outboxDb.close();
10194
- } catch {}
10195
- return 2;
10196
- }
10197
- const broker = new DaemonBrokerClient(mesh, {
10198
- displayName: opts.displayName,
10199
- onStatusChange: (s) => {
10200
- process.stdout.write(JSON.stringify({
10201
- msg: "broker_status",
10202
- status: s,
10203
- mesh: mesh.slug,
10204
- ts: new Date().toISOString()
10205
- }) + `
10254
+ meshes = cfg.meshes;
10255
+ }
10256
+ const brokers = new Map;
10257
+ const meshConfigs = new Map;
10258
+ for (const mesh of meshes) {
10259
+ meshConfigs.set(mesh.slug, mesh);
10260
+ const broker = new DaemonBrokerClient(mesh, {
10261
+ displayName: opts.displayName,
10262
+ onStatusChange: (s) => {
10263
+ process.stdout.write(JSON.stringify({
10264
+ msg: "broker_status",
10265
+ status: s,
10266
+ mesh: mesh.slug,
10267
+ ts: new Date().toISOString()
10268
+ }) + `
10206
10269
  `);
10207
- bus.publish("broker_status", { mesh: mesh.slug, status: s });
10208
- },
10209
- onPush: (m) => {
10210
- const sessionKeys = broker.getSessionKeys();
10211
- handleBrokerPush(m, {
10212
- db: inboxDb,
10213
- bus,
10214
- meshSlug: mesh.slug,
10215
- recipientSecretKeyHex: mesh.secretKey,
10216
- sessionSecretKeyHex: sessionKeys?.sessionSecretKey
10217
- });
10218
- }
10219
- });
10220
- broker.connect().catch((err) => process.stderr.write(`broker connect failed: ${String(err)}
10270
+ bus.publish("broker_status", { mesh: mesh.slug, status: s });
10271
+ },
10272
+ onPush: (m) => {
10273
+ const sessionKeys = broker.getSessionKeys();
10274
+ handleBrokerPush(m, {
10275
+ db: inboxDb,
10276
+ bus,
10277
+ meshSlug: mesh.slug,
10278
+ recipientSecretKeyHex: mesh.secretKey,
10279
+ sessionSecretKeyHex: sessionKeys?.sessionSecretKey
10280
+ });
10281
+ }
10282
+ });
10283
+ broker.connect().catch((err) => process.stderr.write(`broker connect failed for ${mesh.slug}: ${String(err)}
10221
10284
  `));
10285
+ brokers.set(mesh.slug, broker);
10286
+ }
10222
10287
  let drain = null;
10223
- drain = startDrainWorker({ db: outboxDb, broker });
10288
+ drain = startDrainWorker({ db: outboxDb, brokers });
10224
10289
  const ipc2 = startIpcServer({
10225
10290
  localToken,
10226
10291
  tcpEnabled,
@@ -10228,10 +10293,9 @@ async function runDaemon(opts = {}) {
10228
10293
  outboxDb,
10229
10294
  inboxDb,
10230
10295
  bus,
10231
- broker,
10232
- onPendingInserted: () => drain?.wake(),
10233
- meshSecretKey: mesh.secretKey,
10234
- meshSlug: mesh.slug
10296
+ brokers,
10297
+ meshConfigs,
10298
+ onPendingInserted: () => drain?.wake()
10235
10299
  });
10236
10300
  try {
10237
10301
  await ipc2.ready;
@@ -10246,7 +10310,7 @@ async function runDaemon(opts = {}) {
10246
10310
  pid: process.pid,
10247
10311
  sock: DAEMON_PATHS.SOCK_FILE,
10248
10312
  tcp: tcpEnabled ? `127.0.0.1:47823` : null,
10249
- mesh: mesh.slug,
10313
+ meshes: meshes.map((m) => m.slug),
10250
10314
  ts: new Date().toISOString()
10251
10315
  }) + `
10252
10316
  `);
@@ -10259,7 +10323,11 @@ async function runDaemon(opts = {}) {
10259
10323
  `);
10260
10324
  if (drain)
10261
10325
  await drain.close();
10262
- await broker.close();
10326
+ for (const b of brokers.values()) {
10327
+ try {
10328
+ await b.close();
10329
+ } catch {}
10330
+ }
10263
10331
  await ipc2.close();
10264
10332
  try {
10265
10333
  outboxDb.close();
@@ -18594,4 +18662,4 @@ main().catch((err) => {
18594
18662
  process.exit(EXIT.INTERNAL_ERROR);
18595
18663
  });
18596
18664
 
18597
- //# debugId=EC115E4068A7B5F664756E2164756E21
18665
+ //# debugId=3BADD117052552A564756E2164756E21