@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
@@ -0,0 +1,42 @@
1
+ export interface PeerRecord {
2
+ name: string;
3
+ remote_epk: string;
4
+ paired_at: string;
5
+ }
6
+ export declare function listPeers(): Promise<PeerRecord[]>;
7
+ declare const _ownerStorageTokenBrand: unique symbol;
8
+ /** Opaque, process-local provenance for one canonical Owner storage slot. */
9
+ export type OwnerStorageToken = {
10
+ readonly [_ownerStorageTokenBrand]: true;
11
+ };
12
+ export interface OwnerStorageSnapshotRecord {
13
+ readonly rawOwnerPubkey: unknown;
14
+ readonly token: OwnerStorageToken;
15
+ }
16
+ export type ConditionalPeerRemoval = {
17
+ readonly outcome: "removed";
18
+ readonly nextToken: OwnerStorageToken;
19
+ } | {
20
+ readonly outcome: "stale" | "not_found" | "no_authority";
21
+ };
22
+ export declare function addPeer(record: PeerRecord): Promise<void>;
23
+ /**
24
+ * Returns the set of distinct `remote_epk` values in peers.json.
25
+ *
26
+ * Each `remote_epk` is the paired Owner's Ed25519 public key and represents a
27
+ * machine-scoped authorization entry.
28
+ */
29
+ export declare function listOwnerPubkeys(): Promise<unknown[]>;
30
+ /**
31
+ * Atomically snapshots raw Owner handles and their canonical-slot provenance.
32
+ * The token is process-local and opaque to callers.
33
+ */
34
+ export declare function snapshotOwnerPubkeys(): Promise<readonly OwnerStorageSnapshotRecord[]>;
35
+ /**
36
+ * Removes one exact raw handle only when its snapshot provenance still owns
37
+ * the target canonical Owner slot. The final authority/token checks and sync
38
+ * write share the existing serialized mutation lane.
39
+ */
40
+ export declare function conditionalRemovePeer(remoteEpk: string, expectedToken: OwnerStorageToken, canCommit?: () => boolean): Promise<ConditionalPeerRemoval>;
41
+ export declare function removePeer(remoteEpk: string, canCommit?: () => boolean): Promise<boolean>;
42
+ export {};
@@ -0,0 +1,207 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { canonicalizeEd25519PublicKey } from "./crypto.js";
6
+ const PEERS_PATH = join(homedir(), ".pi", "remote", "peers.json");
7
+ export async function listPeers() {
8
+ try {
9
+ const raw = await readFile(PEERS_PATH, "utf8");
10
+ const parsed = JSON.parse(raw);
11
+ return Array.isArray(parsed.peers) ? parsed.peers : [];
12
+ }
13
+ catch {
14
+ return [];
15
+ }
16
+ }
17
+ /**
18
+ * Strict container read used by serialized storage mutations. Valid records
19
+ * remain verbatim so one corrupt entry never erases other pairings.
20
+ */
21
+ async function _readPeerContainerStrict() {
22
+ let raw;
23
+ try {
24
+ raw = await readFile(PEERS_PATH, "utf8");
25
+ }
26
+ catch (error) {
27
+ if (typeof error === "object" &&
28
+ error !== null &&
29
+ "code" in error &&
30
+ error.code === "ENOENT") {
31
+ return [];
32
+ }
33
+ throw error;
34
+ }
35
+ const parsed = JSON.parse(raw);
36
+ if (!Array.isArray(parsed.peers)) {
37
+ throw new Error("Invalid peers.json container");
38
+ }
39
+ return parsed.peers;
40
+ }
41
+ let _peerMutationQueue = Promise.resolve();
42
+ const _ownerSlotTokens = new Map();
43
+ const _ownerStorageTokenBrand = Symbol("owner-storage-token");
44
+ function _ownerSlotKey(rawOwnerPubkey) {
45
+ if (typeof rawOwnerPubkey !== "string") {
46
+ // Invalid non-string records remain isolated; their quarantine slots never
47
+ // collide with a valid canonical Owner identity.
48
+ return `raw:quarantine:${typeof rawOwnerPubkey}`;
49
+ }
50
+ try {
51
+ return `owner:${canonicalizeEd25519PublicKey(rawOwnerPubkey, "Owner record")}`;
52
+ }
53
+ catch {
54
+ return `raw:string:${rawOwnerPubkey}`;
55
+ }
56
+ }
57
+ function _tokenForSlot(slot) {
58
+ const existing = _ownerSlotTokens.get(slot);
59
+ if (existing)
60
+ return existing;
61
+ const token = Object.freeze({ [_ownerStorageTokenBrand]: true });
62
+ _ownerSlotTokens.set(slot, token);
63
+ return token;
64
+ }
65
+ function _invalidateOwnerSlot(rawOwnerPubkey) {
66
+ const slot = _ownerSlotKey(rawOwnerPubkey);
67
+ const token = Object.freeze({ [_ownerStorageTokenBrand]: true });
68
+ _ownerSlotTokens.set(slot, token);
69
+ return token;
70
+ }
71
+ function _serializePeerMutation(mutation) {
72
+ const result = _peerMutationQueue.then(mutation, mutation);
73
+ _peerMutationQueue = result.then(() => undefined, () => undefined);
74
+ return result;
75
+ }
76
+ export function addPeer(record) {
77
+ return _serializePeerMutation(async () => {
78
+ const peers = await listPeers();
79
+ const idx = peers.findIndex((peer) => !!peer &&
80
+ typeof peer === "object" &&
81
+ peer.remote_epk === record.remote_epk);
82
+ if (idx >= 0) {
83
+ peers[idx] = record; // idempotent re-pair
84
+ }
85
+ else {
86
+ peers.push(record);
87
+ }
88
+ await mkdir(dirname(PEERS_PATH), { recursive: true });
89
+ await writeFile(PEERS_PATH, JSON.stringify({ peers }, null, 2));
90
+ // A successful re-pair is a new storage provenance event even when the
91
+ // record bytes happen to be identical.
92
+ _invalidateOwnerSlot(record.remote_epk);
93
+ });
94
+ }
95
+ /**
96
+ * Returns the set of distinct `remote_epk` values in peers.json.
97
+ *
98
+ * Each `remote_epk` is the paired Owner's Ed25519 public key and represents a
99
+ * machine-scoped authorization entry.
100
+ */
101
+ export async function listOwnerPubkeys() {
102
+ const peers = await listPeers();
103
+ const seen = new Set();
104
+ for (const peer of peers) {
105
+ if (!peer || typeof peer !== "object") {
106
+ seen.add(peer);
107
+ continue;
108
+ }
109
+ seen.add(peer.remote_epk);
110
+ }
111
+ return [...seen];
112
+ }
113
+ /**
114
+ * Atomically snapshots raw Owner handles and their canonical-slot provenance.
115
+ * The token is process-local and opaque to callers.
116
+ */
117
+ export function snapshotOwnerPubkeys() {
118
+ return _serializePeerMutation(async () => {
119
+ const peers = await _readPeerContainerStrict();
120
+ const rawOwners = new Set();
121
+ for (const peer of peers) {
122
+ if (!peer || typeof peer !== "object") {
123
+ rawOwners.add(peer);
124
+ }
125
+ else {
126
+ rawOwners.add(peer.remote_epk);
127
+ }
128
+ }
129
+ return [...rawOwners].map((rawOwnerPubkey) => ({
130
+ rawOwnerPubkey,
131
+ token: _tokenForSlot(_ownerSlotKey(rawOwnerPubkey)),
132
+ }));
133
+ });
134
+ }
135
+ /**
136
+ * Removes one exact raw handle only when its snapshot provenance still owns
137
+ * the target canonical Owner slot. The final authority/token checks and sync
138
+ * write share the existing serialized mutation lane.
139
+ */
140
+ export function conditionalRemovePeer(remoteEpk, expectedToken, canCommit) {
141
+ return _serializePeerMutation(async () => {
142
+ const slot = _ownerSlotKey(remoteEpk);
143
+ // Provenance belongs to the canonical Owner slot, not the exact raw
144
+ // spelling. A stale slot must therefore win over an absent old spelling.
145
+ if (_tokenForSlot(slot) !== expectedToken)
146
+ return { outcome: "stale" };
147
+ const peers = await _readPeerContainerStrict();
148
+ const filtered = peers.filter((peer) => !peer ||
149
+ typeof peer !== "object" ||
150
+ peer.remote_epk !== remoteEpk);
151
+ if (filtered.length === peers.length)
152
+ return { outcome: "not_found" };
153
+ await mkdir(dirname(PEERS_PATH), { recursive: true });
154
+ // No await may intervene between the final token/authority checks and
155
+ // synchronous write, preserving the lane's fail-closed commit boundary.
156
+ if (_tokenForSlot(slot) !== expectedToken)
157
+ return { outcome: "stale" };
158
+ if (canCommit) {
159
+ let authorized = false;
160
+ try {
161
+ authorized = canCommit();
162
+ }
163
+ catch {
164
+ return { outcome: "no_authority" };
165
+ }
166
+ if (!authorized)
167
+ return { outcome: "no_authority" };
168
+ }
169
+ writeFileSync(PEERS_PATH, JSON.stringify({ peers: filtered }, null, 2));
170
+ return { outcome: "removed", nextToken: _invalidateOwnerSlot(remoteEpk) };
171
+ });
172
+ }
173
+ export function removePeer(remoteEpk, canCommit) {
174
+ return _serializePeerMutation(async () => {
175
+ const peers = await listPeers();
176
+ const filtered = peers.filter((peer) => !peer ||
177
+ typeof peer !== "object" ||
178
+ peer.remote_epk !== remoteEpk);
179
+ if (filtered.length === peers.length)
180
+ return false;
181
+ await mkdir(dirname(PEERS_PATH), { recursive: true });
182
+ const serialized = JSON.stringify({ peers: filtered }, null, 2);
183
+ if (canCommit) {
184
+ // Guarded commits are atomic with their final authority check: fail
185
+ // closed on false/throw, then synchronously persist the small JSON rewrite.
186
+ let authorized = false;
187
+ try {
188
+ authorized = canCommit();
189
+ }
190
+ catch {
191
+ return false;
192
+ }
193
+ if (!authorized)
194
+ return false;
195
+ writeFileSync(PEERS_PATH, serialized);
196
+ }
197
+ else {
198
+ // Manual removals keep the established asynchronous storage behavior.
199
+ await writeFile(PEERS_PATH, serialized);
200
+ }
201
+ const removed = true;
202
+ if (removed)
203
+ _invalidateOwnerSlot(remoteEpk);
204
+ return removed;
205
+ });
206
+ }
207
+ //# sourceMappingURL=owner_storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owner_storage.js","sourceRoot":"","sources":["../../src/pairing/owner_storage.ts"],"names":[],"mappings":"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"}
@@ -1,59 +1,20 @@
1
- /** Default ephemeral-token lifetime (also the QR rotation period). */
2
1
  export declare const TOKEN_TTL_MS = 60000;
3
- /** Bounds for a caller-supplied pairing TTL (e.g. `/remote-pi pair --ttl <s>`). */
4
2
  export declare const PAIR_TTL_MIN_MS = 10000;
5
3
  export declare const PAIR_TTL_MAX_MS = 600000;
6
- /** Clamp an arbitrary ttl (ms) into the safe pairing range; NaN → default. */
7
4
  export declare function clampPairTtlMs(ttlMs: number): number;
8
- /** Encapsulates the single active QR token. One instance per Pi process. */
9
5
  export declare class QRSession {
10
6
  private active;
11
- /** Generates a fresh 16-byte random token encoded as base64url. */
12
7
  generateToken(): string;
13
- /**
14
- * Issues a new active token, invalidating any previous one.
15
- * Returns the token and its expiry timestamp.
16
- */
17
8
  issueToken(ttlMs?: number): {
18
9
  token: string;
19
10
  expiresAt: number;
20
11
  };
21
- /** Validates and atomically consumes a token. */
22
12
  consumeToken(token: string): "ok" | "expired" | "consumed" | "unknown";
23
13
  clear(): void;
24
14
  }
25
15
  export declare const qrSession: QRSession;
26
- export declare function buildQRUri(token: string, longtermEdPk: Uint8Array, // Ed25519 — only peer ID after E2E rollback
27
- sessionName: string,
28
- /**
29
- * Pi room id (12 chars, base64url) derived from cwd. App routes pair_request
30
- * to this room so the relay delivers it to the right Pi instance among N
31
- * paralelos com mesmo epk. Adicionado no fix do plano 17 (sem `rm` o app
32
- * cai em room=main e o relay drops com "dest not found").
33
- */
34
- roomId?: string): string;
35
- /**
36
- * Returns the QR ASCII as a string (pure Unicode block characters —
37
- * `█ ▀ ▄` and space, NO ANSI escapes — qrcode-terminal v0.12 small mode
38
- * is escape-free, see lib/main.js:48-53).
39
- *
40
- * The caller can either write the string to stderr (legacy path, breaks
41
- * the Pi TUI layout) or inject it via `pi.sendMessage` (renders inside
42
- * the chat panel as proper content).
43
- */
16
+ /** Builds the endpoint-aware pairing URI. */
17
+ export declare function buildQRUri(token: string, longtermEdPk: Uint8Array, sessionName: string, endpointId: string, runtimeInstanceId: string): string;
44
18
  export declare function renderQRAscii(uri: string): string;
45
- /**
46
- * Legacy stderr writer — kept for the standalone CLI mode
47
- * (`pi-extension/src/index.ts` bottom block, which runs outside a Pi TUI).
48
- * Inside the Pi TUI extension flow, use `renderQRAscii` + `pi.sendMessage`
49
- * instead — direct stderr writes from inside an extension break the TUI's
50
- * scrollable output widget (the QR overflows the panel and other writes
51
- * collide with the prompt area).
52
- */
53
19
  export declare function displayQR(uri: string): void;
54
- /**
55
- * Starts a rotating QR session: generates a new QR every 60s, printing it
56
- * to stdout. Returns a `stop()` function that cancels the rotation and clears
57
- * the active token.
58
- */
59
- export declare function startQRRotation(longtermEdPk: Uint8Array, sessionName: string, roomId?: string): () => void;
20
+ export declare function startQRRotation(longtermEdPk: Uint8Array, sessionName: string, endpointId: string, runtimeInstanceId: string): () => void;
@@ -1,34 +1,24 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import qrTerminal from "qrcode-terminal";
3
- /** Default ephemeral-token lifetime (also the QR rotation period). */
4
3
  export const TOKEN_TTL_MS = 60_000;
5
- /** Bounds for a caller-supplied pairing TTL (e.g. `/remote-pi pair --ttl <s>`). */
6
4
  export const PAIR_TTL_MIN_MS = 10_000;
7
5
  export const PAIR_TTL_MAX_MS = 600_000;
8
- /** Clamp an arbitrary ttl (ms) into the safe pairing range; NaN → default. */
9
6
  export function clampPairTtlMs(ttlMs) {
10
7
  if (!Number.isFinite(ttlMs))
11
8
  return TOKEN_TTL_MS;
12
9
  return Math.min(PAIR_TTL_MAX_MS, Math.max(PAIR_TTL_MIN_MS, Math.floor(ttlMs)));
13
10
  }
14
- /** Encapsulates the single active QR token. One instance per Pi process. */
15
11
  export class QRSession {
16
12
  active = null;
17
- /** Generates a fresh 16-byte random token encoded as base64url. */
18
13
  generateToken() {
19
14
  return randomBytes(16).toString("base64url");
20
15
  }
21
- /**
22
- * Issues a new active token, invalidating any previous one.
23
- * Returns the token and its expiry timestamp.
24
- */
25
16
  issueToken(ttlMs = TOKEN_TTL_MS) {
26
17
  const token = this.generateToken();
27
18
  const expiresAt = Date.now() + ttlMs;
28
19
  this.active = { token, expiresAt, consumed: false };
29
20
  return { token, expiresAt };
30
21
  }
31
- /** Validates and atomically consumes a token. */
32
22
  consumeToken(token) {
33
23
  if (!this.active || this.active.token !== token)
34
24
  return "unknown";
@@ -44,74 +34,34 @@ export class QRSession {
44
34
  }
45
35
  }
46
36
  export const qrSession = new QRSession();
47
- // ── URI + display ─────────────────────────────────────────────────────────────
48
- export function buildQRUri(token, longtermEdPk, // Ed25519 — only peer ID after E2E rollback
49
- sessionName,
50
- /**
51
- * Pi room id (12 chars, base64url) derived from cwd. App routes pair_request
52
- * to this room so the relay delivers it to the right Pi instance among N
53
- * paralelos com mesmo epk. Adicionado no fix do plano 17 (sem `rm` o app
54
- * cai em room=main e o relay drops com "dest not found").
55
- */
56
- roomId) {
57
- // `r` (relay URL) removed in plano 14 — relay now comes from app config /
58
- // pi-ext env|config|default chain. Keeps QR ~30-50 chars shorter.
59
- // `n` (session name) is kept: the app uses it for the pre-pair_ok preview
60
- // screen (showing the agent name immediately after scan, before the
61
- // handshake completes). Dropping it briefly shrank the QR but the QR
62
- // size no longer matters now that the copy-paste URI is rendered via
63
- // `pi.sendMessage` into the chat panel (not the QR overflow area).
64
- const epkB64 = Buffer.from(longtermEdPk).toString("base64url");
37
+ /** Builds the endpoint-aware pairing URI. */
38
+ export function buildQRUri(token, longtermEdPk, sessionName, endpointId, runtimeInstanceId) {
65
39
  const params = new URLSearchParams({
66
40
  t: token,
67
- epk: epkB64,
41
+ epk: Buffer.from(longtermEdPk).toString("base64url"),
68
42
  n: sessionName.slice(0, 80),
43
+ ep: endpointId,
44
+ rt: runtimeInstanceId,
69
45
  });
70
- if (roomId)
71
- params.set("rm", roomId);
72
46
  return `remotepi://pair?${params.toString()}`;
73
47
  }
74
- /**
75
- * Returns the QR ASCII as a string (pure Unicode block characters —
76
- * `█ ▀ ▄` and space, NO ANSI escapes — qrcode-terminal v0.12 small mode
77
- * is escape-free, see lib/main.js:48-53).
78
- *
79
- * The caller can either write the string to stderr (legacy path, breaks
80
- * the Pi TUI layout) or inject it via `pi.sendMessage` (renders inside
81
- * the chat panel as proper content).
82
- */
83
48
  export function renderQRAscii(uri) {
84
49
  let out = "";
85
50
  qrTerminal.generate(uri, { small: true }, (qrcode) => { out = qrcode; });
86
51
  return out;
87
52
  }
88
- /**
89
- * Legacy stderr writer — kept for the standalone CLI mode
90
- * (`pi-extension/src/index.ts` bottom block, which runs outside a Pi TUI).
91
- * Inside the Pi TUI extension flow, use `renderQRAscii` + `pi.sendMessage`
92
- * instead — direct stderr writes from inside an extension break the TUI's
93
- * scrollable output widget (the QR overflows the panel and other writes
94
- * collide with the prompt area).
95
- */
96
53
  export function displayQR(uri) {
97
- const qrcode = renderQRAscii(uri);
98
- process.stderr.write(`\n📱 Scan to pair:\n\n${qrcode}\n`);
54
+ process.stderr.write(`\nScan to pair:\n\n${renderQRAscii(uri)}\n`);
99
55
  }
100
- /**
101
- * Starts a rotating QR session: generates a new QR every 60s, printing it
102
- * to stdout. Returns a `stop()` function that cancels the rotation and clears
103
- * the active token.
104
- */
105
- export function startQRRotation(longtermEdPk, sessionName, roomId) {
56
+ export function startQRRotation(longtermEdPk, sessionName, endpointId, runtimeInstanceId) {
106
57
  let timer = null;
107
58
  let stopped = false;
108
59
  const rotate = () => {
109
60
  if (stopped)
110
61
  return;
111
62
  const { token, expiresAt } = qrSession.issueToken();
112
- const uri = buildQRUri(token, longtermEdPk, sessionName, roomId);
113
- displayQR(uri);
114
- console.log(`⏱ Renews at ${new Date(expiresAt).toLocaleTimeString()} — waiting for scan…`);
63
+ displayQR(buildQRUri(token, longtermEdPk, sessionName, endpointId, runtimeInstanceId));
64
+ console.log(`Renews at ${new Date(expiresAt).toLocaleTimeString()} — waiting for scan…`);
115
65
  timer = setTimeout(rotate, TOKEN_TTL_MS);
116
66
  };
117
67
  rotate();
@@ -1 +1 @@
1
- {"version":3,"file":"qr.js","sourceRoot":"","sources":["../../src/pairing/qr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"qr.js","sourceRoot":"","sources":["../../src/pairing/qr.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { type Ed25519Keypair } from "./crypto.js";
2
+ export { addPeer, listPeers, listOwnerPubkeys, snapshotOwnerPubkeys, conditionalRemovePeer, removePeer, } from "./owner_storage.js";
3
+ export type { PeerRecord, OwnerStorageToken, OwnerStorageSnapshotRecord, ConditionalPeerRemoval, } from "./owner_storage.js";
2
4
  /** Raised when the keyring is unreadable on a platform where it's a core OS
3
5
  * service (macOS Keychain, Windows Credential Manager) AND no prior file
4
6
  * identity exists. We refuse to generate a NEW identity here because that
@@ -9,7 +11,7 @@ export declare class KeyringUnavailableError extends Error {
9
11
  }
10
12
  /** Raised when no identity can be resolved (keyring unreadable, no identity
11
13
  * file) BUT `peers.json` already lists paired devices. Minting a fresh key
12
- * here would make SelfRevoke wipe those pairings — see issues #95 / #69. */
14
+ * here would make those existing pairings unusable — see issues #95 / #69. */
13
15
  export declare class PairedIdentityMissingError extends Error {
14
16
  constructor(pairedCount: number, cause: unknown);
15
17
  }
@@ -70,51 +72,7 @@ export declare function _setKeyringRetryForTest(attempts: number | null, delayMs
70
72
  * runs at most once per machine (the old entry is deleted after copy).
71
73
  */
72
74
  export declare function getOrCreateEd25519Keypair(): Promise<Ed25519Keypair>;
73
- export interface PeerRecord {
74
- name: string;
75
- remote_epk: string;
76
- paired_at: string;
77
- }
78
- export declare function listPeers(): Promise<PeerRecord[]>;
79
- declare const _ownerStorageTokenBrand: unique symbol;
80
- /** Opaque, process-local provenance for one canonical Owner storage slot. */
81
- export type OwnerStorageToken = {
82
- readonly [_ownerStorageTokenBrand]: true;
83
- };
84
- export interface OwnerStorageSnapshotRecord {
85
- readonly rawOwnerPubkey: unknown;
86
- readonly token: OwnerStorageToken;
87
- }
88
- export type ConditionalPeerRemoval = {
89
- readonly outcome: "removed";
90
- readonly nextToken: OwnerStorageToken;
91
- } | {
92
- readonly outcome: "stale" | "not_found" | "no_authority";
93
- };
94
- export declare function addPeer(record: PeerRecord): Promise<void>;
95
- /**
96
- * Returns the set of distinct `remote_epk` values in peers.json.
97
- *
98
- * In the current pairing model (plan/23 + plan/24), each `remote_epk` is the
99
- * Owner's Ed25519 pubkey — and we treat each as a distinct Owner the Pi has
100
- * been paired with. Used by the mesh self-revoke poller (plan/24 Wave 3) to
101
- * know which Owners' mesh blobs to fetch.
102
- */
103
- export declare function listOwnerPubkeys(): Promise<unknown[]>;
104
- /**
105
- * Atomically snapshots raw Owner handles and their canonical-slot provenance.
106
- * The token is deliberately process-local and opaque to callers.
107
- */
108
- export declare function snapshotOwnerPubkeys(): Promise<readonly OwnerStorageSnapshotRecord[]>;
109
- /**
110
- * Removes one exact raw handle only when its snapshot provenance still owns
111
- * the target canonical Owner slot. The final authority/token checks and sync
112
- * write share the existing serialized mutation lane.
113
- */
114
- export declare function conditionalRemovePeer(remoteEpk: string, expectedToken: OwnerStorageToken, canCommit?: () => boolean): Promise<ConditionalPeerRemoval>;
115
- export declare function removePeer(remoteEpk: string, canCommit?: () => boolean): Promise<boolean>;
116
75
  /** Test-only: expose the identity-file path so tests can clean it. */
117
76
  export declare const _IDENTITY_FILE_FOR_TEST: string;
118
77
  /** Test-only: expose unlink for cleanup. */
119
78
  export declare const _unlinkIdentityFileForTest: () => Promise<void>;
120
- export {};