@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.
- package/README.md +81 -586
- package/dist/bin/supervisord.js +4 -5
- package/dist/bin/supervisord.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/daemon/cli-links.d.ts +30 -0
- package/dist/daemon/cli-links.js +134 -0
- package/dist/daemon/cli-links.js.map +1 -0
- package/dist/daemon/commands.d.ts +27 -0
- package/dist/daemon/commands.js +295 -0
- package/dist/daemon/commands.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +53 -31
- package/dist/daemon/control_protocol.js +8 -31
- package/dist/daemon/control_protocol.js.map +1 -1
- package/dist/daemon/cron_log.d.ts +2 -23
- package/dist/daemon/cron_log.js +10 -25
- package/dist/daemon/cron_log.js.map +1 -1
- package/dist/daemon/cron_registry.d.ts +3 -40
- package/dist/daemon/cron_registry.js +58 -103
- package/dist/daemon/cron_registry.js.map +1 -1
- package/dist/daemon/install-runtime.d.ts +10 -0
- package/dist/daemon/install-runtime.js +81 -0
- package/dist/daemon/install-runtime.js.map +1 -0
- package/dist/daemon/install.d.ts +3 -63
- package/dist/daemon/install.js +5 -289
- package/dist/daemon/install.js.map +1 -1
- package/dist/daemon/preflight.d.ts +51 -0
- package/dist/daemon/preflight.js +136 -0
- package/dist/daemon/preflight.js.map +1 -0
- package/dist/daemon/registry.d.ts +33 -45
- package/dist/daemon/registry.js +171 -117
- package/dist/daemon/registry.js.map +1 -1
- package/dist/daemon/rpc_child.d.ts +92 -146
- package/dist/daemon/rpc_child.js +336 -263
- package/dist/daemon/rpc_child.js.map +1 -1
- package/dist/daemon/status.d.ts +45 -0
- package/dist/daemon/status.js +87 -0
- package/dist/daemon/status.js.map +1 -0
- package/dist/daemon/supervisor-ipc.d.ts +2 -0
- package/dist/daemon/supervisor-ipc.js +20 -0
- package/dist/daemon/supervisor-ipc.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +48 -71
- package/dist/daemon/supervisor.js +430 -420
- package/dist/daemon/supervisor.js.map +1 -1
- package/dist/extension_ui_bridge.d.ts +4 -3
- package/dist/extension_ui_bridge.js +10 -0
- package/dist/extension_ui_bridge.js.map +1 -1
- package/dist/index.d.ts +25 -230
- package/dist/index.js +515 -5553
- package/dist/index.js.map +1 -1
- package/dist/pairing/crypto.d.ts +8 -1
- package/dist/pairing/crypto.js +56 -6
- package/dist/pairing/crypto.js.map +1 -1
- package/dist/pairing/owner_storage.d.ts +42 -0
- package/dist/pairing/owner_storage.js +207 -0
- package/dist/pairing/owner_storage.js.map +1 -0
- package/dist/pairing/qr.d.ts +3 -42
- package/dist/pairing/qr.js +9 -59
- package/dist/pairing/qr.js.map +1 -1
- package/dist/pairing/storage.d.ts +3 -45
- package/dist/pairing/storage.js +10 -223
- package/dist/pairing/storage.js.map +1 -1
- package/dist/protocol/types.d.ts +1 -1
- package/dist/protocol/v2/schemas.d.ts +1 -1
- package/dist/protocol/v2/schemas.js +1 -1
- package/dist/protocol/v2/schemas.js.map +1 -1
- package/dist/runtime/owner_router.d.ts +16 -0
- package/dist/runtime/owner_router.js +37 -0
- package/dist/runtime/owner_router.js.map +1 -0
- package/dist/session/ipc.d.ts +1 -22
- package/dist/session/ipc.js +4 -11
- package/dist/session/ipc.js.map +1 -1
- package/dist/session/local_config.d.ts +4 -47
- package/dist/session/local_config.js +19 -101
- package/dist/session/local_config.js.map +1 -1
- package/dist/transport/peer_channel.d.ts +25 -39
- package/dist/transport/peer_channel.js +74 -131
- package/dist/transport/peer_channel.js.map +1 -1
- package/dist/transport/relay_client.d.ts +26 -70
- package/dist/transport/relay_client.js +37 -106
- package/dist/transport/relay_client.js.map +1 -1
- package/docs/daemon.md +91 -207
- package/package.json +21 -17
- package/dist/daemon/id.d.ts +0 -24
- package/dist/daemon/id.js +0 -36
- package/dist/daemon/id.js.map +0 -1
- package/dist/mcp/mesh_result.d.ts +0 -10
- package/dist/mcp/mesh_result.js +0 -42
- package/dist/mcp/mesh_result.js.map +0 -1
- package/dist/mcp/mesh_server.d.ts +0 -16
- package/dist/mcp/mesh_server.js +0 -327
- package/dist/mcp/mesh_server.js.map +0 -1
- package/dist/mesh/canonical.d.ts +0 -30
- package/dist/mesh/canonical.js +0 -61
- package/dist/mesh/canonical.js.map +0 -1
- package/dist/mesh/client.d.ts +0 -18
- package/dist/mesh/client.js +0 -125
- package/dist/mesh/client.js.map +0 -1
- package/dist/mesh/encoding.d.ts +0 -38
- package/dist/mesh/encoding.js +0 -216
- package/dist/mesh/encoding.js.map +0 -1
- package/dist/mesh/self_revoke.d.ts +0 -73
- package/dist/mesh/self_revoke.js +0 -401
- package/dist/mesh/self_revoke.js.map +0 -1
- package/dist/mesh/siblings.d.ts +0 -49
- package/dist/mesh/siblings.js +0 -159
- package/dist/mesh/siblings.js.map +0 -1
- package/dist/mesh/types.d.ts +0 -34
- package/dist/mesh/types.js +0 -11
- package/dist/mesh/types.js.map +0 -1
- package/dist/mesh/verify.d.ts +0 -17
- package/dist/mesh/verify.js +0 -86
- package/dist/mesh/verify.js.map +0 -1
- package/dist/rooms.d.ts +0 -29
- package/dist/rooms.js +0 -57
- package/dist/rooms.js.map +0 -1
- package/dist/session/bridge.d.ts +0 -37
- package/dist/session/bridge.js +0 -130
- package/dist/session/bridge.js.map +0 -1
- package/dist/session/broker.d.ts +0 -189
- package/dist/session/broker.js +0 -507
- package/dist/session/broker.js.map +0 -1
- package/dist/session/broker_remote.d.ts +0 -74
- package/dist/session/broker_remote.js +0 -583
- package/dist/session/broker_remote.js.map +0 -1
- package/dist/session/cwd_lock.d.ts +0 -33
- package/dist/session/cwd_lock.js +0 -126
- package/dist/session/cwd_lock.js.map +0 -1
- package/dist/session/envelope.d.ts +0 -33
- package/dist/session/envelope.js +0 -117
- package/dist/session/envelope.js.map +0 -1
- package/dist/session/global_config.d.ts +0 -33
- package/dist/session/global_config.js +0 -73
- package/dist/session/global_config.js.map +0 -1
- package/dist/session/leader_election.d.ts +0 -32
- package/dist/session/leader_election.js +0 -106
- package/dist/session/leader_election.js.map +0 -1
- package/dist/session/mesh_node.d.ts +0 -116
- package/dist/session/mesh_node.js +0 -573
- package/dist/session/mesh_node.js.map +0 -1
- package/dist/session/peer.d.ts +0 -139
- package/dist/session/peer.js +0 -451
- package/dist/session/peer.js.map +0 -1
- package/dist/session/peer_inventory.d.ts +0 -13
- package/dist/session/peer_inventory.js +0 -48
- package/dist/session/peer_inventory.js.map +0 -1
- package/dist/session/peer_limits.d.ts +0 -9
- package/dist/session/peer_limits.js +0 -21
- package/dist/session/peer_limits.js.map +0 -1
- package/dist/session/setup_wizard.d.ts +0 -39
- package/dist/session/setup_wizard.js +0 -63
- package/dist/session/setup_wizard.js.map +0 -1
- package/dist/session/tools.d.ts +0 -24
- package/dist/session/tools.js +0 -252
- package/dist/session/tools.js.map +0 -1
- package/dist/session/wizard.d.ts +0 -13
- package/dist/session/wizard.js +0 -20
- package/dist/session/wizard.js.map +0 -1
- package/dist/transport/pi_forward_client.d.ts +0 -29
- package/dist/transport/pi_forward_client.js +0 -62
- package/dist/transport/pi_forward_client.js.map +0 -1
- package/dist/ui/footer.d.ts +0 -32
- package/dist/ui/footer.js +0 -34
- package/dist/ui/footer.js.map +0 -1
- 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":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AAQlE,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;QACtD,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,wBAAwB;IACrC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,KAAK,IAAI;YACd,MAAM,IAAI,KAAK;YACd,KAA4B,CAAC,IAAI,KAAK,QAAQ,EAC/C,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;IACtD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,IAAI,kBAAkB,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAC1D,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA6B,CAAC;AAC9D,MAAM,uBAAuB,GAAkB,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAgB7E,SAAS,aAAa,CAAC,cAAuB;IAC5C,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE,CAAC;QACvC,2EAA2E;QAC3E,iDAAiD;QACjD,OAAO,kBAAkB,OAAO,cAAc,EAAE,CAAC;IACnD,CAAC;IACD,IAAI,CAAC;QACH,OAAO,SAAS,4BAA4B,CAAC,cAAc,EAAE,cAAc,CAAC,EAAE,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,cAAc,EAAE,CAAC;IACxC,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,CAAsB,CAAC;IACtF,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,cAAuB;IACnD,MAAM,IAAI,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,EAAE,IAAI,EAAE,CAAsB,CAAC;IACtF,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,sBAAsB,CAAI,QAA0B;IAC3D,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3D,kBAAkB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACnE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAAkB;IACxC,OAAO,sBAAsB,CAAC,KAAK,IAAI,EAAE;QACvC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAe,CAAC;QAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CACnC,CAAC,CAAC,IAAI;YACN,OAAO,IAAI,KAAK,QAAQ;YACvB,IAAiC,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU,CACpE,CAAC;QACF,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,qBAAqB;QAC5C,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;QACD,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,uEAAuE;QACvE,uCAAuC;QACvC,oBAAoB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAe,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAE,IAAiC,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,sBAAsB,CAAC,KAAK,IAAI,EAAE;QACvC,MAAM,KAAK,GAAG,MAAM,wBAAwB,EAAE,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAW,CAAC;QACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC,GAAG,CAAE,IAAiC,CAAC,UAAU,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAC7C,cAAc;YACd,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;SACpD,CAAC,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,aAAgC,EAChC,SAAyB;IAEzB,OAAO,sBAAsB,CAAC,KAAK,IAAI,EAAE;QACvC,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;QACtC,oEAAoE;QACpE,yEAAyE;QACzE,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,aAAa;YAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QACvE,MAAM,KAAK,GAAG,MAAM,wBAAwB,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACrC,CAAC,IAAI;YACL,OAAO,IAAI,KAAK,QAAQ;YACvB,IAAiC,CAAC,UAAU,KAAK,SAAS,CAC5D,CAAC;QACF,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QACtE,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,sEAAsE;QACtE,wEAAwE;QACxE,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,aAAa;YAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QACvE,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,UAAU,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC;gBAAC,UAAU,GAAG,SAAS,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;YAAC,CAAC;YAC/E,IAAI,CAAC,UAAU;gBAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;QACtD,CAAC;QACD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACxE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,oBAAoB,CAAC,SAAS,CAAC,EAAE,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,SAAyB;IAEzB,OAAO,sBAAsB,CAAC,KAAK,IAAI,EAAE;QACvC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAe,CAAC;QAC7C,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CACrC,CAAC,IAAI;YACL,OAAO,IAAI,KAAK,QAAQ;YACvB,IAAiC,CAAC,UAAU,KAAK,SAAS,CAC5D,CAAC;QACF,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QACnD,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAChE,IAAI,SAAS,EAAE,CAAC;YACd,oEAAoE;YACpE,4EAA4E;YAC5E,IAAI,UAAU,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC;gBAAC,UAAU,GAAG,SAAS,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,KAAK,CAAC;YAAC,CAAC;YACzD,IAAI,CAAC,UAAU;gBAAE,OAAO,KAAK,CAAC;YAC9B,aAAa,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,sEAAsE;YACtE,MAAM,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC;QACrB,IAAI,OAAO;YAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAC7C,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/pairing/qr.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/dist/pairing/qr.js
CHANGED
|
@@ -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
|
-
|
|
48
|
-
export function buildQRUri(token, longtermEdPk,
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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();
|
package/dist/pairing/qr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qr.js","sourceRoot":"","sources":["../../src/pairing/qr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,UAAU,MAAM,iBAAiB,CAAC;AAEzC,
|
|
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
|
|
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 {};
|