@yefengr/remote-pi 0.7.4 → 0.7.6

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 (165) hide show
  1. package/README.md +81 -586
  2. package/dist/bin/supervisord.js +4 -5
  3. package/dist/bin/supervisord.js.map +1 -1
  4. package/dist/config.d.ts +1 -1
  5. package/dist/config.js +2 -2
  6. package/dist/daemon/cli-links.d.ts +30 -0
  7. package/dist/daemon/cli-links.js +134 -0
  8. package/dist/daemon/cli-links.js.map +1 -0
  9. package/dist/daemon/commands.d.ts +27 -0
  10. package/dist/daemon/commands.js +295 -0
  11. package/dist/daemon/commands.js.map +1 -0
  12. package/dist/daemon/control_protocol.d.ts +53 -31
  13. package/dist/daemon/control_protocol.js +8 -31
  14. package/dist/daemon/control_protocol.js.map +1 -1
  15. package/dist/daemon/cron_log.d.ts +2 -23
  16. package/dist/daemon/cron_log.js +10 -25
  17. package/dist/daemon/cron_log.js.map +1 -1
  18. package/dist/daemon/cron_registry.d.ts +3 -40
  19. package/dist/daemon/cron_registry.js +58 -103
  20. package/dist/daemon/cron_registry.js.map +1 -1
  21. package/dist/daemon/install-runtime.d.ts +10 -0
  22. package/dist/daemon/install-runtime.js +81 -0
  23. package/dist/daemon/install-runtime.js.map +1 -0
  24. package/dist/daemon/install.d.ts +3 -63
  25. package/dist/daemon/install.js +5 -289
  26. package/dist/daemon/install.js.map +1 -1
  27. package/dist/daemon/preflight.d.ts +51 -0
  28. package/dist/daemon/preflight.js +136 -0
  29. package/dist/daemon/preflight.js.map +1 -0
  30. package/dist/daemon/registry.d.ts +33 -45
  31. package/dist/daemon/registry.js +171 -117
  32. package/dist/daemon/registry.js.map +1 -1
  33. package/dist/daemon/rpc_child.d.ts +92 -146
  34. package/dist/daemon/rpc_child.js +336 -263
  35. package/dist/daemon/rpc_child.js.map +1 -1
  36. package/dist/daemon/status.d.ts +45 -0
  37. package/dist/daemon/status.js +87 -0
  38. package/dist/daemon/status.js.map +1 -0
  39. package/dist/daemon/supervisor-ipc.d.ts +2 -0
  40. package/dist/daemon/supervisor-ipc.js +20 -0
  41. package/dist/daemon/supervisor-ipc.js.map +1 -0
  42. package/dist/daemon/supervisor.d.ts +48 -71
  43. package/dist/daemon/supervisor.js +430 -420
  44. package/dist/daemon/supervisor.js.map +1 -1
  45. package/dist/extension_ui_bridge.d.ts +4 -3
  46. package/dist/extension_ui_bridge.js +10 -0
  47. package/dist/extension_ui_bridge.js.map +1 -1
  48. package/dist/index.d.ts +25 -230
  49. package/dist/index.js +515 -5553
  50. package/dist/index.js.map +1 -1
  51. package/dist/pairing/crypto.d.ts +8 -1
  52. package/dist/pairing/crypto.js +56 -6
  53. package/dist/pairing/crypto.js.map +1 -1
  54. package/dist/pairing/owner_storage.d.ts +42 -0
  55. package/dist/pairing/owner_storage.js +207 -0
  56. package/dist/pairing/owner_storage.js.map +1 -0
  57. package/dist/pairing/qr.d.ts +3 -42
  58. package/dist/pairing/qr.js +9 -59
  59. package/dist/pairing/qr.js.map +1 -1
  60. package/dist/pairing/storage.d.ts +3 -45
  61. package/dist/pairing/storage.js +10 -223
  62. package/dist/pairing/storage.js.map +1 -1
  63. package/dist/protocol/types.d.ts +1 -1
  64. package/dist/protocol/v2/schemas.d.ts +1 -1
  65. package/dist/protocol/v2/schemas.js +1 -1
  66. package/dist/protocol/v2/schemas.js.map +1 -1
  67. package/dist/runtime/owner_router.d.ts +16 -0
  68. package/dist/runtime/owner_router.js +37 -0
  69. package/dist/runtime/owner_router.js.map +1 -0
  70. package/dist/session/ipc.d.ts +1 -22
  71. package/dist/session/ipc.js +4 -11
  72. package/dist/session/ipc.js.map +1 -1
  73. package/dist/session/local_config.d.ts +4 -47
  74. package/dist/session/local_config.js +19 -101
  75. package/dist/session/local_config.js.map +1 -1
  76. package/dist/transport/peer_channel.d.ts +25 -39
  77. package/dist/transport/peer_channel.js +74 -131
  78. package/dist/transport/peer_channel.js.map +1 -1
  79. package/dist/transport/relay_client.d.ts +26 -70
  80. package/dist/transport/relay_client.js +37 -106
  81. package/dist/transport/relay_client.js.map +1 -1
  82. package/docs/daemon.md +91 -207
  83. package/package.json +21 -17
  84. package/dist/daemon/id.d.ts +0 -24
  85. package/dist/daemon/id.js +0 -36
  86. package/dist/daemon/id.js.map +0 -1
  87. package/dist/mcp/mesh_result.d.ts +0 -10
  88. package/dist/mcp/mesh_result.js +0 -42
  89. package/dist/mcp/mesh_result.js.map +0 -1
  90. package/dist/mcp/mesh_server.d.ts +0 -16
  91. package/dist/mcp/mesh_server.js +0 -327
  92. package/dist/mcp/mesh_server.js.map +0 -1
  93. package/dist/mesh/canonical.d.ts +0 -30
  94. package/dist/mesh/canonical.js +0 -61
  95. package/dist/mesh/canonical.js.map +0 -1
  96. package/dist/mesh/client.d.ts +0 -18
  97. package/dist/mesh/client.js +0 -125
  98. package/dist/mesh/client.js.map +0 -1
  99. package/dist/mesh/encoding.d.ts +0 -38
  100. package/dist/mesh/encoding.js +0 -216
  101. package/dist/mesh/encoding.js.map +0 -1
  102. package/dist/mesh/self_revoke.d.ts +0 -73
  103. package/dist/mesh/self_revoke.js +0 -401
  104. package/dist/mesh/self_revoke.js.map +0 -1
  105. package/dist/mesh/siblings.d.ts +0 -49
  106. package/dist/mesh/siblings.js +0 -159
  107. package/dist/mesh/siblings.js.map +0 -1
  108. package/dist/mesh/types.d.ts +0 -34
  109. package/dist/mesh/types.js +0 -11
  110. package/dist/mesh/types.js.map +0 -1
  111. package/dist/mesh/verify.d.ts +0 -17
  112. package/dist/mesh/verify.js +0 -86
  113. package/dist/mesh/verify.js.map +0 -1
  114. package/dist/rooms.d.ts +0 -29
  115. package/dist/rooms.js +0 -57
  116. package/dist/rooms.js.map +0 -1
  117. package/dist/session/bridge.d.ts +0 -37
  118. package/dist/session/bridge.js +0 -130
  119. package/dist/session/bridge.js.map +0 -1
  120. package/dist/session/broker.d.ts +0 -189
  121. package/dist/session/broker.js +0 -507
  122. package/dist/session/broker.js.map +0 -1
  123. package/dist/session/broker_remote.d.ts +0 -74
  124. package/dist/session/broker_remote.js +0 -583
  125. package/dist/session/broker_remote.js.map +0 -1
  126. package/dist/session/cwd_lock.d.ts +0 -33
  127. package/dist/session/cwd_lock.js +0 -126
  128. package/dist/session/cwd_lock.js.map +0 -1
  129. package/dist/session/envelope.d.ts +0 -33
  130. package/dist/session/envelope.js +0 -117
  131. package/dist/session/envelope.js.map +0 -1
  132. package/dist/session/global_config.d.ts +0 -33
  133. package/dist/session/global_config.js +0 -73
  134. package/dist/session/global_config.js.map +0 -1
  135. package/dist/session/leader_election.d.ts +0 -32
  136. package/dist/session/leader_election.js +0 -106
  137. package/dist/session/leader_election.js.map +0 -1
  138. package/dist/session/mesh_node.d.ts +0 -116
  139. package/dist/session/mesh_node.js +0 -573
  140. package/dist/session/mesh_node.js.map +0 -1
  141. package/dist/session/peer.d.ts +0 -139
  142. package/dist/session/peer.js +0 -451
  143. package/dist/session/peer.js.map +0 -1
  144. package/dist/session/peer_inventory.d.ts +0 -13
  145. package/dist/session/peer_inventory.js +0 -48
  146. package/dist/session/peer_inventory.js.map +0 -1
  147. package/dist/session/peer_limits.d.ts +0 -9
  148. package/dist/session/peer_limits.js +0 -21
  149. package/dist/session/peer_limits.js.map +0 -1
  150. package/dist/session/setup_wizard.d.ts +0 -39
  151. package/dist/session/setup_wizard.js +0 -63
  152. package/dist/session/setup_wizard.js.map +0 -1
  153. package/dist/session/tools.d.ts +0 -24
  154. package/dist/session/tools.js +0 -252
  155. package/dist/session/tools.js.map +0 -1
  156. package/dist/session/wizard.d.ts +0 -13
  157. package/dist/session/wizard.js +0 -20
  158. package/dist/session/wizard.js.map +0 -1
  159. package/dist/transport/pi_forward_client.d.ts +0 -29
  160. package/dist/transport/pi_forward_client.js +0 -62
  161. package/dist/transport/pi_forward_client.js.map +0 -1
  162. package/dist/ui/footer.d.ts +0 -32
  163. package/dist/ui/footer.js +0 -34
  164. package/dist/ui/footer.js.map +0 -1
  165. package/skills/agent-network/SKILL.md +0 -310
@@ -1,34 +0,0 @@
1
- /**
2
- * Mesh-membership types — pi-extension side. Mirrors the wire shape defined
3
- * in plan/24-mesh-membership.md and must stay bit-compatible with the Dart
4
- * (app) and Rust (relay) implementations of the same protocol.
5
- *
6
- * On the wire, JSON field names are `snake_case` (per the plan); this module
7
- * exposes `camelCase` for ergonomic TS use. Conversion happens at the
8
- * (de)serialization boundary in `verify.ts` / `canonical.ts`.
9
- */
10
- export interface MeshMember {
11
- /** Pi Ed25519 pubkey, canonical RFC 4648 standard base64 with padding. */
12
- remoteEpk: string;
13
- /** Relay URL where this member registers. */
14
- relayUrl: string;
15
- /** ISO-8601 timestamp of when the pairing happened. */
16
- pairedAt: string;
17
- /** Optional Owner-set label. */
18
- nickname?: string;
19
- }
20
- export interface MeshHeader {
21
- /** Owner-scoped monotonic counter. Higher = newer. */
22
- version: number;
23
- /** Issued-at, ms since epoch. */
24
- issuedAt: number;
25
- /** Owner's Ed25519 pubkey, raw 32 bytes. */
26
- ownerPk: Uint8Array;
27
- members: MeshMember[];
28
- }
29
- export interface MeshEnvelope {
30
- /** Canonical JSON bytes of the header (snake_case keys, sorted, no whitespace). */
31
- blob: Uint8Array;
32
- /** Ed25519 signature of `blob`, 64 bytes. */
33
- sig: Uint8Array;
34
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Mesh-membership types — pi-extension side. Mirrors the wire shape defined
3
- * in plan/24-mesh-membership.md and must stay bit-compatible with the Dart
4
- * (app) and Rust (relay) implementations of the same protocol.
5
- *
6
- * On the wire, JSON field names are `snake_case` (per the plan); this module
7
- * exposes `camelCase` for ergonomic TS use. Conversion happens at the
8
- * (de)serialization boundary in `verify.ts` / `canonical.ts`.
9
- */
10
- export {};
11
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/mesh/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -1,17 +0,0 @@
1
- import type { MeshEnvelope, MeshHeader } from "./types.js";
2
- /**
3
- * Verifies the Ed25519 signature on a mesh envelope and decodes the blob
4
- * into a typed `MeshHeader`.
5
- *
6
- * The verification key is extracted *from the blob* (`owner_pk` field) —
7
- * the caller MUST then check that `sha256(header.ownerPk)` matches the
8
- * URL hash they queried with. Otherwise a malicious relay could serve a
9
- * valid-but-different-owner blob at our hash slot.
10
- *
11
- * Throws on:
12
- * - JSON parse failure
13
- * - Missing or wrong-type required fields
14
- * - `owner_pk` not 32 bytes
15
- * - Signature mismatch
16
- */
17
- export declare function verifyEnvelope(env: MeshEnvelope): Promise<MeshHeader>;
@@ -1,86 +0,0 @@
1
- import { ed25519Verify } from "../pairing/crypto.js";
2
- import { canonicalizeEd25519PublicKey, decodeEd25519PublicKey, } from "./encoding.js";
3
- /**
4
- * Verifies the Ed25519 signature on a mesh envelope and decodes the blob
5
- * into a typed `MeshHeader`.
6
- *
7
- * The verification key is extracted *from the blob* (`owner_pk` field) —
8
- * the caller MUST then check that `sha256(header.ownerPk)` matches the
9
- * URL hash they queried with. Otherwise a malicious relay could serve a
10
- * valid-but-different-owner blob at our hash slot.
11
- *
12
- * Throws on:
13
- * - JSON parse failure
14
- * - Missing or wrong-type required fields
15
- * - `owner_pk` not 32 bytes
16
- * - Signature mismatch
17
- */
18
- export async function verifyEnvelope(env) {
19
- let parsed;
20
- try {
21
- parsed = JSON.parse(new TextDecoder().decode(env.blob));
22
- }
23
- catch {
24
- throw new Error("mesh: blob is not valid JSON");
25
- }
26
- if (!parsed || typeof parsed !== "object") {
27
- throw new Error("mesh: blob is not a JSON object");
28
- }
29
- const o = parsed;
30
- if (typeof o["owner_pk"] !== "string") {
31
- throw new Error("mesh: owner_pk missing or not a string");
32
- }
33
- if (typeof o["version"] !== "number" || !Number.isInteger(o["version"])) {
34
- throw new Error("mesh: version missing or not an integer");
35
- }
36
- if (typeof o["issued_at"] !== "number" || !Number.isInteger(o["issued_at"])) {
37
- throw new Error("mesh: issued_at missing or not an integer");
38
- }
39
- if (!Array.isArray(o["members"])) {
40
- throw new Error("mesh: members missing or not an array");
41
- }
42
- const rawMembers = o["members"].map((raw, index) => {
43
- if (!raw || typeof raw !== "object") {
44
- throw new Error(`mesh: members[${index}] is not an object`);
45
- }
46
- const member = raw;
47
- if (typeof member["remote_epk"] !== "string") {
48
- throw new Error(`mesh: members[${index}].remote_epk invalid`);
49
- }
50
- if (typeof member["relay_url"] !== "string") {
51
- throw new Error(`mesh: members[${index}].relay_url invalid`);
52
- }
53
- if (typeof member["paired_at"] !== "string") {
54
- throw new Error(`mesh: members[${index}].paired_at invalid`);
55
- }
56
- const nickname = member["nickname"];
57
- if (nickname !== undefined &&
58
- nickname !== null &&
59
- typeof nickname !== "string") {
60
- throw new Error(`mesh: members[${index}].nickname invalid`);
61
- }
62
- return {
63
- remoteEpk: member["remote_epk"],
64
- relayUrl: member["relay_url"],
65
- pairedAt: member["paired_at"],
66
- ...(typeof nickname === "string" ? { nickname } : {}),
67
- };
68
- });
69
- const ownerPk = decodeEd25519PublicKey(o["owner_pk"], "owner_pk");
70
- if (!ed25519Verify(ownerPk, env.blob, env.sig)) {
71
- throw new Error("mesh: signature verification failed");
72
- }
73
- const members = rawMembers.map((member, index) => ({
74
- remoteEpk: canonicalizeEd25519PublicKey(member.remoteEpk, `members[${index}].remote_epk`),
75
- relayUrl: member.relayUrl,
76
- pairedAt: member.pairedAt,
77
- ...(member.nickname !== undefined ? { nickname: member.nickname } : {}),
78
- }));
79
- return {
80
- version: o["version"],
81
- issuedAt: o["issued_at"],
82
- ownerPk,
83
- members,
84
- };
85
- }
86
- //# sourceMappingURL=verify.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/mesh/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAUvB;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAiB;IACpD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,MAAM,CAAC,GAAG,MAAiC,CAAC;IAE5C,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,CAAC,CAAC,WAAW,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,UAAU,GAAqB,CAAC,CAAC,SAAS,CAAe,CAAC,GAAG,CACjE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACb,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,oBAAoB,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,MAAM,GAAG,GAA8B,CAAC;QAC9C,IAAI,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,sBAAsB,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,qBAAqB,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC5C,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,qBAAqB,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QACpC,IACE,QAAQ,KAAK,SAAS;YACtB,QAAQ,KAAK,IAAI;YACjB,OAAO,QAAQ,KAAK,QAAQ,EAC5B,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,oBAAoB,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO;YACL,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC;YAC/B,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC;YAC7B,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC;YAC7B,GAAG,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,OAAO,GAAG,sBAAsB,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;IAClE,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,OAAO,GAAiB,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/D,SAAS,EAAE,4BAA4B,CACrC,MAAM,CAAC,SAAS,EAChB,WAAW,KAAK,cAAc,CAC/B;QACD,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxE,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,OAAO,EAAE,CAAC,CAAC,SAAS,CAAW;QAC/B,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAW;QAClC,OAAO;QACP,OAAO;KACR,CAAC;AACJ,CAAC"}
package/dist/rooms.d.ts DELETED
@@ -1,29 +0,0 @@
1
- /**
2
- * Deterministic room id derived from a cwd. Two Pi processes in the same
3
- * directory produce the same id; different cwds produce different ids
4
- * (with cryptographic-strength collision resistance). Symlinks are resolved
5
- * via `realpath` so `/a` and `/symlink-to-a` map to the same room.
6
- *
7
- * Format: first 12 chars of base64url(sha256(realpath)).
8
- */
9
- export declare function roomIdForCwd(cwd: string): string;
10
- /**
11
- * THE single derivation of the App↔Pi `room_id` (plan/41) — keyed by
12
- * `(cwd, name)` so several agents in the SAME folder get distinct rooms (the
13
- * app then renders one tile per agent instead of merging them into one).
14
- *
15
- * Default-preserving: when `name` is absent OR equals `defaultAgentName(cwd)`
16
- * (an agent with no custom `agent_name`), it returns the LEGACY `roomIdForCwd`
17
- * EXACTLY — so a single unnamed agent's existing conversation is NOT re-keyed
18
- * on upgrade. A custom or `#N`-suffixed name → a name-scoped id (same formula
19
- * the cwd-lock uses).
20
- *
21
- * Using the ASSIGNED leaf name (the broker's `#N` on collision) disambiguates
22
- * even two unnamed agents: the 1st stays `folder` (== default → legacy room),
23
- * the 2nd becomes `folder#2` (≠ default → name-scoped room).
24
- *
25
- * INVARIANT: every callsite that derives the App↔Pi room for the same agent
26
- * MUST go through this function — otherwise the app would pair on a room the
27
- * Pi never announces.
28
- */
29
- export declare function roomIdFor(cwd: string, name?: string): string;
package/dist/rooms.js DELETED
@@ -1,57 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { realpathSync } from "node:fs";
3
- import { defaultAgentName } from "./session/local_config.js";
4
- /**
5
- * Deterministic room id derived from a cwd. Two Pi processes in the same
6
- * directory produce the same id; different cwds produce different ids
7
- * (with cryptographic-strength collision resistance). Symlinks are resolved
8
- * via `realpath` so `/a` and `/symlink-to-a` map to the same room.
9
- *
10
- * Format: first 12 chars of base64url(sha256(realpath)).
11
- */
12
- export function roomIdForCwd(cwd) {
13
- let target;
14
- try {
15
- target = realpathSync(cwd);
16
- }
17
- catch {
18
- // cwd doesn't exist (unlikely in production) — fallback to raw path.
19
- target = cwd;
20
- }
21
- return createHash("sha256").update(target).digest("base64url").slice(0, 12);
22
- }
23
- /**
24
- * THE single derivation of the App↔Pi `room_id` (plan/41) — keyed by
25
- * `(cwd, name)` so several agents in the SAME folder get distinct rooms (the
26
- * app then renders one tile per agent instead of merging them into one).
27
- *
28
- * Default-preserving: when `name` is absent OR equals `defaultAgentName(cwd)`
29
- * (an agent with no custom `agent_name`), it returns the LEGACY `roomIdForCwd`
30
- * EXACTLY — so a single unnamed agent's existing conversation is NOT re-keyed
31
- * on upgrade. A custom or `#N`-suffixed name → a name-scoped id (same formula
32
- * the cwd-lock uses).
33
- *
34
- * Using the ASSIGNED leaf name (the broker's `#N` on collision) disambiguates
35
- * even two unnamed agents: the 1st stays `folder` (== default → legacy room),
36
- * the 2nd becomes `folder#2` (≠ default → name-scoped room).
37
- *
38
- * INVARIANT: every callsite that derives the App↔Pi room for the same agent
39
- * MUST go through this function — otherwise the app would pair on a room the
40
- * Pi never announces.
41
- */
42
- export function roomIdFor(cwd, name) {
43
- if (!name || name === defaultAgentName(cwd))
44
- return roomIdForCwd(cwd);
45
- let target;
46
- try {
47
- target = realpathSync(cwd);
48
- }
49
- catch {
50
- target = cwd;
51
- }
52
- // NUL separator (U+0000): impossible in a POSIX path and stripped from any
53
- // sanitized name, so the cwd/name boundary is unambiguous.
54
- const sep = String.fromCharCode(0);
55
- return createHash("sha256").update(target + sep + name).digest("base64url").slice(0, 12);
56
- }
57
- //# sourceMappingURL=rooms.js.map
package/dist/rooms.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"rooms.js","sourceRoot":"","sources":["../src/rooms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;QACrE,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,IAAa;IAClD,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,gBAAgB,CAAC,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;IACtE,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IACD,2EAA2E;IAC3E,2DAA2D;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACnC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3F,CAAC"}
@@ -1,37 +0,0 @@
1
- import type { Broker } from "./broker.js";
2
- import { BrokerRemote } from "./broker_remote.js";
3
- import { PiForwardClient } from "../transport/pi_forward_client.js";
4
- import type { RelayClient } from "../transport/relay_client.js";
5
- import { type MeshTopologySnapshot } from "../mesh/siblings.js";
6
- import type { Ed25519Keypair } from "../pairing/crypto.js";
7
- /**
8
- * Cross-PC mesh bridge composition. Discovery finishes before either transport
9
- * half is constructed, and the returned bridge stays dormant until its caller
10
- * has re-checked lifecycle ownership and calls `activate()`.
11
- */
12
- export interface AttachBridgeOptions {
13
- /** The leader's local Broker (from SessionPeer.localBroker()). */
14
- broker: Broker;
15
- /** Live relay connection. Caller owns its lifecycle. */
16
- relay: RelayClient;
17
- /** Relay URL in http(s):// form — for standalone topology discovery. */
18
- relayUrl: string;
19
- /** This host's Ed25519 identity (machine Pi-key). */
20
- keypair: Ed25519Keypair;
21
- /** Retained Pi-produced topology. Supplying it bypasses discovery. */
22
- topology?: MeshTopologySnapshot;
23
- /** Standalone discovery deadline per mesh request. Defaults to 5 seconds. */
24
- meshRequestTimeoutMs?: number;
25
- /** Diagnostic logger. Defaults to a no-op (avoids TUI leaks). */
26
- log?: (msg: string) => void;
27
- }
28
- export interface CrossPcBridge {
29
- brokerRemote: BrokerRemote;
30
- piForward: PiForwardClient;
31
- topology: MeshTopologySnapshot;
32
- /** Publish the already-built router exactly once. */
33
- activate(): void;
34
- /** Safe before or after activation; tears down both halves exactly once. */
35
- detach(): void;
36
- }
37
- export declare function attachCrossPcBridge(opts: AttachBridgeOptions): Promise<CrossPcBridge>;
@@ -1,130 +0,0 @@
1
- import { BrokerRemote } from "./broker_remote.js";
2
- import { PiForwardClient } from "../transport/pi_forward_client.js";
3
- import { MeshClient } from "../mesh/client.js";
4
- import { buildTopologySnapshot, discoverTopology, } from "../mesh/siblings.js";
5
- import { canonicalizeEd25519PublicKey, encodeEd25519PublicKey, } from "../mesh/encoding.js";
6
- import { listOwnerPubkeys } from "../pairing/storage.js";
7
- function compareAscii(left, right) {
8
- return left < right ? -1 : left > right ? 1 : 0;
9
- }
10
- function validateAlias(alias, field) {
11
- if (typeof alias !== "string" || alias.length === 0 || alias.includes(":")) {
12
- throw new Error(`mesh: ${field} is not a valid routing alias`);
13
- }
14
- return alias;
15
- }
16
- function validateLegacyPcLabel(label, field) {
17
- if (typeof label !== "string" || label.length === 0) {
18
- throw new Error(`mesh: ${field} is not a valid legacy PC label`);
19
- }
20
- return label;
21
- }
22
- function ownTopology(snapshot, expectedSelfPubkey) {
23
- const selfPubkey = canonicalizeEd25519PublicKey(snapshot.self?.pcPubkey, "self public key");
24
- if (selfPubkey !== expectedSelfPubkey) {
25
- throw new Error("mesh: topology self public key does not match relay identity");
26
- }
27
- const selfLabel = validateAlias(snapshot.self.pcLabel, "self.pcLabel");
28
- const selfLegacyPcLabel = validateLegacyPcLabel(snapshot.self.legacyPcLabel, "self.legacyPcLabel");
29
- const self = Object.freeze({
30
- pcLabel: selfLabel,
31
- pcPubkey: selfPubkey,
32
- legacyPcLabel: selfLegacyPcLabel,
33
- });
34
- const siblingKeys = new Set();
35
- const siblingAliases = new Set();
36
- const normalizedSiblings = [];
37
- for (const [index, sibling] of snapshot.siblings.entries()) {
38
- const pcPubkey = canonicalizeEd25519PublicKey(sibling.pcPubkey, `siblings[${index}].pcPubkey`);
39
- if (pcPubkey === selfPubkey)
40
- continue;
41
- const pcLabel = validateAlias(sibling.pcLabel, `siblings[${index}].pcLabel`);
42
- const legacyPcLabel = validateLegacyPcLabel(sibling.legacyPcLabel, `siblings[${index}].legacyPcLabel`);
43
- if (pcLabel === selfLabel || siblingAliases.has(pcLabel)) {
44
- throw new Error("mesh: duplicate sibling routing alias");
45
- }
46
- if (siblingKeys.has(pcPubkey)) {
47
- throw new Error("mesh: duplicate sibling public key");
48
- }
49
- siblingAliases.add(pcLabel);
50
- siblingKeys.add(pcPubkey);
51
- normalizedSiblings.push(Object.freeze({ pcLabel, pcPubkey, legacyPcLabel }));
52
- }
53
- normalizedSiblings.sort((left, right) => compareAscii(left.pcPubkey, right.pcPubkey));
54
- return Object.freeze({ self, siblings: Object.freeze(normalizedSiblings) });
55
- }
56
- async function discoverStandaloneTopology(opts) {
57
- const silent = { warn: (_message) => { } };
58
- try {
59
- const owners = await listOwnerPubkeys();
60
- return await discoverTopology({
61
- client: new MeshClient(opts.relayUrl, {
62
- ...(opts.meshRequestTimeoutMs !== undefined
63
- ? { requestTimeoutMs: opts.meshRequestTimeoutMs }
64
- : {}),
65
- }),
66
- ownerEpks: owners,
67
- myPubkey: opts.keypair.publicKey,
68
- log: silent,
69
- });
70
- }
71
- catch {
72
- return buildTopologySnapshot(opts.keypair.publicKey, []);
73
- }
74
- }
75
- export async function attachCrossPcBridge(opts) {
76
- const expectedSelfPubkey = encodeEd25519PublicKey(opts.keypair.publicKey, "relay public key");
77
- const topology = ownTopology(opts.topology ?? await discoverStandaloneTopology(opts), expectedSelfPubkey);
78
- // No Relay listeners exist until all standalone discovery has completed.
79
- const piForward = new PiForwardClient(opts.relay);
80
- let brokerRemote;
81
- try {
82
- brokerRemote = new BrokerRemote({
83
- broker: opts.broker,
84
- pi: piForward,
85
- topology,
86
- activateOnConstruct: false,
87
- log: opts.log ?? (() => { }),
88
- });
89
- }
90
- catch (error) {
91
- piForward.detach();
92
- throw error;
93
- }
94
- let state = "dormant";
95
- return {
96
- brokerRemote,
97
- piForward,
98
- topology,
99
- activate() {
100
- if (state !== "dormant")
101
- return;
102
- try {
103
- brokerRemote.activate();
104
- state = "active";
105
- }
106
- catch (error) {
107
- state = "detached";
108
- try {
109
- brokerRemote.detach();
110
- }
111
- finally {
112
- piForward.detach();
113
- }
114
- throw error;
115
- }
116
- },
117
- detach() {
118
- if (state === "detached")
119
- return;
120
- state = "detached";
121
- try {
122
- brokerRemote.detach();
123
- }
124
- finally {
125
- piForward.detach();
126
- }
127
- },
128
- };
129
- }
130
- //# sourceMappingURL=bridge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/session/bridge.ts"],"names":[],"mappings":"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"}
@@ -1,189 +0,0 @@
1
- import type { Server } from "node:net";
2
- import { type Envelope } from "./envelope.js";
3
- /**
4
- * Structured view of one mesh peer (plan/38). The `address` is the canonical
5
- * routing key; the other fields let a client group/label peers WITHOUT parsing
6
- * the address string. `pc` is undefined for local peers (filled cross-PC in
7
- * Fase 2). Returned by `list_peers` as `peers_detailed`.
8
- */
9
- export interface PeerInfo {
10
- /** Cross-PC label; undefined for a local peer. */
11
- pc?: string;
12
- /** Working directory (realpath). Empty string for a legacy peer (no cwd). */
13
- cwd: string;
14
- /** Clean leaf name (carries a `#N` only on a same-(cwd,name) collision). */
15
- name: string;
16
- /** Canonical address — the broker's Map key and the `to`/`from` on the wire. */
17
- address: string;
18
- }
19
- /**
20
- * THE sole encoder of a peer address (plan/38): `[<pc>:]<cwd>@<nome>`.
21
- *
22
- * - `cwd` present → `<cwd>@<nome>` (the `@` separates name from path so a `/`
23
- * in the path never confuses lookup, which is exact-match anyway).
24
- * - `cwd` empty (legacy peer that sent no cwd) → `address == name`, preserving
25
- * pre-plan/38 behavior so a mixed mesh keeps routing.
26
- * - `pc` present (cross-PC, Fase 2) → prefixed `<pc>:`.
27
- *
28
- * Does NOT sanitize — callers sanitize the `name` once (see `sanitizeMeshName`)
29
- * before composing, so an already-appended `#N` collision suffix survives.
30
- * Everyone else ECHOES `peer.address` verbatim; only the broker composes.
31
- */
32
- export declare function composeAddress(parts: {
33
- pc?: string;
34
- cwd: string;
35
- name: string;
36
- }): string;
37
- /**
38
- * Sanitize a requested mesh name to a safe leaf while PRESERVING a trailing
39
- * `#N` collision suffix (which the cwd-lock or a prior assignment may have
40
- * added — `sanitizeSegment` alone would mangle `#`→`-`). The base is run through
41
- * `sanitizeSegment` (af66d04); an unusable base (empty / reserved keyword) falls
42
- * back to `"agent"`.
43
- */
44
- export declare function sanitizeMeshName(raw: string): string;
45
- /**
46
- * Broker hosted by the session leader. Accepts UDS connections, maintains a
47
- * `name → connection` map, routes envelopes per the `to` field, and appends
48
- * each routed message to an `audit.jsonl` log.
49
- *
50
- * Auto-suffix on name collision: when a peer registers a name already taken,
51
- * the broker assigns `<name>#N` and returns it in the register ack.
52
- *
53
- * ## ACK protocol (plan/25 Wave 0; reliable delivery per plan/34)
54
- *
55
- * For **unicast non-broker** envelopes the broker synchronously emits an ACK
56
- * envelope back to the sender once it has delivered:
57
- *
58
- * - target online → deliver envelope, ACK `received`
59
- * - no such peer → silent drop (sender times out)
60
- *
61
- * plan/34 removed the busy-drop: a message that arrives while the target is
62
- * mid-turn is **always delivered**, never dropped. The Pi harness
63
- * (`sendMessage(triggerTurn:true)`) enqueues mid-turn messages and processes
64
- * them in the upcoming turn, so the broker needs no busy gate or mailbox.
65
- * Consequently `busy` is no longer a possible ACK status for unicast new
66
- * work — the sender always gets `received`. (Turn-lifecycle / working
67
- * indicators live in `index.ts` via room_meta over the relay, not here.)
68
- *
69
- * Broadcast/multicast/broker-addressed envelopes are not ACKed (no single
70
- * authoritative recipient or no semantic match). The audit log carries the
71
- * ACK status (`received | denied | none`) per envelope.
72
- */
73
- export interface BrokerOptions {
74
- server: Server;
75
- auditPath?: string;
76
- /** Optional callback invoked after each successful route (testing/observability). */
77
- onRouted?: (env: Envelope, deliveredTo: string[]) => void;
78
- }
79
- /**
80
- * Hook the broker calls before doing local routing, so cross-PC prefixes
81
- * (`<pc_label>:<peer_name>`) can be handed off to a remote forwarder
82
- * without baking transport knowledge into the broker. Wave C (plan/25)
83
- * wires `broker_remote.ts` here.
84
- */
85
- export interface RemoteRouter {
86
- /**
87
- * Try to claim responsibility for routing this envelope cross-PC.
88
- * Returns true if claimed (broker MUST NOT also deliver locally). Returns
89
- * false if the envelope should fall through to local routing — e.g., the
90
- * prefix matches the local `pc_label`, the prefix is not a known remote
91
- * label (backward-compat for local names containing `:`), or there's no
92
- * prefix at all.
93
- */
94
- tryRouteOutbound(env: Envelope): boolean;
95
- /** Aggregated remote peer addresses (`<pc_label>:<cwd>@<nome>`) for the
96
- * `list_peers` reply's `peers` (string) field. Empty when nothing known. */
97
- listRemotePeers(): string[];
98
- /** Structured remote roster (plan/38 Fase 2): one `PeerInfo` per cross-PC
99
- * peer with `pc` filled (the sibling label), `cwd`/`name` from the sibling's
100
- * inventory, and `address` prefixed `<pc>:<cwd>@<nome>`. Powers the
101
- * `peers_detailed` half of `list_peers` so clients group by `pc`/`cwd`
102
- * without parsing. Empty when nothing known. */
103
- listRemotePeerInfos(): PeerInfo[];
104
- }
105
- export interface ConditionalRemoteRouterHost {
106
- clearRemoteRouter(expected: RemoteRouter): void;
107
- }
108
- /** Local outcome of a cross-PC envelope injection. broker_remote uses this
109
- * to construct the ACK envelope it sends back via the relay. plan/34: `busy`
110
- * is gone — injection always delivers when the peer exists. */
111
- export type RemoteInjectStatus = "received" | "denied";
112
- export declare class Broker {
113
- private readonly peers;
114
- private readonly auditPath?;
115
- private readonly onRouted?;
116
- private readonly server;
117
- /** Plan/25 Wave C: optional handoff for cross-PC routing. Null = local only. */
118
- private remoteRouter;
119
- constructor(opts: BrokerOptions);
120
- /** Attach (or detach with null) a cross-PC router. Idempotent. */
121
- setRemoteRouter(router: RemoteRouter | null): void;
122
- /** Clear only when the caller still owns the active router slot. */
123
- clearRemoteRouter(expected: RemoteRouter): void;
124
- /**
125
- * Plan/25 Wave C entry point: deliver an envelope that arrived from a
126
- * remote PC (via relay forward) into the local UDS mesh. Skips the
127
- * `force from = conn.name` rule (that defense is anti-spoof for local
128
- * peers; cross-PC has its own defense via the relay's verified `from_pc`).
129
- *
130
- * Returns the ACK status so the caller (broker_remote) can pack and
131
- * forward an ACK envelope back across the relay:
132
- * - `received` — target exists, envelope delivered (plan/34: always
133
- * delivered when the peer is online — the Pi harness enqueues mid-turn
134
- * messages, so there is no busy-drop)
135
- * - `denied` — no such local peer (or write failed) — caller maps to
136
- * transport_error or denied ACK as it sees fit
137
- */
138
- injectFromRemote(env: Envelope): RemoteInjectStatus;
139
- /** Peers currently registered. Snapshot, safe to read. */
140
- peerNames(): string[];
141
- close(): Promise<void>;
142
- private _handleConnection;
143
- private _onData;
144
- private _handleLine;
145
- private _handleRegister;
146
- /**
147
- * Answer a read-only `list_peers` request from an UNREGISTERED connection
148
- * (the `remote-pi peers` CLI probe). Returns true when the line was such a
149
- * probe — the reply is written and the connection stays unregistered: no
150
- * name assigned, no `peer_joined`/`peer_left` broadcast, no sibling push, so
151
- * querying the roster from the shell never perturbs the mesh. Returns false
152
- * (not a probe) so the caller falls through to the register handshake.
153
- */
154
- private _tryObserverProbe;
155
- /** Local UDS peer names plus cross-PC `<pc>:<peer>` entries from the remote
156
- * router (empty when no bridge). Shared by the registered `list_peers`
157
- * handler and the unregistered observer probe. */
158
- private _allPeerNames;
159
- /** Structured roster of LOCAL UDS peers (plan/38): one `PeerInfo` each, no
160
- * `pc` (they're on this machine). Public so the cross-PC router
161
- * (`broker_remote`) can read the authoritative local inventory directly to
162
- * push to siblings — no `list_peers` round-trip, no stale cache. */
163
- localPeerInfos(): PeerInfo[];
164
- /** Structured roster (plan/38): local peers (no `pc`) + cross-PC peers with
165
- * `pc`/`cwd`/`name` filled by the remote router (Fase 2). */
166
- private _allPeerInfos;
167
- /**
168
- * Resolve a free `(name, address)` for a register, keyed by **(cwd, name)**
169
- * (plan/38): the collision check is on the composed ADDRESS, so a name only
170
- * collides with another peer in the SAME cwd. `#N` is appended to the name
171
- * (matching the cwd-lock's suffix scheme) until the address is free; for a
172
- * legacy peer (cwd "") the address is the name, preserving global-name `#N`.
173
- */
174
- private _identityForRegister;
175
- private _dropPeerAt;
176
- private _onClose;
177
- private _route;
178
- private _resolveTargets;
179
- /**
180
- * Writes an ACK envelope to the original sender's socket. Synchronous —
181
- * the caller is inside `_route` and must keep busy-check/busy-set atomic.
182
- * Broker → sender: `from="broker"`, `to=env.from`, `re=env.id`,
183
- * `body={type:"ack", status, target}`.
184
- */
185
- private _sendAckToSender;
186
- private _handleBrokerMessage;
187
- private _broadcastSystem;
188
- private _appendAudit;
189
- }