@cryptiklemur/lattice 1.37.0 → 1.37.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptiklemur/lattice",
|
|
3
|
-
"version": "1.37.
|
|
3
|
+
"version": "1.37.2",
|
|
4
4
|
"description": "Multi-machine agentic dashboard for Claude Code. Monitor sessions, manage MCP servers and skills, orchestrate across mesh-networked nodes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Aaron Scherer <me@aaronscherer.me>",
|
package/server/src/daemon.ts
CHANGED
|
@@ -250,7 +250,7 @@ export async function startDaemon(portOverride?: number | null): Promise<void> {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
if (!isAuthenticated(req, config.passphraseHash)) {
|
|
253
|
+
if (url.pathname !== "/ws" && !isAuthenticated(req, config.passphraseHash)) {
|
|
254
254
|
return new Response(buildLoginPage(), {
|
|
255
255
|
status: 200,
|
|
256
256
|
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
@@ -5,7 +5,8 @@ import { loadConfig } from "../config";
|
|
|
5
5
|
import { loadOrCreateIdentity } from "../identity";
|
|
6
6
|
import { generateInviteCode, parseInviteCode, validatePairingToken, consumePairingToken } from "../mesh/pairing";
|
|
7
7
|
import { addPeer, removePeer, loadPeers, getPeer } from "../mesh/peers";
|
|
8
|
-
import { getConnectedPeerIds, connectToPeer, reconnectPeer, getPeerConnection, disconnectPeer, getConnectedPeerProjects } from "../mesh/connector";
|
|
8
|
+
import { getConnectedPeerIds, connectToPeer, reconnectPeer, getPeerConnection, disconnectPeer, getConnectedPeerProjects, registerInboundPeer } from "../mesh/connector";
|
|
9
|
+
import { getClientWebSocket } from "../ws/broadcast";
|
|
9
10
|
import type { PeerInfo } from "@lattice/shared";
|
|
10
11
|
import { networkInterfaces } from "node:os";
|
|
11
12
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -237,6 +238,12 @@ registerHandler("mesh", function (clientId: string, message: ClientMessage) {
|
|
|
237
238
|
sendTo(clientId, { type: "mesh:hello_rejected" as any, error: "Public key mismatch — possible impersonation" });
|
|
238
239
|
return;
|
|
239
240
|
}
|
|
241
|
+
|
|
242
|
+
var inboundWs = getClientWebSocket(clientId);
|
|
243
|
+
if (inboundWs) {
|
|
244
|
+
registerInboundPeer(hello.nodeId, inboundWs as any);
|
|
245
|
+
}
|
|
246
|
+
|
|
240
247
|
var identity = loadOrCreateIdentity();
|
|
241
248
|
sendTo(clientId, {
|
|
242
249
|
type: "mesh:hello" as any,
|
|
@@ -239,6 +239,52 @@ export function getPeerConnection(nodeId: string): WebSocket | undefined {
|
|
|
239
239
|
return conn.ws;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
export function registerInboundPeer(nodeId: string, ws: { send: (data: string) => void; readyState: number }): void {
|
|
243
|
+
var existing = connections.get(nodeId);
|
|
244
|
+
if (existing && !existing.dead && existing.ws.readyState === WebSocket.OPEN) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (existing) {
|
|
249
|
+
existing.dead = true;
|
|
250
|
+
if (existing.retryTimer !== null) {
|
|
251
|
+
clearTimeout(existing.retryTimer);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
circuitBreakers.delete(nodeId);
|
|
256
|
+
|
|
257
|
+
var conn: PeerConnection = {
|
|
258
|
+
nodeId: nodeId,
|
|
259
|
+
ws: ws as WebSocket,
|
|
260
|
+
backoffMs: 1000,
|
|
261
|
+
retryTimer: null,
|
|
262
|
+
dead: false,
|
|
263
|
+
projects: [],
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
connections.set(nodeId, conn);
|
|
267
|
+
|
|
268
|
+
var peers = loadPeers();
|
|
269
|
+
var peer = peers.find(function (p) { return p.id === nodeId; });
|
|
270
|
+
if (peer) {
|
|
271
|
+
var identity = loadOrCreateIdentity();
|
|
272
|
+
var config = loadConfig();
|
|
273
|
+
var projects = config.projects || [];
|
|
274
|
+
conn.projects = [];
|
|
275
|
+
|
|
276
|
+
ws.send(JSON.stringify({
|
|
277
|
+
type: "mesh:hello",
|
|
278
|
+
nodeId: identity.id,
|
|
279
|
+
name: config.name,
|
|
280
|
+
publicKey: identity.publicKey,
|
|
281
|
+
projects: projects.map(function (p: { slug: string; title: string }) {
|
|
282
|
+
return { slug: p.slug, title: p.title };
|
|
283
|
+
}),
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
242
288
|
export function disconnectPeer(nodeId: string): void {
|
|
243
289
|
var existing = connections.get(nodeId);
|
|
244
290
|
if (existing) {
|
|
@@ -40,6 +40,10 @@ export function sendTo(id: string, message: object): void {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export function getClientWebSocket(id: string): ServerWebSocket<{ id: string }> | undefined {
|
|
44
|
+
return clients.get(id);
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
export function getClientCount(): number {
|
|
44
48
|
return clients.size;
|
|
45
49
|
}
|