@cryptiklemur/lattice 5.2.0 → 5.3.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/server/daemon.js +6 -1
- package/dist/server/index.js +128 -29
- package/package.json +1 -1
package/dist/server/daemon.js
CHANGED
|
@@ -407,7 +407,12 @@ export async function startDaemon(portOverride, tlsOverride) {
|
|
|
407
407
|
log.server("TLS enabled (cert: %s)", certs.cert);
|
|
408
408
|
}
|
|
409
409
|
catch (err) {
|
|
410
|
-
|
|
410
|
+
if (err?.code === "EACCES") {
|
|
411
|
+
console.error("[lattice] Permission denied reading TLS certs. Run 'lattice setup-tls' to fix permissions.");
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
console.error("[lattice] Failed to load TLS certs, falling back to HTTP:", err);
|
|
415
|
+
}
|
|
411
416
|
}
|
|
412
417
|
}
|
|
413
418
|
if (tlsOptions) {
|
package/dist/server/index.js
CHANGED
|
@@ -18,7 +18,7 @@ function getCurrentVersion() {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
var args = process.argv.slice(2);
|
|
21
|
-
var command = "
|
|
21
|
+
var command = "help";
|
|
22
22
|
var portOverride = null;
|
|
23
23
|
var tlsOverride = null;
|
|
24
24
|
for (var i = 0; i < args.length; i++) {
|
|
@@ -92,11 +92,11 @@ function spawnDaemon(port, tls) {
|
|
|
92
92
|
var pkgRoot = join(__dirname_local, "..");
|
|
93
93
|
var localTsx = join(pkgRoot, "node_modules", ".bin", "tsx");
|
|
94
94
|
spawnCmd = existsSync(localTsx) ? localTsx : "tsx";
|
|
95
|
-
spawnArgs = ["--tsconfig", join(pkgRoot, "tsconfig.json"), __filename_local, "
|
|
95
|
+
spawnArgs = ["--tsconfig", join(pkgRoot, "tsconfig.json"), __filename_local, "run", "--port", String(port)];
|
|
96
96
|
}
|
|
97
97
|
else {
|
|
98
98
|
spawnCmd = process.execPath;
|
|
99
|
-
spawnArgs = [__filename_local, "
|
|
99
|
+
spawnArgs = [__filename_local, "run", "--port", String(port)];
|
|
100
100
|
}
|
|
101
101
|
if (tls === true)
|
|
102
102
|
spawnArgs.push("--tls");
|
|
@@ -111,6 +111,7 @@ function spawnDaemon(port, tls) {
|
|
|
111
111
|
return child.pid;
|
|
112
112
|
}
|
|
113
113
|
switch (command) {
|
|
114
|
+
case "run":
|
|
114
115
|
case "daemon":
|
|
115
116
|
await runDaemon();
|
|
116
117
|
break;
|
|
@@ -263,7 +264,8 @@ function runHelp() {
|
|
|
263
264
|
console.log(" Usage: lattice [command] [options]");
|
|
264
265
|
console.log("");
|
|
265
266
|
console.log(" Commands:");
|
|
266
|
-
console.log(" start Start the daemon and open the UI
|
|
267
|
+
console.log(" start Start the daemon and open the UI");
|
|
268
|
+
console.log(" run Run the daemon in the foreground");
|
|
267
269
|
console.log(" stop Stop the running daemon");
|
|
268
270
|
console.log(" restart Stop and restart the daemon");
|
|
269
271
|
console.log(" status Show daemon status and connection info");
|
|
@@ -273,7 +275,7 @@ function runHelp() {
|
|
|
273
275
|
console.log(" open Open the UI in the browser");
|
|
274
276
|
console.log(" config Show configuration paths and settings");
|
|
275
277
|
console.log(" setup-tls Set up HTTPS (Tailscale or self-signed)");
|
|
276
|
-
console.log(" help Show this help message");
|
|
278
|
+
console.log(" help Show this help message (default)");
|
|
277
279
|
console.log("");
|
|
278
280
|
console.log(" Options:");
|
|
279
281
|
console.log(" --port=N Override the server port");
|
|
@@ -286,51 +288,148 @@ function runHelp() {
|
|
|
286
288
|
console.log("");
|
|
287
289
|
}
|
|
288
290
|
async function runSetupTls() {
|
|
289
|
-
var {
|
|
291
|
+
var { spawnSync } = await import("node:child_process");
|
|
292
|
+
var { createInterface } = await import("node:readline");
|
|
293
|
+
var { mkdirSync, chmodSync, chownSync, statSync } = await import("node:fs");
|
|
290
294
|
var certsDir = join(getLatticeHome(), "certs");
|
|
291
295
|
var certPath = join(certsDir, "cert.pem");
|
|
292
296
|
var keyPath = join(certsDir, "key.pem");
|
|
293
|
-
|
|
297
|
+
function prompt(question) {
|
|
298
|
+
var rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
299
|
+
return new Promise(function (resolve) {
|
|
300
|
+
rl.question(question, function (answer) {
|
|
301
|
+
rl.close();
|
|
302
|
+
resolve(answer.trim().toLowerCase());
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
console.log("");
|
|
307
|
+
console.log(" lattice — TLS Setup");
|
|
294
308
|
console.log("");
|
|
295
309
|
var hasTailscale = false;
|
|
310
|
+
var hostname = "";
|
|
296
311
|
try {
|
|
297
|
-
|
|
312
|
+
spawnSync("tailscale", ["version"], { stdio: "ignore" });
|
|
298
313
|
hasTailscale = true;
|
|
314
|
+
var statusResult = spawnSync("tailscale", ["status", "--json"], { encoding: "utf-8" });
|
|
315
|
+
if (statusResult.status === 0) {
|
|
316
|
+
hostname = JSON.parse(statusResult.stdout).Self.DNSName.replace(/\.$/, "");
|
|
317
|
+
}
|
|
299
318
|
}
|
|
300
319
|
catch { }
|
|
301
|
-
if (hasTailscale) {
|
|
302
|
-
console.log(" Tailscale detected
|
|
320
|
+
if (hasTailscale && hostname) {
|
|
321
|
+
console.log(" Tailscale detected: " + hostname);
|
|
303
322
|
console.log("");
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
323
|
+
var answer = await prompt(" Set up Tailscale HTTPS certs automatically? [Y/n] ");
|
|
324
|
+
if (answer !== "n" && answer !== "no") {
|
|
325
|
+
if (!existsSync(certsDir)) {
|
|
326
|
+
mkdirSync(certsDir, { recursive: true });
|
|
327
|
+
}
|
|
309
328
|
console.log("");
|
|
310
|
-
console.log("
|
|
311
|
-
console.log(" lattice restart --tls");
|
|
329
|
+
console.log(" Generating Tailscale cert (sudo required)...");
|
|
312
330
|
console.log("");
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
331
|
+
var certResult = spawnSync("sudo", ["tailscale", "cert", "--cert-file", certPath, "--key-file", keyPath, hostname], { stdio: "inherit" });
|
|
332
|
+
if (certResult.status !== 0) {
|
|
333
|
+
console.error("");
|
|
334
|
+
console.error(" Failed to generate Tailscale certs.");
|
|
335
|
+
console.error(" You can run manually:");
|
|
336
|
+
console.error(" sudo tailscale cert --cert-file " + certPath + " --key-file " + keyPath + " " + hostname);
|
|
337
|
+
process.exit(1);
|
|
338
|
+
}
|
|
339
|
+
var uid = process.getuid ? process.getuid() : 0;
|
|
340
|
+
var gid = process.getgid ? process.getgid() : 0;
|
|
341
|
+
try {
|
|
342
|
+
chownSync(certPath, uid, gid);
|
|
343
|
+
chownSync(keyPath, uid, gid);
|
|
344
|
+
chmodSync(certPath, 0o644);
|
|
345
|
+
chmodSync(keyPath, 0o600);
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
console.log(" Fixing permissions with sudo...");
|
|
349
|
+
spawnSync("sudo", ["chown", uid + ":" + gid, certPath, keyPath], { stdio: "inherit" });
|
|
350
|
+
spawnSync("sudo", ["chmod", "644", certPath], { stdio: "inherit" });
|
|
351
|
+
spawnSync("sudo", ["chmod", "600", keyPath], { stdio: "inherit" });
|
|
352
|
+
}
|
|
353
|
+
console.log("");
|
|
354
|
+
console.log(" Certs installed and permissions fixed.");
|
|
355
|
+
var config = loadConfig();
|
|
356
|
+
if (!config.tls) {
|
|
357
|
+
var { saveConfig: saveCfg } = await import("./config.js");
|
|
358
|
+
config.tls = true;
|
|
359
|
+
saveCfg(config);
|
|
360
|
+
console.log(" TLS enabled in config.");
|
|
361
|
+
}
|
|
362
|
+
var pid = readPid();
|
|
363
|
+
if (pid !== null && isDaemonRunning(pid)) {
|
|
364
|
+
var restartAnswer = await prompt(" Daemon is running. Restart with TLS? [Y/n] ");
|
|
365
|
+
if (restartAnswer !== "n" && restartAnswer !== "no") {
|
|
366
|
+
console.log(" Restarting daemon...");
|
|
367
|
+
try {
|
|
368
|
+
process.kill(pid, "SIGTERM");
|
|
369
|
+
}
|
|
370
|
+
catch { }
|
|
371
|
+
removePid();
|
|
372
|
+
await new Promise(function (r) { setTimeout(r, 1500); });
|
|
373
|
+
var port = portOverride ?? config.port;
|
|
374
|
+
var childPid = spawnDaemon(port, true);
|
|
375
|
+
writePid(childPid);
|
|
376
|
+
console.log(" Daemon restarted (PID " + childPid + ")");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
console.log("");
|
|
380
|
+
console.log(" Access at: https://" + hostname + ":" + loadConfig().port);
|
|
381
|
+
console.log("");
|
|
382
|
+
return;
|
|
319
383
|
}
|
|
320
384
|
}
|
|
321
|
-
else {
|
|
322
|
-
console.log(" Tailscale
|
|
385
|
+
else if (hasTailscale) {
|
|
386
|
+
console.log(" Tailscale detected but could not determine hostname.");
|
|
387
|
+
console.log(" Run 'tailscale status' to verify your connection.");
|
|
323
388
|
console.log("");
|
|
324
389
|
}
|
|
325
|
-
console.log("");
|
|
326
390
|
console.log(" ── Self-signed certificate ──");
|
|
327
391
|
console.log("");
|
|
328
|
-
if (existsSync(certPath)) {
|
|
392
|
+
if (existsSync(certPath) && existsSync(keyPath)) {
|
|
329
393
|
console.log(" Cert exists: " + certPath);
|
|
330
|
-
console.log(" To regenerate: rm -rf " + certsDir + " && lattice
|
|
394
|
+
console.log(" To regenerate: rm -rf " + certsDir + " && lattice setup-tls");
|
|
331
395
|
}
|
|
332
396
|
else {
|
|
333
|
-
|
|
397
|
+
var selfSignAnswer = await prompt(" Generate a self-signed certificate? [Y/n] ");
|
|
398
|
+
if (selfSignAnswer !== "n" && selfSignAnswer !== "no") {
|
|
399
|
+
var { ensureCerts } = await import("./tls.js");
|
|
400
|
+
try {
|
|
401
|
+
var certs = ensureCerts();
|
|
402
|
+
console.log(" Certificate generated: " + certs.cert);
|
|
403
|
+
var config = loadConfig();
|
|
404
|
+
if (!config.tls) {
|
|
405
|
+
var { saveConfig: saveCfg } = await import("./config.js");
|
|
406
|
+
config.tls = true;
|
|
407
|
+
saveCfg(config);
|
|
408
|
+
console.log(" TLS enabled in config.");
|
|
409
|
+
}
|
|
410
|
+
var pid = readPid();
|
|
411
|
+
if (pid !== null && isDaemonRunning(pid)) {
|
|
412
|
+
var restartAnswer = await prompt(" Daemon is running. Restart with TLS? [Y/n] ");
|
|
413
|
+
if (restartAnswer !== "n" && restartAnswer !== "no") {
|
|
414
|
+
console.log(" Restarting daemon...");
|
|
415
|
+
try {
|
|
416
|
+
process.kill(pid, "SIGTERM");
|
|
417
|
+
}
|
|
418
|
+
catch { }
|
|
419
|
+
removePid();
|
|
420
|
+
await new Promise(function (r) { setTimeout(r, 1500); });
|
|
421
|
+
var port = portOverride ?? config.port;
|
|
422
|
+
var childPid = spawnDaemon(port, true);
|
|
423
|
+
writePid(childPid);
|
|
424
|
+
console.log(" Daemon restarted (PID " + childPid + ")");
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
console.error(" Failed to generate certificate:", err);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
334
433
|
}
|
|
335
434
|
console.log("");
|
|
336
435
|
console.log(" To trust the self-signed cert (removes browser warnings):");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cryptiklemur/lattice",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
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>",
|