meldivo 1.1.1 → 2.0.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/README.md CHANGED
@@ -77,7 +77,11 @@ project.
77
77
  | `meldivo remote cloudflare` | Publish the hub through a Cloudflare quick tunnel. |
78
78
  | `meldivo remote certificate` | Publish the hub over HTTPS using your own certificate. |
79
79
  | `meldivo remote stop` | Turn remote access off. |
80
- | `meldivo peer add <name> <link>` | Show another machine's hub (and its sessions) in this one. `meldivo peer` lists peers; `meldivo peer remove <name>` removes one. |
80
+ | `meldivo hub enable` | Make this machine a hub that your other machines join. `meldivo hub disable` turns it off. |
81
+ | `meldivo hub code` | Print a one-time code (10 minutes, single use) and the `meldivo join` command for adding a machine. |
82
+ | `meldivo hub machines` | List the machines that joined this hub. `meldivo hub remove <name>` removes one at once. |
83
+ | `meldivo join <hub-address> <code>` | Join a hub, so this machine's sessions appear there. Options: `--name <name>`, `--allow pi,opencode,claude`, `--speech` (also do speech for the hub). |
84
+ | `meldivo leave` | Leave the hub this machine joined. |
81
85
  | `meldivo logs` | Show the service's recent log output. |
82
86
  | `meldivo uninstall [--purge]` | Remove the background service. `--purge` also deletes configuration, models, and logs. |
83
87
  | `meldivo --version` | Print the installed version. |
@@ -101,28 +105,42 @@ how to trust a certificate on iPhone and Android.
101
105
 
102
106
  ## Several machines, one hub
103
107
 
104
- Install meldivo on each machine, pick one as the main hub, and add the others
105
- to it as peers. The main hub then lists every machine with its own new-chat
106
- tiles and sessions, all behind the main hub's single link. Speech runs on the
107
- main hub; only the text of each turn travels to the other machine.
108
+ If you use coding agents on more than one computer, make one of them (or a
109
+ small always-on box such as a Raspberry Pi) a **hub**. Every other machine
110
+ joins it and keeps an outbound connection to it, so those machines need no
111
+ open ports. The hub's single link then lists every machine with its sessions
112
+ and new-chat tiles. Only the text of each turn goes to the machine that runs
113
+ it. Speech runs on the hub, or on a faster machine that joins with `--speech`,
114
+ which is recommended when the hub is a small computer.
108
115
 
109
- Peers must be reachable from the main hub over a private network such as a
110
- VPN. On each other machine:
116
+ On the hub:
111
117
 
112
118
  ```sh
113
- MELDIVO_HOST=<vpn-ip> meldivo start # also listen on the VPN address
114
- meldivo open # prints "Also on http://<vpn-ip>:4100/#token=..."
119
+ meldivo hub enable # prints the hub link
120
+ meldivo hub code # prints a one-time code and the join command
115
121
  ```
116
122
 
117
- Then on the main hub:
123
+ On each other machine (with meldivo installed and started):
118
124
 
119
125
  ```sh
120
- meldivo peer add workstation 'http://<vpn-ip>:4100/#token=...'
126
+ meldivo join http://<hub-address>:4100 <code>
121
127
  ```
122
128
 
123
- Peer links are stored in `~/.config/meldivo/peers.json`, readable only by you.
124
- Never put a peer on a public address: the main hub's link now controls every
125
- machine it lists.
129
+ The hub address must be reachable from that machine, ideally over a private
130
+ network such as a VPN: set `MELDIVO_HOST=<vpn-ip>` when starting the hub so it
131
+ also listens there. See the [self-hosting guide](docs/self-hosting-hub.md) for
132
+ a full walkthrough, including running the hub on a Raspberry Pi.
133
+
134
+ How it stays private:
135
+
136
+ - A machine joins only with a one-time code, and gets its own credential; the
137
+ hub stores only a hash of it. `meldivo hub remove <name>` cuts a machine off
138
+ immediately.
139
+ - The hub proves its identity on every connection with a key the machine
140
+ pinned when it joined, so a machine never talks to a look-alike hub.
141
+ - The hub can only ask a machine to run or cancel a text turn in one of its
142
+ own sessions, never a command. `--allow` limits which agents it may use.
143
+ - Session lists are kept in memory on the hub, never written to disk.
126
144
 
127
145
  ## How it works
128
146
 
@@ -144,7 +162,7 @@ All settings are optional.
144
162
  | `MELDIVO_PORT` | `4100` | Port of the local server (`127.0.0.1` only). |
145
163
  | `MELDIVO_HTTPS_PORT` | `4443` | HTTPS port used by the "own certificate" remote option. |
146
164
  | `MELDIVO_PUBLIC_URL` | unset | Base URL to print when you run your own reverse proxy. |
147
- | `MELDIVO_HOST` | unset | Extra addresses to listen on besides `127.0.0.1` (comma-separated), e.g. a VPN address your reverse proxy forwards to. |
165
+ | `MELDIVO_HOST` | unset | Extra addresses to listen on besides `127.0.0.1` (comma-separated), e.g. a VPN address that joined machines or your reverse proxy connect to. |
148
166
  | `MELDIVO_MODELS_DIR` | `~/.cache/meldivo/models` | Location of the downloaded speech models. |
149
167
 
150
168
  ## Files and locations
@@ -152,7 +170,8 @@ All settings are optional.
152
170
  | Path | Contents |
153
171
  |---|---|
154
172
  | `~/.config/meldivo/secret` | The hub's shared secret, generated automatically. |
155
- | `~/.config/meldivo/peers.json` | Other machines' hubs shown in this one, with their keys. |
173
+ | `~/.config/meldivo/hub.json` | On a machine that joined a hub: the hub's address, this machine's credential, and the hub's pinned key. |
174
+ | `~/.config/meldivo/machines.json`, `hub-key.pem` | On a hub: joined machines (names and credential hashes) and the hub's signing key. |
156
175
  | `~/.cache/meldivo/models` | Downloaded speech models. |
157
176
  | `~/.local/state/meldivo` | Service logs and runtime state. |
158
177
 
@@ -162,7 +181,7 @@ The server listens on `127.0.0.1` only; it is never exposed on the network
162
181
  unless you explicitly turn on phone access. Every hub link, local or remote,
163
182
  embeds a random token, and requests without it are rejected. Treat the hub
164
183
  link like a password: anyone who has it can use every session in the hub,
165
- including the sessions of every peer machine added to it.
184
+ including the sessions of every machine that joined it.
166
185
 
167
186
  ## Uninstall
168
187
 
package/bin/meldivo.mjs CHANGED
@@ -42,8 +42,8 @@ function runtimePath() {
42
42
  return path.join(configDir(), "runtime.json");
43
43
  }
44
44
 
45
- function peersPath() {
46
- return path.join(configDir(), "peers.json");
45
+ function hubLinkPath() {
46
+ return path.join(configDir(), "hub.json");
47
47
  }
48
48
 
49
49
  function pidPath() {
@@ -171,6 +171,7 @@ function serviceEnv(port, httpsPort) {
171
171
  if (publicUrl) env.MELDIVO_PUBLIC_URL = publicUrl;
172
172
  const host = resolveHost();
173
173
  if (host) env.MELDIVO_HOST = host;
174
+ if (readRuntime().hub) env.MELDIVO_HUB = "1";
174
175
  if (process.env.MELDIVO_MODELS_DIR) env.MELDIVO_MODELS_DIR = process.env.MELDIVO_MODELS_DIR;
175
176
  env.PATH = servicePath();
176
177
  return env;
@@ -312,19 +313,19 @@ function serviceMode() {
312
313
  return "detached";
313
314
  }
314
315
 
315
- async function cmdStart(args) {
316
+ async function cmdStart(args, { quiet = false } = {}) {
316
317
  const foreground = args.includes("--foreground");
317
318
  const port = resolvePort();
318
319
  const httpsPort = resolveHttpsPort();
319
320
  const secret = ensureSecret();
320
- writeRuntime({ port, httpsPort, publicUrl: resolvePublicUrl() || undefined, host: resolveHost() || undefined });
321
+ writeRuntime({ ...readRuntime(), port, httpsPort, publicUrl: resolvePublicUrl() || undefined, host: resolveHost() || undefined });
321
322
 
322
323
  if (foreground) {
323
324
  process.env.MELDIVO_SECRET = secret;
324
325
  process.env.MELDIVO_PORT = String(port);
325
326
  process.env.MELDIVO_HTTPS_PORT = String(httpsPort);
326
327
  const { startServer } = await import(pathToFileURL(serverEntry).href);
327
- const server = await startServer({ port, host: "127.0.0.1", secret, httpsPort });
328
+ const server = await startServer({ port, host: "127.0.0.1", secret, httpsPort, hub: Boolean(readRuntime().hub), version: pkgJson.version });
328
329
  console.log(`meldivo running in the foreground on port ${server.port}`);
329
330
  await printUrl(secret);
330
331
  const shutdown = () => server.close().then(() => process.exit(0));
@@ -337,17 +338,19 @@ async function cmdStart(args) {
337
338
  const mode = serviceMode();
338
339
  if (mode === "systemd") {
339
340
  installSystemdUnit(env);
340
- console.log("Installed and started the meldivo systemd user service.");
341
- console.log("To keep it running after logout: loginctl enable-linger $USER");
341
+ if (!quiet) console.log("Installed and started the meldivo systemd user service.");
342
+ if (!quiet) console.log("To keep it running after logout: loginctl enable-linger $USER");
342
343
  } else if (mode === "launchd") {
343
344
  installLaunchAgent(env);
344
- console.log("Installed and started the meldivo LaunchAgent.");
345
+ if (!quiet) console.log("Installed and started the meldivo LaunchAgent.");
345
346
  } else {
347
+ stopDetached();
346
348
  startDetached(env);
347
- console.log(`Started meldivo as a background process (no user service manager found). Logs: ${logPath()}`);
349
+ if (!quiet) console.log(`Started meldivo as a background process (no user service manager found). Logs: ${logPath()}`);
348
350
  }
349
351
 
350
352
  await waitForHealth(port);
353
+ if (quiet) return;
351
354
  console.log("meldivo is up:");
352
355
  await printUrl(secret);
353
356
  }
@@ -379,6 +382,8 @@ async function cmdStatus() {
379
382
  try {
380
383
  const health = await waitForHealth(port, 2_000);
381
384
  console.log(`Health: ok, speech=${JSON.stringify(health.speech)}`);
385
+ if (health.hub) console.log("Hub: on (meldivo hub machines lists joined machines)");
386
+ if (health.joined) console.log(`Joined hub as "${health.joined.name}": ${health.joined.connected ? "connected" : "not connected"}`);
382
387
  } catch {
383
388
  console.log("Health: unreachable");
384
389
  }
@@ -388,59 +393,9 @@ async function cmdOpen(args) {
388
393
  const secret = ensureSecret();
389
394
  const url = hubUrl(secret);
390
395
  await printUrl(secret).then(() => {}).catch(() => {});
391
- // Extra private addresses (MELDIVO_HOST) are what another hub uses with `meldivo peer add`.
392
- for (const host of resolveHost().split(",").map((value) => value.trim()).filter((value) => value && value !== "127.0.0.1")) {
393
- console.log(`Also on http://${host.includes(":") ? `[${host}]` : host}:${resolvePort()}/#token=${encodeURIComponent(secret)}`);
394
- }
395
396
  if (args.includes("--browser")) openInBrowser(url);
396
397
  }
397
398
 
398
- function readPeers() {
399
- try {
400
- const peers = JSON.parse(readFileSync(peersPath(), "utf8"));
401
- return Array.isArray(peers) ? peers : [];
402
- } catch {
403
- return [];
404
- }
405
- }
406
-
407
- function writePeers(peers) {
408
- ensureDir(configDir(), 0o700);
409
- writePrivate(peersPath(), JSON.stringify(peers, null, 2));
410
- }
411
-
412
- // Peers are other machines' hubs shown in this one. The hub rereads the file, so no restart is needed.
413
- function cmdPeer(args) {
414
- const [sub, name, link] = args;
415
- if (!sub || sub === "list") {
416
- const peers = readPeers();
417
- if (peers.length === 0) console.log("No peers. Add one with: meldivo peer add <name> <link>");
418
- for (const peer of peers) console.log(`${peer.name}\t${peer.url}`);
419
- return;
420
- }
421
- if (sub === "remove" && name) {
422
- const peers = readPeers();
423
- const remaining = peers.filter((peer) => peer.name !== name);
424
- if (remaining.length === peers.length) throw new Error(`No peer named "${name}"`);
425
- writePeers(remaining);
426
- console.log(`Removed ${name}.`);
427
- return;
428
- }
429
- if (sub === "add" && name && link) {
430
- if (!/^[A-Za-z0-9._-]{1,40}$/.test(name)) throw new Error("Peer names may use letters, digits, dot, dash, and underscore");
431
- const parsed = new URL(link);
432
- const token = decodeURIComponent(/(?:^#|&)token=([^&]+)/.exec(parsed.hash)?.[1] ?? "");
433
- if (!token) throw new Error("The link must end in #token=<key> (run `meldivo open` on that machine)");
434
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("The link must be http(s)");
435
- const peers = readPeers().filter((peer) => peer.name !== name);
436
- peers.push({ name, url: parsed.origin, token });
437
- writePeers(peers);
438
- console.log(`Added ${name} (${parsed.origin}).`);
439
- return;
440
- }
441
- throw new Error("Usage: meldivo peer [list] | add <name> <link> | remove <name>");
442
- }
443
-
444
399
  function openInBrowser(url) {
445
400
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
446
401
  try {
@@ -489,6 +444,90 @@ async function cmdRemote(args) {
489
444
  for (const alt of result.alternatives ?? []) console.log(`Also reachable at: ${alt}`);
490
445
  }
491
446
 
447
+ // Addresses other machines can use to reach this hub: MELDIVO_HOST addresses, then the public URL.
448
+ function hubAddresses() {
449
+ const port = resolvePort();
450
+ const addresses = resolveHost().split(",").map((value) => value.trim()).filter((value) => value && value !== "127.0.0.1")
451
+ .map((host) => `http://${host.includes(":") ? `[${host}]` : host}:${port}`);
452
+ if (resolvePublicUrl()) addresses.push(resolvePublicUrl());
453
+ return addresses.length ? addresses : [baseUrl()];
454
+ }
455
+
456
+ async function cmdHub(args) {
457
+ const [sub, name] = args;
458
+ const secret = ensureSecret();
459
+ if (sub === "enable" || sub === "disable") {
460
+ writeRuntime({ ...readRuntime(), hub: sub === "enable" || undefined });
461
+ await cmdStart([], { quiet: true });
462
+ if (sub === "disable") {
463
+ console.log("Hub mode is off. Machines that joined this hub keep trying to reconnect until you run `meldivo leave` on them.");
464
+ return;
465
+ }
466
+ console.log("This machine is now a hub. Open it with:");
467
+ await printUrl(secret);
468
+ console.log("To add a machine, run `meldivo hub code` here and follow the instructions it prints.");
469
+ return;
470
+ }
471
+ if (!readRuntime().hub) throw new Error("This machine is not a hub. Turn hub mode on with: meldivo hub enable");
472
+ if (sub === "code") {
473
+ const { code, expiresAt } = await apiCall("/api/hub/codes", "POST", secret);
474
+ const minutes = Math.round((expiresAt - Date.now()) / 60_000);
475
+ console.log(`One-time code (valid ${minutes} minutes, single use): ${code}`);
476
+ console.log("\nOn the machine you want to add, run:");
477
+ for (const address of hubAddresses()) console.log(` meldivo join ${address} ${code}`);
478
+ console.log("\nUse an address that machine can reach privately, such as a VPN address (see MELDIVO_HOST).");
479
+ return;
480
+ }
481
+ if (!sub || sub === "machines") {
482
+ const { machines } = await apiCall("/api/hub/machines", "GET", secret);
483
+ if (machines.length === 0) console.log("No machines yet. Add one with: meldivo hub code");
484
+ for (const machine of machines) {
485
+ console.log(`${machine.name}\t${machine.online ? "online" : "offline"}${machine.version ? `\t${machine.version}` : ""}\tjoined ${new Date(machine.joinedAt).toISOString().slice(0, 10)}`);
486
+ }
487
+ return;
488
+ }
489
+ if (sub === "remove" && name) {
490
+ await apiCall(`/api/hub/machines/${encodeURIComponent(name)}`, "DELETE", secret);
491
+ console.log(`Removed ${name}. It can no longer connect; run \`meldivo leave\` on it to stop it trying.`);
492
+ return;
493
+ }
494
+ throw new Error("Usage: meldivo hub enable | disable | code | machines | remove <name>");
495
+ }
496
+
497
+ function optionValue(args, flag) {
498
+ const index = args.indexOf(flag);
499
+ return index >= 0 ? args[index + 1] : undefined;
500
+ }
501
+
502
+ async function cmdJoin(args) {
503
+ const positional = args.filter((arg, index) => !arg.startsWith("--") && !(index > 0 && args[index - 1].startsWith("--")));
504
+ const [hubAddress, code] = positional;
505
+ if (!hubAddress || !code) throw new Error("Usage: meldivo join <hub-address> <code> [--name <name>] [--allow pi,opencode,claude] [--speech]");
506
+ const requestedName = optionValue(args, "--name") ?? os.hostname().split(".")[0].replace(/[^A-Za-z0-9._-]/g, "-").slice(0, 40);
507
+ const allow = optionValue(args, "--allow")?.split(",").map((id) => id.trim()).filter(Boolean);
508
+ const url = new URL(hubAddress);
509
+ if (url.protocol === "http:" && !/^(127\.|localhost$|\[::1\]$)/.test(url.hostname)) {
510
+ console.log("Note: this hub address is plain http. That is fine on a private VPN; over any other network use https.");
511
+ }
512
+ const { joinHub } = await import(pathToFileURL(path.join(pkgRoot, "dist", "server", "machine-client.js")).href);
513
+ const link = await joinHub(hubAddress, code, requestedName);
514
+ ensureDir(configDir(), 0o700);
515
+ const speech = args.includes("--speech") || undefined;
516
+ writePrivate(hubLinkPath(), JSON.stringify({ ...link, ...(allow?.length ? { allow } : {}), ...(speech ? { speech } : {}) }, null, 2));
517
+ await cmdStart([], { quiet: true });
518
+ console.log(`Joined the hub as "${link.name}". This machine's sessions now appear in the hub.`);
519
+ }
520
+
521
+ async function cmdLeave() {
522
+ if (!existsSync(hubLinkPath())) {
523
+ console.log("This machine has not joined a hub.");
524
+ return;
525
+ }
526
+ rmSync(hubLinkPath(), { force: true });
527
+ await cmdStart([], { quiet: true });
528
+ console.log("Left the hub. Also remove this machine on the hub with: meldivo hub remove <name>");
529
+ }
530
+
492
531
  async function cmdUninstall(args) {
493
532
  await cmdStop();
494
533
  const mode = serviceMode();
@@ -524,14 +563,20 @@ function printHelp() {
524
563
  Usage: meldivo <command> [options]
525
564
 
526
565
  Commands:
527
- start [--foreground] Start the meldivo hub as a user service
566
+ start [--foreground] Start meldivo as a user service
528
567
  stop Stop and disable the service
529
568
  status Show health, speech, and service state
530
569
  open [--browser] Print the hub URL and QR (optionally open it)
531
570
  remote [tailscale|cloudflare|certificate|stop]
532
571
  Manage remote access
533
- peer [list|add <name> <link>|remove <name>]
534
- Show other machines' hubs in this one (link from their \`meldivo open\`)
572
+ hub enable|disable Make this machine a hub that other machines join (or stop)
573
+ hub code Print a one-time code for adding a machine to this hub
574
+ hub machines List the machines that joined this hub
575
+ hub remove <name> Remove a machine from this hub
576
+ join <hub-address> <code> [--name <name>] [--allow pi,opencode,claude] [--speech]
577
+ Join a hub: this machine's sessions appear there
578
+ (--speech: also do speech for the hub)
579
+ leave Leave the hub this machine joined
535
580
  uninstall [--purge] Stop and remove the service (optionally wipe config/cache/state)
536
581
  logs Tail service logs
537
582
  --version Print the version
@@ -558,8 +603,14 @@ async function main() {
558
603
  case "remote":
559
604
  await cmdRemote(rest);
560
605
  break;
561
- case "peer":
562
- cmdPeer(rest);
606
+ case "hub":
607
+ await cmdHub(rest);
608
+ break;
609
+ case "join":
610
+ await cmdJoin(rest);
611
+ break;
612
+ case "leave":
613
+ await cmdLeave();
563
614
  break;
564
615
  case "uninstall":
565
616
  await cmdUninstall(rest);
@@ -39,7 +39,7 @@ export function createAccessGate(secret) {
39
39
  return { middleware, unlock, isAuthorized };
40
40
  }
41
41
  // The same bare 404 for every unauthenticated request, page or API, right key path or not.
42
- function notFound(req, res) {
42
+ export function notFound(req, res) {
43
43
  res.removeHeader("X-Request-Id");
44
44
  res.status(404).set({ "Cache-Control": "no-store", "Content-Type": "text/html" });
45
45
  res.end(req.method === "HEAD" ? undefined : NOT_FOUND_PAGE);
@@ -1 +1 @@
1
- {"version":3,"file":"access.js","sourceRoot":"","sources":["../../server/src/access.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../../server/src/access.ts"],"names":[],"mappings":"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"}