pinomad 0.5.0 → 0.7.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.
Files changed (31) hide show
  1. package/README.md +2 -2
  2. package/dist/{chunk-f0v3sht0.js → chunk-07769pqx.js} +10 -8
  3. package/dist/{chunk-ebfaf3k2.js → chunk-0xh6cy9v.js} +1 -1
  4. package/dist/{chunk-aqj4wg33.js → chunk-12kaxggg.js} +29 -12
  5. package/dist/{chunk-d4wdt5qs.js → chunk-1nyzr0mg.js} +2282 -1027
  6. package/dist/chunk-1t58fh0k.js +16 -0
  7. package/dist/{chunk-4by4x5c4.js → chunk-6ysezfy5.js} +44 -14
  8. package/dist/{chunk-kmbh44dt.js → chunk-7qb9tq54.js} +42 -6
  9. package/dist/{chunk-gqr7ahv4.js → chunk-8yme2wep.js} +2 -2
  10. package/dist/chunk-b1h374jr.js +159 -0
  11. package/dist/{chunk-hsp12cjt.js → chunk-e4ahjbmz.js} +212 -50
  12. package/dist/{chunk-9d59jjmt.js → chunk-fbkd73zr.js} +36 -10
  13. package/dist/chunk-kzbzacz9.js +12 -0
  14. package/dist/{chunk-zttf1hvh.js → chunk-m4c5gvce.js} +4 -3
  15. package/dist/{chunk-cjfmfyjb.js → chunk-ngf1zatm.js} +7 -6
  16. package/dist/{chunk-1d9sppj0.js → chunk-rtwxjb90.js} +1 -1
  17. package/dist/{chunk-m4q9wafw.js → chunk-sj7rnvh4.js} +118 -6
  18. package/dist/chunk-sz3rzk55.js +79 -0
  19. package/dist/{chunk-26d04z02.js → chunk-ywmm63ks.js} +7 -3
  20. package/dist/chunk-znhn8af7.js +33 -0
  21. package/dist/pinomad.js +36 -12
  22. package/package.json +1 -1
  23. package/web/assets/index-C0rwAo0H.css +1 -0
  24. package/web/assets/index-DGee2kNU.js +394 -0
  25. package/web/index.html +2 -2
  26. package/dist/chunk-5ng86fmy.js +0 -14
  27. package/dist/chunk-crv3dqzp.js +0 -63
  28. package/web/assets/index-BkF0-im5.css +0 -1
  29. package/web/assets/index-D4lgm3Y4.js +0 -383
  30. package/web/assets/montserrat-latin-ext-wght-normal-BsZE-iaG.woff2 +0 -0
  31. package/web/assets/montserrat-latin-wght-normal-l_AIctKy.woff2 +0 -0
package/README.md CHANGED
@@ -35,7 +35,7 @@ pinomad host --remote-port 7422
35
35
  pinomad pair # one-time QR code and link, expires after 5 minutes
36
36
  ```
37
37
 
38
- Scan the code with the iPhone app, or paste the link into the Mac app. The remote port accepts paired devices only; revoke them under Devices in the sidebar.
38
+ Scan the code with the iPhone app, or paste the link into the Mac app. The remote port accepts paired devices only; revoke them under Settings → Devices.
39
39
 
40
40
  The pairing link uses the LAN address the host detects. On a tailnet or behind a tunnel, add `--public-url http://<tailnet-ip>:7422` so the link points there. To reach a host at home from anywhere, run the relay on a VPS: see [Remote access](docs/remote-access.md).
41
41
 
@@ -74,7 +74,7 @@ The agent has pi's four tools (read, bash, edit, write) plus:
74
74
  | codemode | The model writes JavaScript that calls other tools in a QuickJS sandbox; only the script's output enters the context |
75
75
  | MCP | Servers configured in `~/.agents/mcp.json`, in the usual `mcpServers` format |
76
76
  | Images | Paste, drop, or pick up to 4 images per message in the Web/desktop composer — resized to JPEG before sending |
77
- | AGENTS.md and skills | Reads `AGENTS.md` / `CLAUDE.md` and skills from `~/.agents` and the project, on every request |
77
+ | AGENTS.md and skills | Reads `AGENTS.md` / `CLAUDE.md` and skills from `~/.agents` and the project, on every request; a `$name` mention sends that skill's full text with the message |
78
78
 
79
79
  Details and the MCP config reference: [Usage](docs/usage.md).
80
80
 
@@ -3,28 +3,30 @@ import {
3
3
  assertSecureServerOrigin,
4
4
  probeServerAccounts,
5
5
  runServerOperation
6
- } from "./chunk-26d04z02.js";
6
+ } from "./chunk-ywmm63ks.js";
7
7
  import {
8
8
  loadHostKey,
9
9
  loadRelayKey,
10
10
  readServerConfig,
11
11
  removeServerConfig
12
- } from "./chunk-ebfaf3k2.js";
12
+ } from "./chunk-0xh6cy9v.js";
13
13
  import {
14
14
  relayHostId
15
- } from "./chunk-kmbh44dt.js";
15
+ } from "./chunk-7qb9tq54.js";
16
16
  import {
17
17
  argValue,
18
18
  restartService,
19
19
  serviceManager,
20
20
  withoutRelayArgs
21
- } from "./chunk-aqj4wg33.js";
22
- import"./chunk-1d9sppj0.js";
23
- import"./chunk-m4q9wafw.js";
24
- import"./chunk-hsp12cjt.js";
21
+ } from "./chunk-12kaxggg.js";
22
+ import"./chunk-kzbzacz9.js";
23
+ import"./chunk-rtwxjb90.js";
24
+ import"./chunk-sj7rnvh4.js";
25
+ import"./chunk-e4ahjbmz.js";
26
+ import"./chunk-znhn8af7.js";
25
27
  import {
26
28
  DEFAULT_DATA_DIR
27
- } from "./chunk-cjfmfyjb.js";
29
+ } from "./chunk-ngf1zatm.js";
28
30
  import"./chunk-df32avw6.js";
29
31
 
30
32
  // apps/host/src/cli/leave.ts
@@ -3,7 +3,7 @@ import {
3
3
  generateKeyPair,
4
4
  keyPairFromPrivate,
5
5
  toBase64Url
6
- } from "./chunk-kmbh44dt.js";
6
+ } from "./chunk-7qb9tq54.js";
7
7
 
8
8
  // apps/host/src/devices.ts
9
9
  import { link, readFile, unlink, writeFile } from "node:fs/promises";
@@ -1,15 +1,19 @@
1
+ import {
2
+ isParseArgsError
3
+ } from "./chunk-kzbzacz9.js";
1
4
  import {
2
5
  commandHint,
3
6
  hostEntry,
4
7
  packagedVersion
5
- } from "./chunk-1d9sppj0.js";
8
+ } from "./chunk-rtwxjb90.js";
6
9
  import {
10
+ ProtocolMismatchError,
7
11
  connectRemoteDurable
8
- } from "./chunk-m4q9wafw.js";
12
+ } from "./chunk-sj7rnvh4.js";
9
13
  import {
10
14
  DEFAULT_DATA_DIR,
11
15
  hostAddress
12
- } from "./chunk-cjfmfyjb.js";
16
+ } from "./chunk-ngf1zatm.js";
13
17
 
14
18
  // apps/host/src/cli/service.ts
15
19
  import { execFile as execFile2 } from "node:child_process";
@@ -375,7 +379,7 @@ function serviceManager(platform = process.platform) {
375
379
  var run2 = promisify2(execFile2);
376
380
  var repoRoot = fileURLToPath(new URL("../../../../", import.meta.url));
377
381
  var message = (error) => error instanceof Error ? error.message : String(error);
378
- function connect(url, token, timeoutMs = 3000) {
382
+ function connectToHost(url, token, timeoutMs = 3000) {
379
383
  const connecting = connectRemoteDurable({ url, token, reconnectDelayMs: { min: 200, max: 2000 } });
380
384
  const timedOut = Symbol("timedOut");
381
385
  return Promise.race([
@@ -416,7 +420,7 @@ async function status(argv) {
416
420
  }
417
421
  try {
418
422
  const { url, token } = await hostAddress(argv);
419
- const remote = await connect(url, token);
423
+ const remote = await connectToHost(url, token);
420
424
  if (remote.view.current().tasks === undefined)
421
425
  await remote.controller.toggleTasks();
422
426
  const tasks = remote.view.current().tasks;
@@ -424,6 +428,8 @@ async function status(argv) {
424
428
  console.log(`host: reachable at ${url}, ${count} live task${count === 1 ? "" : "s"}`);
425
429
  remote.close();
426
430
  } catch (error) {
431
+ if (isParseArgsError(error))
432
+ throw error;
427
433
  console.log(`host: unreachable (${message(error)})`);
428
434
  }
429
435
  }
@@ -431,13 +437,18 @@ async function restartService({
431
437
  force,
432
438
  argv,
433
439
  manager = serviceManager(),
434
- restart
440
+ restart,
441
+ connect = connectToHost,
442
+ pollTimeoutMs = 30000,
443
+ pollDelayMs = 500
435
444
  }) {
436
445
  if (!(await manager.state()).installed) {
437
446
  console.log(`service not installed (${commandHint("service")} install)`);
438
447
  return 1;
439
448
  }
440
- const address = await hostAddress(argv).catch(() => {
449
+ const address = await hostAddress(argv).catch((error) => {
450
+ if (isParseArgsError(error))
451
+ throw error;
441
452
  return;
442
453
  });
443
454
  if (!force && address !== undefined) {
@@ -457,7 +468,7 @@ async function restartService({
457
468
  console.log("restart requested (host address unknown; not polling)");
458
469
  return 0;
459
470
  }
460
- const deadline = Date.now() + 30000;
471
+ const deadline = Date.now() + pollTimeoutMs;
461
472
  for (;; ) {
462
473
  try {
463
474
  const remote = await connect(address.url, address.token, 2000);
@@ -465,11 +476,16 @@ async function restartService({
465
476
  console.log(`host restarted, reachable at ${address.url}`);
466
477
  return 0;
467
478
  } catch (error) {
479
+ if (error instanceof ProtocolMismatchError && error.direction === "client-older") {
480
+ const newer = error.hostVersion ?? `protocol major ${error.hostMajor}`;
481
+ console.log(`host restarted (${newer}, newer than this upgrader), reachable at ${address.url}`);
482
+ return 0;
483
+ }
468
484
  if (Date.now() > deadline) {
469
- console.error(`host did not answer within 30s after restart: ${message(error)}`);
485
+ console.error(`host did not answer within ${pollTimeoutMs / 1000}s after restart: ${message(error)}`);
470
486
  return 1;
471
487
  }
472
- await new Promise((resolve3) => setTimeout(resolve3, 500));
488
+ await new Promise((resolve3) => setTimeout(resolve3, pollDelayMs));
473
489
  }
474
490
  }
475
491
  }
@@ -512,11 +528,12 @@ async function main(argv) {
512
528
  process.exitCode = 1;
513
529
  }
514
530
  } catch (error) {
531
+ if (isParseArgsError(error))
532
+ throw error;
515
533
  console.error(message(error));
516
534
  process.exitCode = 1;
517
535
  }
518
536
  }
519
- if (false)
520
- ;
537
+ if (false) {}
521
538
 
522
539
  export { installSpec, argValue, withoutRelayArgs, serviceManager, restartService, main };