claudemesh-cli 1.32.0 → 1.33.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 +414 -353
- package/dist/entrypoints/cli.js.map +10 -9
- 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
|
@@ -104,7 +104,7 @@ __export(exports_urls, {
|
|
|
104
104
|
VERSION: () => VERSION,
|
|
105
105
|
URLS: () => URLS
|
|
106
106
|
});
|
|
107
|
-
var URLS, VERSION = "1.
|
|
107
|
+
var URLS, VERSION = "1.33.0", env;
|
|
108
108
|
var init_urls = __esm(() => {
|
|
109
109
|
URLS = {
|
|
110
110
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -7948,8 +7948,15 @@ async function listPeersForMesh(slug) {
|
|
|
7948
7948
|
function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
|
|
7949
7949
|
const isSelf = !!(selfMemberPubkey && peer.memberPubkey && peer.memberPubkey === selfMemberPubkey);
|
|
7950
7950
|
const isThisSession = !!(isSelf && selfSessionPubkey && peer.pubkey === selfSessionPubkey);
|
|
7951
|
-
const
|
|
7952
|
-
|
|
7951
|
+
const peerRole = peer.peerRole ?? "session";
|
|
7952
|
+
const profileRole = peer.profile?.role?.trim() || undefined;
|
|
7953
|
+
return {
|
|
7954
|
+
...peer,
|
|
7955
|
+
...profileRole ? { role: profileRole } : {},
|
|
7956
|
+
peerRole,
|
|
7957
|
+
isSelf,
|
|
7958
|
+
isThisSession
|
|
7959
|
+
};
|
|
7953
7960
|
}
|
|
7954
7961
|
async function runPeers(flags) {
|
|
7955
7962
|
const config = readConfig();
|
|
@@ -7977,13 +7984,13 @@ async function runPeers(flags) {
|
|
|
7977
7984
|
allJson.push({ mesh: slug, peers: projected });
|
|
7978
7985
|
continue;
|
|
7979
7986
|
}
|
|
7980
|
-
const visible = flags.all ? peers : peers.filter((p) => p.
|
|
7987
|
+
const visible = flags.all ? peers : peers.filter((p) => p.peerRole !== "control-plane");
|
|
7981
7988
|
const sorted = visible.slice().sort((a, b) => {
|
|
7982
7989
|
const score = (p) => p.isThisSession ? 0 : p.isSelf ? 1 : 2;
|
|
7983
7990
|
return score(a) - score(b);
|
|
7984
7991
|
});
|
|
7985
|
-
const
|
|
7986
|
-
const header =
|
|
7992
|
+
const hiddenControlPlane = peers.length - visible.length;
|
|
7993
|
+
const header = hiddenControlPlane > 0 ? `peers on ${slug} (${sorted.length}, ${hiddenControlPlane} control-plane hidden — use --all)` : `peers on ${slug} (${sorted.length})`;
|
|
7987
7994
|
render.section(header);
|
|
7988
7995
|
if (sorted.length === 0) {
|
|
7989
7996
|
render.info(dim(" (no peers connected)"));
|
|
@@ -10450,9 +10457,7 @@ async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
|
|
|
10450
10457
|
return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
|
|
10451
10458
|
}
|
|
10452
10459
|
if (/^[0-9a-f]{64}$/i.test(to)) {
|
|
10453
|
-
const
|
|
10454
|
-
const senderSecret2 = sessionKeys2?.sessionSecretKey ?? meshSecretKey;
|
|
10455
|
-
const env3 = await encryptDirect2(req.message, to, senderSecret2);
|
|
10460
|
+
const env3 = await encryptDirect2(req.message, to, meshSecretKey);
|
|
10456
10461
|
return { target_spec: to, ciphertext: env3.ciphertext, nonce: env3.nonce, mesh: meshSlug ?? "" };
|
|
10457
10462
|
}
|
|
10458
10463
|
const peers = await broker.listPeers().catch(() => []);
|
|
@@ -10463,18 +10468,14 @@ async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
|
|
|
10463
10468
|
if (matches2.length > 1)
|
|
10464
10469
|
throw new Error(`prefix "${to}" is ambiguous (${matches2.length} matches)`);
|
|
10465
10470
|
const recipient2 = matches2[0].pubkey;
|
|
10466
|
-
const
|
|
10467
|
-
const senderSecret2 = sessionKeys2?.sessionSecretKey ?? meshSecretKey;
|
|
10468
|
-
const env3 = await encryptDirect2(req.message, recipient2, senderSecret2);
|
|
10471
|
+
const env3 = await encryptDirect2(req.message, recipient2, meshSecretKey);
|
|
10469
10472
|
return { target_spec: recipient2, ciphertext: env3.ciphertext, nonce: env3.nonce, mesh: meshSlug ?? "" };
|
|
10470
10473
|
}
|
|
10471
10474
|
const match = peers.find((p) => p.displayName.toLowerCase() === to.toLowerCase());
|
|
10472
10475
|
if (!match)
|
|
10473
10476
|
throw new Error(`peer "${to}" not found`);
|
|
10474
10477
|
const recipient = match.pubkey;
|
|
10475
|
-
const
|
|
10476
|
-
const senderSecret = sessionKeys?.sessionSecretKey ?? meshSecretKey;
|
|
10477
|
-
const env2 = await encryptDirect2(req.message, recipient, senderSecret);
|
|
10478
|
+
const env2 = await encryptDirect2(req.message, recipient, meshSecretKey);
|
|
10478
10479
|
return { target_spec: recipient, ciphertext: env2.ciphertext, nonce: env2.nonce, mesh: meshSlug ?? "" };
|
|
10479
10480
|
}
|
|
10480
10481
|
function respond(res, status, body) {
|
|
@@ -10491,18 +10492,149 @@ var init_server = __esm(() => {
|
|
|
10491
10492
|
init_urls();
|
|
10492
10493
|
});
|
|
10493
10494
|
|
|
10494
|
-
// src/daemon/
|
|
10495
|
+
// src/daemon/ws-lifecycle.ts
|
|
10495
10496
|
import WebSocket2 from "ws";
|
|
10497
|
+
function connectWsWithBackoff(opts) {
|
|
10498
|
+
const helloAckTimeoutMs = opts.helloAckTimeoutMs ?? DEFAULT_HELLO_ACK_TIMEOUT_MS;
|
|
10499
|
+
const backoffCapsMs = opts.backoffCapsMs ?? DEFAULT_BACKOFF_CAPS_MS;
|
|
10500
|
+
const log2 = opts.log ?? defaultLog;
|
|
10501
|
+
let ws = null;
|
|
10502
|
+
let status = "closed";
|
|
10503
|
+
let closed = false;
|
|
10504
|
+
let reconnectAttempt = 0;
|
|
10505
|
+
let reconnectTimer = null;
|
|
10506
|
+
let helloTimer = null;
|
|
10507
|
+
const setStatus = (s) => {
|
|
10508
|
+
if (status === s)
|
|
10509
|
+
return;
|
|
10510
|
+
status = s;
|
|
10511
|
+
opts.onStatusChange?.(s);
|
|
10512
|
+
};
|
|
10513
|
+
const openOnce = () => {
|
|
10514
|
+
if (closed)
|
|
10515
|
+
return Promise.reject(new Error("client_closed"));
|
|
10516
|
+
setStatus("connecting");
|
|
10517
|
+
log2("info", "ws_open_attempt", { url: opts.url });
|
|
10518
|
+
const sock = new WebSocket2(opts.url);
|
|
10519
|
+
ws = sock;
|
|
10520
|
+
return new Promise((resolve, reject) => {
|
|
10521
|
+
sock.on("open", () => {
|
|
10522
|
+
log2("info", "ws_open_ok", { url: opts.url });
|
|
10523
|
+
(async () => {
|
|
10524
|
+
try {
|
|
10525
|
+
const hello = await opts.buildHello();
|
|
10526
|
+
sock.send(JSON.stringify(hello));
|
|
10527
|
+
log2("info", "ws_hello_sent", { url: opts.url });
|
|
10528
|
+
helloTimer = setTimeout(() => {
|
|
10529
|
+
log2("warn", "hello_ack_timeout", { url: opts.url });
|
|
10530
|
+
try {
|
|
10531
|
+
sock.close();
|
|
10532
|
+
} catch {}
|
|
10533
|
+
reject(new Error("hello_ack_timeout"));
|
|
10534
|
+
}, helloAckTimeoutMs);
|
|
10535
|
+
} catch (e) {
|
|
10536
|
+
log2("warn", "ws_build_hello_threw", { err: String(e) });
|
|
10537
|
+
reject(e instanceof Error ? e : new Error(String(e)));
|
|
10538
|
+
}
|
|
10539
|
+
})();
|
|
10540
|
+
});
|
|
10541
|
+
sock.on("message", (raw) => {
|
|
10542
|
+
let msg;
|
|
10543
|
+
try {
|
|
10544
|
+
msg = JSON.parse(raw.toString());
|
|
10545
|
+
} catch {
|
|
10546
|
+
return;
|
|
10547
|
+
}
|
|
10548
|
+
if (opts.isHelloAck(msg)) {
|
|
10549
|
+
if (helloTimer) {
|
|
10550
|
+
clearTimeout(helloTimer);
|
|
10551
|
+
helloTimer = null;
|
|
10552
|
+
}
|
|
10553
|
+
setStatus("open");
|
|
10554
|
+
reconnectAttempt = 0;
|
|
10555
|
+
log2("info", "ws_hello_acked", { url: opts.url });
|
|
10556
|
+
resolve();
|
|
10557
|
+
return;
|
|
10558
|
+
}
|
|
10559
|
+
opts.onMessage(msg);
|
|
10560
|
+
});
|
|
10561
|
+
sock.on("close", (code, reason) => {
|
|
10562
|
+
if (helloTimer) {
|
|
10563
|
+
clearTimeout(helloTimer);
|
|
10564
|
+
helloTimer = null;
|
|
10565
|
+
}
|
|
10566
|
+
const reasonStr = reason.toString("utf8");
|
|
10567
|
+
log2("warn", "ws_closed", { url: opts.url, code, reason: reasonStr, status });
|
|
10568
|
+
opts.onBeforeReconnect?.(code, reasonStr);
|
|
10569
|
+
if (closed) {
|
|
10570
|
+
setStatus("closed");
|
|
10571
|
+
return;
|
|
10572
|
+
}
|
|
10573
|
+
setStatus("reconnecting");
|
|
10574
|
+
const wait = backoffCapsMs[Math.min(reconnectAttempt, backoffCapsMs.length - 1)] ?? 30000;
|
|
10575
|
+
reconnectAttempt++;
|
|
10576
|
+
log2("info", "ws_reconnect_scheduled", { url: opts.url, wait_ms: wait, code, reason: reasonStr });
|
|
10577
|
+
reconnectTimer = setTimeout(() => openOnce().catch((err) => log2("warn", "ws_reconnect_failed", { url: opts.url, err: String(err) })), wait);
|
|
10578
|
+
if (status === "connecting" || status === "reconnecting") {
|
|
10579
|
+
reject(new Error(`closed_before_hello_${code}`));
|
|
10580
|
+
}
|
|
10581
|
+
});
|
|
10582
|
+
sock.on("error", (err) => log2("warn", "ws_error", { url: opts.url, err: err.message }));
|
|
10583
|
+
});
|
|
10584
|
+
};
|
|
10585
|
+
return openOnce().then(() => {
|
|
10586
|
+
const handle = {
|
|
10587
|
+
get status() {
|
|
10588
|
+
return status;
|
|
10589
|
+
},
|
|
10590
|
+
get ws() {
|
|
10591
|
+
return ws;
|
|
10592
|
+
},
|
|
10593
|
+
send(payload) {
|
|
10594
|
+
if (!ws || ws.readyState !== ws.OPEN) {
|
|
10595
|
+
throw new Error("ws_not_open");
|
|
10596
|
+
}
|
|
10597
|
+
ws.send(JSON.stringify(payload));
|
|
10598
|
+
},
|
|
10599
|
+
async close() {
|
|
10600
|
+
closed = true;
|
|
10601
|
+
if (reconnectTimer) {
|
|
10602
|
+
clearTimeout(reconnectTimer);
|
|
10603
|
+
reconnectTimer = null;
|
|
10604
|
+
}
|
|
10605
|
+
if (helloTimer) {
|
|
10606
|
+
clearTimeout(helloTimer);
|
|
10607
|
+
helloTimer = null;
|
|
10608
|
+
}
|
|
10609
|
+
try {
|
|
10610
|
+
ws?.close();
|
|
10611
|
+
} catch {}
|
|
10612
|
+
setStatus("closed");
|
|
10613
|
+
}
|
|
10614
|
+
};
|
|
10615
|
+
return handle;
|
|
10616
|
+
});
|
|
10617
|
+
}
|
|
10618
|
+
var DEFAULT_HELLO_ACK_TIMEOUT_MS = 5000, DEFAULT_BACKOFF_CAPS_MS, defaultLog = (level, msg, meta) => {
|
|
10619
|
+
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
10620
|
+
if (level === "info")
|
|
10621
|
+
process.stdout.write(line + `
|
|
10622
|
+
`);
|
|
10623
|
+
else
|
|
10624
|
+
process.stderr.write(line + `
|
|
10625
|
+
`);
|
|
10626
|
+
};
|
|
10627
|
+
var init_ws_lifecycle = __esm(() => {
|
|
10628
|
+
DEFAULT_BACKOFF_CAPS_MS = [1000, 2000, 4000, 8000, 16000, 30000];
|
|
10629
|
+
});
|
|
10496
10630
|
|
|
10631
|
+
// src/daemon/broker.ts
|
|
10497
10632
|
class DaemonBrokerClient {
|
|
10498
10633
|
mesh;
|
|
10499
10634
|
opts;
|
|
10500
|
-
|
|
10635
|
+
lifecycle = null;
|
|
10501
10636
|
_status = "closed";
|
|
10502
10637
|
closed = false;
|
|
10503
|
-
reconnectAttempt = 0;
|
|
10504
|
-
reconnectTimer = null;
|
|
10505
|
-
helloTimer = null;
|
|
10506
10638
|
pendingAcks = new Map;
|
|
10507
10639
|
peerListResolvers = new Map;
|
|
10508
10640
|
skillListResolvers = new Map;
|
|
@@ -10511,8 +10643,6 @@ class DaemonBrokerClient {
|
|
|
10511
10643
|
stateListResolvers = new Map;
|
|
10512
10644
|
memoryStoreResolvers = new Map;
|
|
10513
10645
|
memoryRecallResolvers = new Map;
|
|
10514
|
-
sessionPubkey = null;
|
|
10515
|
-
sessionSecretKey = null;
|
|
10516
10646
|
opens = [];
|
|
10517
10647
|
reqCounter = 0;
|
|
10518
10648
|
constructor(mesh, opts = {}) {
|
|
@@ -10529,72 +10659,39 @@ class DaemonBrokerClient {
|
|
|
10529
10659
|
return this.mesh.meshId;
|
|
10530
10660
|
}
|
|
10531
10661
|
log = (level, msg, meta) => {
|
|
10532
|
-
(this.opts.log ??
|
|
10662
|
+
(this.opts.log ?? defaultLog2)(level, msg, { mesh: this.mesh.slug, ...meta });
|
|
10533
10663
|
};
|
|
10534
|
-
setConnStatus(s) {
|
|
10535
|
-
if (this._status === s)
|
|
10536
|
-
return;
|
|
10537
|
-
this._status = s;
|
|
10538
|
-
this.opts.onStatusChange?.(s);
|
|
10539
|
-
}
|
|
10540
10664
|
async connect() {
|
|
10541
10665
|
if (this.closed)
|
|
10542
10666
|
throw new Error("client_closed");
|
|
10543
10667
|
if (this._status === "connecting" || this._status === "open")
|
|
10544
10668
|
return;
|
|
10545
|
-
this.
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
|
|
10556
|
-
|
|
10557
|
-
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
timestamp: timestamp2,
|
|
10572
|
-
signature
|
|
10573
|
-
}));
|
|
10574
|
-
this.helloTimer = setTimeout(() => {
|
|
10575
|
-
this.log("warn", "broker_hello_ack_timeout");
|
|
10576
|
-
try {
|
|
10577
|
-
ws.close();
|
|
10578
|
-
} catch {}
|
|
10579
|
-
reject(new Error("hello_ack_timeout"));
|
|
10580
|
-
}, HELLO_ACK_TIMEOUT_MS2);
|
|
10581
|
-
} catch (e) {
|
|
10582
|
-
reject(e instanceof Error ? e : new Error(String(e)));
|
|
10583
|
-
}
|
|
10584
|
-
});
|
|
10585
|
-
ws.on("message", (raw) => {
|
|
10586
|
-
let msg;
|
|
10587
|
-
try {
|
|
10588
|
-
msg = JSON.parse(raw.toString());
|
|
10589
|
-
} catch {
|
|
10590
|
-
return;
|
|
10591
|
-
}
|
|
10592
|
-
if (msg.type === "hello_ack") {
|
|
10593
|
-
if (this.helloTimer)
|
|
10594
|
-
clearTimeout(this.helloTimer);
|
|
10595
|
-
this.helloTimer = null;
|
|
10596
|
-
this.setConnStatus("open");
|
|
10597
|
-
this.reconnectAttempt = 0;
|
|
10669
|
+
this.lifecycle = await connectWsWithBackoff({
|
|
10670
|
+
url: this.mesh.brokerUrl,
|
|
10671
|
+
buildHello: async () => {
|
|
10672
|
+
const { timestamp: timestamp2, signature } = await signHello(this.mesh.meshId, this.mesh.memberId, this.mesh.pubkey, this.mesh.secretKey);
|
|
10673
|
+
return {
|
|
10674
|
+
type: "hello",
|
|
10675
|
+
meshId: this.mesh.meshId,
|
|
10676
|
+
memberId: this.mesh.memberId,
|
|
10677
|
+
pubkey: this.mesh.pubkey,
|
|
10678
|
+
displayName: this.opts.displayName,
|
|
10679
|
+
sessionId: `daemon-${process.pid}`,
|
|
10680
|
+
pid: process.pid,
|
|
10681
|
+
cwd: process.cwd(),
|
|
10682
|
+
hostname: __require("node:os").hostname(),
|
|
10683
|
+
peerType: "ai",
|
|
10684
|
+
channel: "claudemesh-daemon",
|
|
10685
|
+
timestamp: timestamp2,
|
|
10686
|
+
signature
|
|
10687
|
+
};
|
|
10688
|
+
},
|
|
10689
|
+
isHelloAck: (msg) => msg.type === "hello_ack",
|
|
10690
|
+
onMessage: (msg) => this.handleMessage(msg),
|
|
10691
|
+
onStatusChange: (s) => {
|
|
10692
|
+
this._status = s;
|
|
10693
|
+
this.opts.onStatusChange?.(s);
|
|
10694
|
+
if (s === "open") {
|
|
10598
10695
|
const queued = this.opens.slice();
|
|
10599
10696
|
this.opens.length = 0;
|
|
10600
10697
|
for (const fn of queued) {
|
|
@@ -10604,123 +10701,121 @@ class DaemonBrokerClient {
|
|
|
10604
10701
|
this.log("warn", "open_handler_failed", { err: String(e) });
|
|
10605
10702
|
}
|
|
10606
10703
|
}
|
|
10607
|
-
resolve();
|
|
10608
|
-
return;
|
|
10609
10704
|
}
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
const pending = this.peerListResolvers.get(reqId);
|
|
10627
|
-
if (pending) {
|
|
10628
|
-
this.peerListResolvers.delete(reqId);
|
|
10629
|
-
clearTimeout(pending.timer);
|
|
10630
|
-
pending.resolve(Array.isArray(msg.peers) ? msg.peers : []);
|
|
10631
|
-
}
|
|
10632
|
-
return;
|
|
10633
|
-
}
|
|
10634
|
-
if (msg.type === "skill_list") {
|
|
10635
|
-
const reqId = String(msg._reqId ?? "");
|
|
10636
|
-
const pending = this.skillListResolvers.get(reqId);
|
|
10637
|
-
if (pending) {
|
|
10638
|
-
this.skillListResolvers.delete(reqId);
|
|
10639
|
-
clearTimeout(pending.timer);
|
|
10640
|
-
pending.resolve(Array.isArray(msg.skills) ? msg.skills : []);
|
|
10641
|
-
}
|
|
10642
|
-
return;
|
|
10643
|
-
}
|
|
10644
|
-
if (msg.type === "skill_data") {
|
|
10645
|
-
const reqId = String(msg._reqId ?? "");
|
|
10646
|
-
const pending = this.skillDataResolvers.get(reqId);
|
|
10647
|
-
if (pending) {
|
|
10648
|
-
this.skillDataResolvers.delete(reqId);
|
|
10649
|
-
clearTimeout(pending.timer);
|
|
10650
|
-
pending.resolve(msg.skill ?? null);
|
|
10651
|
-
}
|
|
10652
|
-
return;
|
|
10653
|
-
}
|
|
10654
|
-
if (msg.type === "state_value" || msg.type === "state_data") {
|
|
10655
|
-
const reqId = String(msg._reqId ?? "");
|
|
10656
|
-
const pending = this.stateGetResolvers.get(reqId);
|
|
10657
|
-
if (pending) {
|
|
10658
|
-
this.stateGetResolvers.delete(reqId);
|
|
10659
|
-
clearTimeout(pending.timer);
|
|
10660
|
-
pending.resolve(msg.state ?? msg.row ?? null);
|
|
10661
|
-
}
|
|
10662
|
-
return;
|
|
10663
|
-
}
|
|
10664
|
-
if (msg.type === "state_list") {
|
|
10665
|
-
const reqId = String(msg._reqId ?? "");
|
|
10666
|
-
const pending = this.stateListResolvers.get(reqId);
|
|
10667
|
-
if (pending) {
|
|
10668
|
-
this.stateListResolvers.delete(reqId);
|
|
10669
|
-
clearTimeout(pending.timer);
|
|
10670
|
-
pending.resolve(Array.isArray(msg.entries) ? msg.entries : []);
|
|
10671
|
-
}
|
|
10672
|
-
return;
|
|
10673
|
-
}
|
|
10674
|
-
if (msg.type === "memory_stored") {
|
|
10675
|
-
const reqId = String(msg._reqId ?? "");
|
|
10676
|
-
const pending = this.memoryStoreResolvers.get(reqId);
|
|
10677
|
-
if (pending) {
|
|
10678
|
-
this.memoryStoreResolvers.delete(reqId);
|
|
10679
|
-
clearTimeout(pending.timer);
|
|
10680
|
-
pending.resolve(typeof msg.memoryId === "string" ? msg.memoryId : null);
|
|
10681
|
-
}
|
|
10682
|
-
return;
|
|
10683
|
-
}
|
|
10684
|
-
if (msg.type === "memory_recall_result") {
|
|
10685
|
-
const reqId = String(msg._reqId ?? "");
|
|
10686
|
-
const pending = this.memoryRecallResolvers.get(reqId);
|
|
10687
|
-
if (pending) {
|
|
10688
|
-
this.memoryRecallResolvers.delete(reqId);
|
|
10689
|
-
clearTimeout(pending.timer);
|
|
10690
|
-
pending.resolve(Array.isArray(msg.matches) ? msg.matches : []);
|
|
10691
|
-
}
|
|
10692
|
-
return;
|
|
10693
|
-
}
|
|
10694
|
-
if (msg.type === "push" || msg.type === "inbound") {
|
|
10695
|
-
this.opts.onPush?.(msg);
|
|
10696
|
-
return;
|
|
10697
|
-
}
|
|
10698
|
-
});
|
|
10699
|
-
ws.on("close", (code, reason) => {
|
|
10700
|
-
if (this.helloTimer) {
|
|
10701
|
-
clearTimeout(this.helloTimer);
|
|
10702
|
-
this.helloTimer = null;
|
|
10703
|
-
}
|
|
10704
|
-
this.failPendingAcks(`broker_disconnected_${code}`);
|
|
10705
|
-
if (this.closed) {
|
|
10706
|
-
this.setConnStatus("closed");
|
|
10707
|
-
return;
|
|
10705
|
+
},
|
|
10706
|
+
onBeforeReconnect: (code) => this.failPendingAcks(`broker_disconnected_${code}`),
|
|
10707
|
+
log: (level, msg, meta) => this.log(level, `broker_${msg}`, meta)
|
|
10708
|
+
});
|
|
10709
|
+
}
|
|
10710
|
+
handleMessage(msg) {
|
|
10711
|
+
if (msg.type === "ack") {
|
|
10712
|
+
const id = String(msg.id ?? "");
|
|
10713
|
+
const ack = this.pendingAcks.get(id);
|
|
10714
|
+
if (ack) {
|
|
10715
|
+
this.pendingAcks.delete(id);
|
|
10716
|
+
clearTimeout(ack.timer);
|
|
10717
|
+
if (typeof msg.error === "string" && msg.error.length > 0) {
|
|
10718
|
+
ack.resolve({ ok: false, error: msg.error, permanent: classifyPermanent(msg.error) });
|
|
10719
|
+
} else {
|
|
10720
|
+
ack.resolve({ ok: true, messageId: String(msg.messageId ?? id) });
|
|
10708
10721
|
}
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10722
|
+
}
|
|
10723
|
+
return;
|
|
10724
|
+
}
|
|
10725
|
+
if (msg.type === "peers_list") {
|
|
10726
|
+
const reqId = String(msg._reqId ?? "");
|
|
10727
|
+
const pending = this.peerListResolvers.get(reqId);
|
|
10728
|
+
if (pending) {
|
|
10729
|
+
this.peerListResolvers.delete(reqId);
|
|
10730
|
+
clearTimeout(pending.timer);
|
|
10731
|
+
pending.resolve(Array.isArray(msg.peers) ? msg.peers : []);
|
|
10732
|
+
}
|
|
10733
|
+
return;
|
|
10734
|
+
}
|
|
10735
|
+
if (msg.type === "skill_list") {
|
|
10736
|
+
const reqId = String(msg._reqId ?? "");
|
|
10737
|
+
const pending = this.skillListResolvers.get(reqId);
|
|
10738
|
+
if (pending) {
|
|
10739
|
+
this.skillListResolvers.delete(reqId);
|
|
10740
|
+
clearTimeout(pending.timer);
|
|
10741
|
+
pending.resolve(Array.isArray(msg.skills) ? msg.skills : []);
|
|
10742
|
+
}
|
|
10743
|
+
return;
|
|
10744
|
+
}
|
|
10745
|
+
if (msg.type === "skill_data") {
|
|
10746
|
+
const reqId = String(msg._reqId ?? "");
|
|
10747
|
+
const pending = this.skillDataResolvers.get(reqId);
|
|
10748
|
+
if (pending) {
|
|
10749
|
+
this.skillDataResolvers.delete(reqId);
|
|
10750
|
+
clearTimeout(pending.timer);
|
|
10751
|
+
pending.resolve(msg.skill ?? null);
|
|
10752
|
+
}
|
|
10753
|
+
return;
|
|
10754
|
+
}
|
|
10755
|
+
if (msg.type === "state_value" || msg.type === "state_data") {
|
|
10756
|
+
const reqId = String(msg._reqId ?? "");
|
|
10757
|
+
const pending = this.stateGetResolvers.get(reqId);
|
|
10758
|
+
if (pending) {
|
|
10759
|
+
this.stateGetResolvers.delete(reqId);
|
|
10760
|
+
clearTimeout(pending.timer);
|
|
10761
|
+
pending.resolve(msg.state ?? msg.row ?? null);
|
|
10762
|
+
}
|
|
10763
|
+
return;
|
|
10764
|
+
}
|
|
10765
|
+
if (msg.type === "state_list") {
|
|
10766
|
+
const reqId = String(msg._reqId ?? "");
|
|
10767
|
+
const pending = this.stateListResolvers.get(reqId);
|
|
10768
|
+
if (pending) {
|
|
10769
|
+
this.stateListResolvers.delete(reqId);
|
|
10770
|
+
clearTimeout(pending.timer);
|
|
10771
|
+
pending.resolve(Array.isArray(msg.entries) ? msg.entries : []);
|
|
10772
|
+
}
|
|
10773
|
+
return;
|
|
10774
|
+
}
|
|
10775
|
+
if (msg.type === "memory_stored") {
|
|
10776
|
+
const reqId = String(msg._reqId ?? "");
|
|
10777
|
+
const pending = this.memoryStoreResolvers.get(reqId);
|
|
10778
|
+
if (pending) {
|
|
10779
|
+
this.memoryStoreResolvers.delete(reqId);
|
|
10780
|
+
clearTimeout(pending.timer);
|
|
10781
|
+
pending.resolve(typeof msg.memoryId === "string" ? msg.memoryId : null);
|
|
10782
|
+
}
|
|
10783
|
+
return;
|
|
10784
|
+
}
|
|
10785
|
+
if (msg.type === "memory_recall_result") {
|
|
10786
|
+
const reqId = String(msg._reqId ?? "");
|
|
10787
|
+
const pending = this.memoryRecallResolvers.get(reqId);
|
|
10788
|
+
if (pending) {
|
|
10789
|
+
this.memoryRecallResolvers.delete(reqId);
|
|
10790
|
+
clearTimeout(pending.timer);
|
|
10791
|
+
pending.resolve(Array.isArray(msg.matches) ? msg.matches : []);
|
|
10792
|
+
}
|
|
10793
|
+
return;
|
|
10794
|
+
}
|
|
10795
|
+
if (msg.type === "push" || msg.type === "inbound") {
|
|
10796
|
+
this.opts.onPush?.(msg);
|
|
10797
|
+
return;
|
|
10798
|
+
}
|
|
10799
|
+
}
|
|
10800
|
+
isOpen() {
|
|
10801
|
+
const sock = this.lifecycle?.ws;
|
|
10802
|
+
return !!sock && sock.readyState === sock.OPEN;
|
|
10803
|
+
}
|
|
10804
|
+
sendClientAck(clientMessageId, brokerMessageId) {
|
|
10805
|
+
if (!this.isOpen())
|
|
10806
|
+
return;
|
|
10807
|
+
try {
|
|
10808
|
+
this.lifecycle.send({
|
|
10809
|
+
type: "client_ack",
|
|
10810
|
+
clientMessageId,
|
|
10811
|
+
...brokerMessageId ? { brokerMessageId } : {}
|
|
10716
10812
|
});
|
|
10717
|
-
|
|
10718
|
-
});
|
|
10813
|
+
} catch {}
|
|
10719
10814
|
}
|
|
10720
10815
|
send(req) {
|
|
10721
10816
|
return new Promise((resolve) => {
|
|
10722
10817
|
const dispatch = () => {
|
|
10723
|
-
if (!this.
|
|
10818
|
+
if (!this.isOpen()) {
|
|
10724
10819
|
resolve({ ok: false, error: "broker_not_open", permanent: false });
|
|
10725
10820
|
return;
|
|
10726
10821
|
}
|
|
@@ -10732,7 +10827,7 @@ class DaemonBrokerClient {
|
|
|
10732
10827
|
}, SEND_ACK_TIMEOUT_MS);
|
|
10733
10828
|
this.pendingAcks.set(id, { resolve, timer });
|
|
10734
10829
|
try {
|
|
10735
|
-
this.
|
|
10830
|
+
this.lifecycle.send({
|
|
10736
10831
|
type: "send",
|
|
10737
10832
|
id,
|
|
10738
10833
|
client_message_id: id,
|
|
@@ -10741,7 +10836,7 @@ class DaemonBrokerClient {
|
|
|
10741
10836
|
priority: req.priority,
|
|
10742
10837
|
nonce: req.nonce,
|
|
10743
10838
|
ciphertext: req.ciphertext
|
|
10744
|
-
})
|
|
10839
|
+
});
|
|
10745
10840
|
} catch (e) {
|
|
10746
10841
|
this.pendingAcks.delete(id);
|
|
10747
10842
|
clearTimeout(timer);
|
|
@@ -10755,7 +10850,7 @@ class DaemonBrokerClient {
|
|
|
10755
10850
|
});
|
|
10756
10851
|
}
|
|
10757
10852
|
async listPeers(timeoutMs = 5000) {
|
|
10758
|
-
if (this._status !== "open" || !this.
|
|
10853
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10759
10854
|
return [];
|
|
10760
10855
|
return new Promise((resolve) => {
|
|
10761
10856
|
const reqId = `pl-${++this.reqCounter}`;
|
|
@@ -10765,7 +10860,7 @@ class DaemonBrokerClient {
|
|
|
10765
10860
|
}, timeoutMs);
|
|
10766
10861
|
this.peerListResolvers.set(reqId, { resolve, timer });
|
|
10767
10862
|
try {
|
|
10768
|
-
this.
|
|
10863
|
+
this.lifecycle.send({ type: "list_peers", _reqId: reqId });
|
|
10769
10864
|
} catch {
|
|
10770
10865
|
this.peerListResolvers.delete(reqId);
|
|
10771
10866
|
clearTimeout(timer);
|
|
@@ -10774,7 +10869,7 @@ class DaemonBrokerClient {
|
|
|
10774
10869
|
});
|
|
10775
10870
|
}
|
|
10776
10871
|
async listSkills(query, timeoutMs = 5000) {
|
|
10777
|
-
if (this._status !== "open" || !this.
|
|
10872
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10778
10873
|
return [];
|
|
10779
10874
|
return new Promise((resolve) => {
|
|
10780
10875
|
const reqId = `sl-${++this.reqCounter}`;
|
|
@@ -10784,7 +10879,7 @@ class DaemonBrokerClient {
|
|
|
10784
10879
|
}, timeoutMs);
|
|
10785
10880
|
this.skillListResolvers.set(reqId, { resolve, timer });
|
|
10786
10881
|
try {
|
|
10787
|
-
this.
|
|
10882
|
+
this.lifecycle.send({ type: "list_skills", query, _reqId: reqId });
|
|
10788
10883
|
} catch {
|
|
10789
10884
|
this.skillListResolvers.delete(reqId);
|
|
10790
10885
|
clearTimeout(timer);
|
|
@@ -10793,7 +10888,7 @@ class DaemonBrokerClient {
|
|
|
10793
10888
|
});
|
|
10794
10889
|
}
|
|
10795
10890
|
async getSkill(name, timeoutMs = 5000) {
|
|
10796
|
-
if (this._status !== "open" || !this.
|
|
10891
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10797
10892
|
return null;
|
|
10798
10893
|
return new Promise((resolve) => {
|
|
10799
10894
|
const reqId = `sg-${++this.reqCounter}`;
|
|
@@ -10803,7 +10898,7 @@ class DaemonBrokerClient {
|
|
|
10803
10898
|
}, timeoutMs);
|
|
10804
10899
|
this.skillDataResolvers.set(reqId, { resolve, timer });
|
|
10805
10900
|
try {
|
|
10806
|
-
this.
|
|
10901
|
+
this.lifecycle.send({ type: "get_skill", name, _reqId: reqId });
|
|
10807
10902
|
} catch {
|
|
10808
10903
|
this.skillDataResolvers.delete(reqId);
|
|
10809
10904
|
clearTimeout(timer);
|
|
@@ -10812,7 +10907,7 @@ class DaemonBrokerClient {
|
|
|
10812
10907
|
});
|
|
10813
10908
|
}
|
|
10814
10909
|
async getState(key, timeoutMs = 5000) {
|
|
10815
|
-
if (this._status !== "open" || !this.
|
|
10910
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10816
10911
|
return null;
|
|
10817
10912
|
return new Promise((resolve) => {
|
|
10818
10913
|
const reqId = `sg-${++this.reqCounter}`;
|
|
@@ -10822,7 +10917,7 @@ class DaemonBrokerClient {
|
|
|
10822
10917
|
}, timeoutMs);
|
|
10823
10918
|
this.stateGetResolvers.set(reqId, { resolve, timer });
|
|
10824
10919
|
try {
|
|
10825
|
-
this.
|
|
10920
|
+
this.lifecycle.send({ type: "get_state", key, _reqId: reqId });
|
|
10826
10921
|
} catch {
|
|
10827
10922
|
this.stateGetResolvers.delete(reqId);
|
|
10828
10923
|
clearTimeout(timer);
|
|
@@ -10831,7 +10926,7 @@ class DaemonBrokerClient {
|
|
|
10831
10926
|
});
|
|
10832
10927
|
}
|
|
10833
10928
|
async listState(timeoutMs = 5000) {
|
|
10834
|
-
if (this._status !== "open" || !this.
|
|
10929
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10835
10930
|
return [];
|
|
10836
10931
|
return new Promise((resolve) => {
|
|
10837
10932
|
const reqId = `sl-${++this.reqCounter}`;
|
|
@@ -10841,7 +10936,7 @@ class DaemonBrokerClient {
|
|
|
10841
10936
|
}, timeoutMs);
|
|
10842
10937
|
this.stateListResolvers.set(reqId, { resolve, timer });
|
|
10843
10938
|
try {
|
|
10844
|
-
this.
|
|
10939
|
+
this.lifecycle.send({ type: "list_state", _reqId: reqId });
|
|
10845
10940
|
} catch {
|
|
10846
10941
|
this.stateListResolvers.delete(reqId);
|
|
10847
10942
|
clearTimeout(timer);
|
|
@@ -10850,14 +10945,14 @@ class DaemonBrokerClient {
|
|
|
10850
10945
|
});
|
|
10851
10946
|
}
|
|
10852
10947
|
setState(key, value) {
|
|
10853
|
-
if (this._status !== "open" || !this.
|
|
10948
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10854
10949
|
return;
|
|
10855
10950
|
try {
|
|
10856
|
-
this.
|
|
10951
|
+
this.lifecycle.send({ type: "set_state", key, value });
|
|
10857
10952
|
} catch {}
|
|
10858
10953
|
}
|
|
10859
10954
|
async remember(content, tags, timeoutMs = 5000) {
|
|
10860
|
-
if (this._status !== "open" || !this.
|
|
10955
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10861
10956
|
return null;
|
|
10862
10957
|
return new Promise((resolve) => {
|
|
10863
10958
|
const reqId = `mr-${++this.reqCounter}`;
|
|
@@ -10867,7 +10962,7 @@ class DaemonBrokerClient {
|
|
|
10867
10962
|
}, timeoutMs);
|
|
10868
10963
|
this.memoryStoreResolvers.set(reqId, { resolve, timer });
|
|
10869
10964
|
try {
|
|
10870
|
-
this.
|
|
10965
|
+
this.lifecycle.send({ type: "remember", content, tags, _reqId: reqId });
|
|
10871
10966
|
} catch {
|
|
10872
10967
|
this.memoryStoreResolvers.delete(reqId);
|
|
10873
10968
|
clearTimeout(timer);
|
|
@@ -10876,7 +10971,7 @@ class DaemonBrokerClient {
|
|
|
10876
10971
|
});
|
|
10877
10972
|
}
|
|
10878
10973
|
async recall(query, timeoutMs = 5000) {
|
|
10879
|
-
if (this._status !== "open" || !this.
|
|
10974
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10880
10975
|
return [];
|
|
10881
10976
|
return new Promise((resolve) => {
|
|
10882
10977
|
const reqId = `mc-${++this.reqCounter}`;
|
|
@@ -10886,7 +10981,7 @@ class DaemonBrokerClient {
|
|
|
10886
10981
|
}, timeoutMs);
|
|
10887
10982
|
this.memoryRecallResolvers.set(reqId, { resolve, timer });
|
|
10888
10983
|
try {
|
|
10889
|
-
this.
|
|
10984
|
+
this.lifecycle.send({ type: "recall", query, _reqId: reqId });
|
|
10890
10985
|
} catch {
|
|
10891
10986
|
this.memoryRecallResolvers.delete(reqId);
|
|
10892
10987
|
clearTimeout(timer);
|
|
@@ -10895,60 +10990,50 @@ class DaemonBrokerClient {
|
|
|
10895
10990
|
});
|
|
10896
10991
|
}
|
|
10897
10992
|
forget(memoryId) {
|
|
10898
|
-
if (this._status !== "open" || !this.
|
|
10993
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10899
10994
|
return;
|
|
10900
10995
|
try {
|
|
10901
|
-
this.
|
|
10996
|
+
this.lifecycle.send({ type: "forget", memoryId });
|
|
10902
10997
|
} catch {}
|
|
10903
10998
|
}
|
|
10904
10999
|
setProfile(profile) {
|
|
10905
|
-
if (this._status !== "open" || !this.
|
|
11000
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10906
11001
|
return;
|
|
10907
11002
|
try {
|
|
10908
|
-
this.
|
|
11003
|
+
this.lifecycle.send({ type: "set_profile", ...profile });
|
|
10909
11004
|
} catch {}
|
|
10910
11005
|
}
|
|
10911
11006
|
setSummary(summary) {
|
|
10912
|
-
if (this._status !== "open" || !this.
|
|
11007
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10913
11008
|
return;
|
|
10914
11009
|
try {
|
|
10915
|
-
this.
|
|
11010
|
+
this.lifecycle.send({ type: "set_summary", summary });
|
|
10916
11011
|
} catch {}
|
|
10917
11012
|
}
|
|
10918
11013
|
setStatus(status) {
|
|
10919
|
-
if (this._status !== "open" || !this.
|
|
11014
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10920
11015
|
return;
|
|
10921
11016
|
try {
|
|
10922
|
-
this.
|
|
11017
|
+
this.lifecycle.send({ type: "set_status", status });
|
|
10923
11018
|
} catch {}
|
|
10924
11019
|
}
|
|
10925
11020
|
setVisible(visible) {
|
|
10926
|
-
if (this._status !== "open" || !this.
|
|
11021
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
10927
11022
|
return;
|
|
10928
11023
|
try {
|
|
10929
|
-
this.
|
|
11024
|
+
this.lifecycle.send({ type: "set_visible", visible });
|
|
10930
11025
|
} catch {}
|
|
10931
11026
|
}
|
|
10932
11027
|
async close() {
|
|
10933
11028
|
this.closed = true;
|
|
10934
|
-
if (this.reconnectTimer) {
|
|
10935
|
-
clearTimeout(this.reconnectTimer);
|
|
10936
|
-
this.reconnectTimer = null;
|
|
10937
|
-
}
|
|
10938
|
-
if (this.helloTimer) {
|
|
10939
|
-
clearTimeout(this.helloTimer);
|
|
10940
|
-
this.helloTimer = null;
|
|
10941
|
-
}
|
|
10942
11029
|
this.failPendingAcks("daemon_shutdown");
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
return null;
|
|
10951
|
-
return { sessionPubkey: this.sessionPubkey, sessionSecretKey: this.sessionSecretKey };
|
|
11030
|
+
if (this.lifecycle) {
|
|
11031
|
+
try {
|
|
11032
|
+
await this.lifecycle.close();
|
|
11033
|
+
} catch {}
|
|
11034
|
+
this.lifecycle = null;
|
|
11035
|
+
}
|
|
11036
|
+
this._status = "closed";
|
|
10952
11037
|
}
|
|
10953
11038
|
failPendingAcks(reason) {
|
|
10954
11039
|
for (const [id, ack] of this.pendingAcks) {
|
|
@@ -10958,7 +11043,7 @@ class DaemonBrokerClient {
|
|
|
10958
11043
|
}
|
|
10959
11044
|
}
|
|
10960
11045
|
}
|
|
10961
|
-
function
|
|
11046
|
+
function defaultLog2(level, msg, meta) {
|
|
10962
11047
|
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
10963
11048
|
if (level === "info")
|
|
10964
11049
|
process.stdout.write(line + `
|
|
@@ -10970,24 +11055,21 @@ function defaultLog(level, msg, meta) {
|
|
|
10970
11055
|
function classifyPermanent(err) {
|
|
10971
11056
|
return /payload_too_large|forbidden|not_found|invalid|schema|auth|signature/i.test(err);
|
|
10972
11057
|
}
|
|
10973
|
-
var
|
|
11058
|
+
var SEND_ACK_TIMEOUT_MS = 15000;
|
|
10974
11059
|
var init_broker = __esm(() => {
|
|
10975
11060
|
init_hello_sig();
|
|
10976
|
-
|
|
11061
|
+
init_ws_lifecycle();
|
|
10977
11062
|
});
|
|
10978
11063
|
|
|
10979
11064
|
// src/daemon/session-broker.ts
|
|
10980
11065
|
import { hostname as osHostname } from "node:os";
|
|
10981
|
-
import WebSocket3 from "ws";
|
|
10982
11066
|
|
|
10983
11067
|
class SessionBrokerClient {
|
|
10984
11068
|
opts;
|
|
10985
|
-
|
|
11069
|
+
lifecycle = null;
|
|
10986
11070
|
_status = "closed";
|
|
10987
11071
|
closed = false;
|
|
10988
|
-
|
|
10989
|
-
reconnectTimer = null;
|
|
10990
|
-
helloTimer = null;
|
|
11072
|
+
brokerUnsupported = false;
|
|
10991
11073
|
constructor(opts) {
|
|
10992
11074
|
this.opts = opts;
|
|
10993
11075
|
}
|
|
@@ -11001,126 +11083,95 @@ class SessionBrokerClient {
|
|
|
11001
11083
|
return this.opts.sessionPubkey;
|
|
11002
11084
|
}
|
|
11003
11085
|
log = (level, msg, meta) => {
|
|
11004
|
-
(this.opts.log ??
|
|
11086
|
+
(this.opts.log ?? defaultLog3)(level, msg, {
|
|
11005
11087
|
mesh: this.opts.mesh.slug,
|
|
11006
11088
|
session_pubkey: this.opts.sessionPubkey.slice(0, 12),
|
|
11007
11089
|
...meta
|
|
11008
11090
|
});
|
|
11009
11091
|
};
|
|
11010
|
-
setStatus(s) {
|
|
11011
|
-
if (this._status === s)
|
|
11012
|
-
return;
|
|
11013
|
-
this._status = s;
|
|
11014
|
-
this.opts.onStatusChange?.(s);
|
|
11015
|
-
}
|
|
11016
11092
|
async connect() {
|
|
11017
11093
|
if (this.closed)
|
|
11018
11094
|
throw new Error("client_closed");
|
|
11019
11095
|
if (this._status === "connecting" || this._status === "open")
|
|
11020
11096
|
return;
|
|
11021
|
-
this.
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
this.helloTimer = setTimeout(() => {
|
|
11053
|
-
this.log("warn", "session_hello_ack_timeout");
|
|
11054
|
-
try {
|
|
11055
|
-
ws.close();
|
|
11056
|
-
} catch {}
|
|
11057
|
-
reject(new Error("session_hello_ack_timeout"));
|
|
11058
|
-
}, HELLO_ACK_TIMEOUT_MS3);
|
|
11059
|
-
} catch (e) {
|
|
11060
|
-
reject(e instanceof Error ? e : new Error(String(e)));
|
|
11061
|
-
}
|
|
11062
|
-
});
|
|
11063
|
-
ws.on("message", (raw) => {
|
|
11064
|
-
let msg;
|
|
11065
|
-
try {
|
|
11066
|
-
msg = JSON.parse(raw.toString());
|
|
11067
|
-
} catch {
|
|
11068
|
-
return;
|
|
11069
|
-
}
|
|
11070
|
-
if (msg.type === "hello_ack") {
|
|
11071
|
-
if (this.helloTimer)
|
|
11072
|
-
clearTimeout(this.helloTimer);
|
|
11073
|
-
this.helloTimer = null;
|
|
11074
|
-
this.setStatus("open");
|
|
11075
|
-
this.reconnectAttempt = 0;
|
|
11076
|
-
resolve();
|
|
11077
|
-
return;
|
|
11078
|
-
}
|
|
11097
|
+
this.lifecycle = await connectWsWithBackoff({
|
|
11098
|
+
url: this.opts.mesh.brokerUrl,
|
|
11099
|
+
buildHello: async () => {
|
|
11100
|
+
const { timestamp: timestamp2, signature } = await signSessionHello({
|
|
11101
|
+
meshId: this.opts.mesh.meshId,
|
|
11102
|
+
parentMemberPubkey: this.opts.mesh.pubkey,
|
|
11103
|
+
sessionPubkey: this.opts.sessionPubkey,
|
|
11104
|
+
sessionSecretKey: this.opts.sessionSecretKey
|
|
11105
|
+
});
|
|
11106
|
+
return {
|
|
11107
|
+
type: "session_hello",
|
|
11108
|
+
meshId: this.opts.mesh.meshId,
|
|
11109
|
+
parentMemberId: this.opts.mesh.memberId,
|
|
11110
|
+
parentMemberPubkey: this.opts.mesh.pubkey,
|
|
11111
|
+
sessionPubkey: this.opts.sessionPubkey,
|
|
11112
|
+
parentAttestation: this.opts.parentAttestation,
|
|
11113
|
+
displayName: this.opts.displayName,
|
|
11114
|
+
sessionId: this.opts.sessionId,
|
|
11115
|
+
pid: this.opts.pid,
|
|
11116
|
+
cwd: this.opts.cwd ?? process.cwd(),
|
|
11117
|
+
hostname: osHostname(),
|
|
11118
|
+
peerType: "ai",
|
|
11119
|
+
channel: "claudemesh-session",
|
|
11120
|
+
...this.opts.groups && this.opts.groups.length > 0 ? { groups: this.opts.groups } : {},
|
|
11121
|
+
...this.opts.role ? { role: this.opts.role } : {},
|
|
11122
|
+
timestamp: timestamp2,
|
|
11123
|
+
signature
|
|
11124
|
+
};
|
|
11125
|
+
},
|
|
11126
|
+
isHelloAck: (msg) => msg.type === "hello_ack",
|
|
11127
|
+
onMessage: (msg) => {
|
|
11079
11128
|
if (msg.type === "error") {
|
|
11080
11129
|
this.log("warn", "broker_error", { code: msg.code, message: msg.message });
|
|
11081
11130
|
if (msg.code === "unknown_message_type") {
|
|
11131
|
+
this.brokerUnsupported = true;
|
|
11082
11132
|
this.closed = true;
|
|
11133
|
+
this.lifecycle?.close();
|
|
11083
11134
|
}
|
|
11084
11135
|
return;
|
|
11085
11136
|
}
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
if (this.helloTimer) {
|
|
11089
|
-
clearTimeout(this.helloTimer);
|
|
11090
|
-
this.helloTimer = null;
|
|
11091
|
-
}
|
|
11092
|
-
if (this.closed) {
|
|
11093
|
-
this.setStatus("closed");
|
|
11137
|
+
if (msg.type === "push" || msg.type === "inbound") {
|
|
11138
|
+
this.opts.onPush?.(msg);
|
|
11094
11139
|
return;
|
|
11095
11140
|
}
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
this.
|
|
11099
|
-
this.
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
reject(new Error(`closed_before_hello_${code}`));
|
|
11103
|
-
});
|
|
11104
|
-
ws.on("error", (err) => this.log("warn", "session_broker_ws_error", { err: err.message }));
|
|
11141
|
+
},
|
|
11142
|
+
onStatusChange: (s) => {
|
|
11143
|
+
this._status = s;
|
|
11144
|
+
this.opts.onStatusChange?.(s);
|
|
11145
|
+
},
|
|
11146
|
+
log: (level, msg, meta) => this.log(level, `session_broker_${msg}`, meta)
|
|
11105
11147
|
});
|
|
11106
11148
|
}
|
|
11149
|
+
sendClientAck(clientMessageId, brokerMessageId) {
|
|
11150
|
+
if (this._status !== "open" || !this.lifecycle)
|
|
11151
|
+
return;
|
|
11152
|
+
try {
|
|
11153
|
+
this.lifecycle.send({
|
|
11154
|
+
type: "client_ack",
|
|
11155
|
+
clientMessageId,
|
|
11156
|
+
...brokerMessageId ? { brokerMessageId } : {}
|
|
11157
|
+
});
|
|
11158
|
+
} catch {}
|
|
11159
|
+
}
|
|
11107
11160
|
async close() {
|
|
11108
11161
|
this.closed = true;
|
|
11109
|
-
if (this.
|
|
11110
|
-
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
clearTimeout(this.helloTimer);
|
|
11115
|
-
this.helloTimer = null;
|
|
11162
|
+
if (this.lifecycle) {
|
|
11163
|
+
try {
|
|
11164
|
+
await this.lifecycle.close();
|
|
11165
|
+
} catch {}
|
|
11166
|
+
this.lifecycle = null;
|
|
11116
11167
|
}
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
this.
|
|
11168
|
+
this._status = "closed";
|
|
11169
|
+
}
|
|
11170
|
+
get isBrokerUnsupported() {
|
|
11171
|
+
return this.brokerUnsupported;
|
|
11121
11172
|
}
|
|
11122
11173
|
}
|
|
11123
|
-
function
|
|
11174
|
+
function defaultLog3(level, msg, meta) {
|
|
11124
11175
|
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
11125
11176
|
if (level === "info")
|
|
11126
11177
|
process.stdout.write(line + `
|
|
@@ -11129,15 +11180,14 @@ function defaultLog2(level, msg, meta) {
|
|
|
11129
11180
|
process.stderr.write(line + `
|
|
11130
11181
|
`);
|
|
11131
11182
|
}
|
|
11132
|
-
var HELLO_ACK_TIMEOUT_MS3 = 5000, BACKOFF_CAPS_MS2;
|
|
11133
11183
|
var init_session_broker = __esm(() => {
|
|
11134
11184
|
init_session_hello_sig();
|
|
11135
|
-
|
|
11185
|
+
init_ws_lifecycle();
|
|
11136
11186
|
});
|
|
11137
11187
|
|
|
11138
11188
|
// src/daemon/drain.ts
|
|
11139
11189
|
function startDrainWorker(opts) {
|
|
11140
|
-
const log2 = opts.log ??
|
|
11190
|
+
const log2 = opts.log ?? defaultLog4;
|
|
11141
11191
|
let stopped = false;
|
|
11142
11192
|
let wakeResolve = null;
|
|
11143
11193
|
let wakePromise = new Promise((r) => {
|
|
@@ -11281,7 +11331,7 @@ async function randomNonce2() {
|
|
|
11281
11331
|
const { randomBytes: randomBytes6 } = await import("node:crypto");
|
|
11282
11332
|
return randomBytes6(24).toString("base64");
|
|
11283
11333
|
}
|
|
11284
|
-
function
|
|
11334
|
+
function defaultLog4(level, msg, meta) {
|
|
11285
11335
|
const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
|
|
11286
11336
|
if (level === "info")
|
|
11287
11337
|
process.stdout.write(line + `
|
|
@@ -11338,6 +11388,7 @@ async function handleBrokerPush(msg, ctx) {
|
|
|
11338
11388
|
received_at: Date.now(),
|
|
11339
11389
|
reply_to_id: replyToId
|
|
11340
11390
|
});
|
|
11391
|
+
ctx.ackClientMessage?.(clientMessageId, brokerMessageId);
|
|
11341
11392
|
if (!inserted)
|
|
11342
11393
|
return;
|
|
11343
11394
|
ctx.bus.publish("message", {
|
|
@@ -11608,13 +11659,12 @@ async function runDaemon(opts = {}) {
|
|
|
11608
11659
|
bus.publish("broker_status", { mesh: mesh.slug, status: s });
|
|
11609
11660
|
},
|
|
11610
11661
|
onPush: (m) => {
|
|
11611
|
-
const sessionKeys = broker.getSessionKeys();
|
|
11612
11662
|
handleBrokerPush(m, {
|
|
11613
11663
|
db: inboxDb,
|
|
11614
11664
|
bus,
|
|
11615
11665
|
meshSlug: mesh.slug,
|
|
11616
11666
|
recipientSecretKeyHex: mesh.secretKey,
|
|
11617
|
-
|
|
11667
|
+
ackClientMessage: (cmid, bmid) => broker.sendClientAck(cmid, bmid)
|
|
11618
11668
|
});
|
|
11619
11669
|
}
|
|
11620
11670
|
});
|
|
@@ -11645,6 +11695,7 @@ async function runDaemon(opts = {}) {
|
|
|
11645
11695
|
sessionBrokers.delete(info.token);
|
|
11646
11696
|
prior.close().catch(() => {});
|
|
11647
11697
|
}
|
|
11698
|
+
const sessionSecretKeyHex = info.presence.sessionSecretKey;
|
|
11648
11699
|
const client = new SessionBrokerClient({
|
|
11649
11700
|
mesh: meshConfig,
|
|
11650
11701
|
sessionPubkey: info.presence.sessionPubkey,
|
|
@@ -11654,7 +11705,17 @@ async function runDaemon(opts = {}) {
|
|
|
11654
11705
|
displayName: info.displayName,
|
|
11655
11706
|
...info.role ? { role: info.role } : {},
|
|
11656
11707
|
...info.cwd ? { cwd: info.cwd } : {},
|
|
11657
|
-
pid: info.pid
|
|
11708
|
+
pid: info.pid,
|
|
11709
|
+
onPush: (m) => {
|
|
11710
|
+
handleBrokerPush(m, {
|
|
11711
|
+
db: inboxDb,
|
|
11712
|
+
bus,
|
|
11713
|
+
meshSlug: meshConfig.slug,
|
|
11714
|
+
recipientSecretKeyHex: meshConfig.secretKey,
|
|
11715
|
+
sessionSecretKeyHex,
|
|
11716
|
+
ackClientMessage: (cmid, bmid) => client.sendClientAck(cmid, bmid)
|
|
11717
|
+
});
|
|
11718
|
+
}
|
|
11658
11719
|
});
|
|
11659
11720
|
sessionBrokers.set(info.token, client);
|
|
11660
11721
|
client.connect().catch((err) => process.stderr.write(JSON.stringify({
|
|
@@ -13062,8 +13123,8 @@ async function checkBrokerWs() {
|
|
|
13062
13123
|
const wsUrl = URLS.BROKER;
|
|
13063
13124
|
const start = Date.now();
|
|
13064
13125
|
try {
|
|
13065
|
-
const
|
|
13066
|
-
const ws = new
|
|
13126
|
+
const WebSocket3 = (await import("ws")).default;
|
|
13127
|
+
const ws = new WebSocket3(wsUrl);
|
|
13067
13128
|
const result = await new Promise((resolve2) => {
|
|
13068
13129
|
const timer = setTimeout(() => {
|
|
13069
13130
|
try {
|
|
@@ -13174,11 +13235,11 @@ __export(exports_status, {
|
|
|
13174
13235
|
runStatus: () => runStatus2
|
|
13175
13236
|
});
|
|
13176
13237
|
import { statSync as statSync4, existsSync as existsSync16 } from "node:fs";
|
|
13177
|
-
import
|
|
13238
|
+
import WebSocket3 from "ws";
|
|
13178
13239
|
async function probeBroker(url, timeoutMs = 4000) {
|
|
13179
13240
|
return new Promise((resolve2) => {
|
|
13180
13241
|
const started = Date.now();
|
|
13181
|
-
const ws = new
|
|
13242
|
+
const ws = new WebSocket3(url);
|
|
13182
13243
|
const timer = setTimeout(() => {
|
|
13183
13244
|
try {
|
|
13184
13245
|
ws.terminate();
|
|
@@ -16388,7 +16449,7 @@ var require_client = __commonJS((exports) => {
|
|
|
16388
16449
|
var ws_1 = __importDefault(__require("ws"));
|
|
16389
16450
|
var crypto_js_1 = require_crypto();
|
|
16390
16451
|
var MAX_QUEUED2 = 100;
|
|
16391
|
-
var
|
|
16452
|
+
var HELLO_ACK_TIMEOUT_MS2 = 5000;
|
|
16392
16453
|
var BACKOFF_CAPS2 = [1000, 2000, 4000, 8000, 16000, 30000];
|
|
16393
16454
|
|
|
16394
16455
|
class MeshClient extends node_events_1.EventEmitter {
|
|
@@ -16453,7 +16514,7 @@ var require_client = __commonJS((exports) => {
|
|
|
16453
16514
|
this.debug("hello_ack timeout");
|
|
16454
16515
|
ws.close();
|
|
16455
16516
|
reject(new Error("hello_ack timeout"));
|
|
16456
|
-
},
|
|
16517
|
+
}, HELLO_ACK_TIMEOUT_MS2);
|
|
16457
16518
|
};
|
|
16458
16519
|
const onMessage = (raw) => {
|
|
16459
16520
|
let msg;
|
|
@@ -20273,4 +20334,4 @@ main().catch((err) => {
|
|
|
20273
20334
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
20274
20335
|
});
|
|
20275
20336
|
|
|
20276
|
-
//# debugId=
|
|
20337
|
+
//# debugId=DC25A8288183DA4364756E2164756E21
|