remote-pi 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/actions/handlers.d.ts +116 -0
- package/dist/actions/handlers.js +152 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +25 -0
- package/dist/actions/registry.js +34 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/bin/supervisord.js +43 -1
- package/dist/bin/supervisord.js.map +1 -1
- package/dist/commands/builtin_mirror.d.ts +58 -0
- package/dist/commands/builtin_mirror.js +71 -0
- package/dist/commands/builtin_mirror.js.map +1 -0
- package/dist/commands/list_commands.d.ts +60 -0
- package/dist/commands/list_commands.js +73 -0
- package/dist/commands/list_commands.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +8 -0
- package/dist/daemon/control_protocol.js.map +1 -1
- package/dist/daemon/rpc_child.d.ts +24 -0
- package/dist/daemon/rpc_child.js +41 -2
- package/dist/daemon/rpc_child.js.map +1 -1
- package/dist/daemon/supervisor.d.ts +11 -0
- package/dist/daemon/supervisor.js +56 -4
- package/dist/daemon/supervisor.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +753 -209
- package/dist/index.js.map +1 -1
- package/dist/mcp/mesh_server.d.ts +16 -0
- package/dist/mcp/mesh_server.js +207 -0
- package/dist/mcp/mesh_server.js.map +1 -0
- package/dist/pairing/storage.js +12 -10
- package/dist/pairing/storage.js.map +1 -1
- package/dist/protocol/types.d.ts +103 -0
- package/dist/session/bridge.d.ts +39 -0
- package/dist/session/bridge.js +41 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/mesh_node.d.ts +123 -0
- package/dist/session/mesh_node.js +203 -0
- package/dist/session/mesh_node.js.map +1 -0
- package/dist/session/setup_wizard.d.ts +6 -23
- package/dist/session/setup_wizard.js +6 -15
- package/dist/session/setup_wizard.js.map +1 -1
- package/dist/session/tools.js +0 -6
- package/dist/session/tools.js.map +1 -1
- package/dist/transport/relay_client.d.ts +8 -0
- package/dist/transport/relay_client.js +50 -2
- package/dist/transport/relay_client.js.map +1 -1
- package/package.json +4 -2
- package/skills/claude-agent-network/SKILL.md +239 -0
package/dist/pairing/storage.js
CHANGED
|
@@ -117,24 +117,26 @@ export async function getOrCreateEd25519Keypair() {
|
|
|
117
117
|
if (legacy) {
|
|
118
118
|
const kp = _deserialize(legacy);
|
|
119
119
|
await backend.write(NEW_SERVICE, ACCOUNT, legacy);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
await backend.delete(OLD_SERVICE, ACCOUNT);
|
|
121
|
+
// Silent migration: writing the chat surface would be premature
|
|
122
|
+
// (Pi SDK isn't bound yet at this point in boot) and console
|
|
123
|
+
// output bleeds outside the TUI. The presence of an entry under
|
|
124
|
+
// NEW_SERVICE is itself the audit signal — re-running migration
|
|
125
|
+
// is idempotent and harmless.
|
|
123
126
|
return kp;
|
|
124
127
|
}
|
|
125
128
|
// Neither entry exists — generate and save to new service.
|
|
126
129
|
const fresh = generateEd25519Keypair();
|
|
127
130
|
await backend.write(NEW_SERVICE, ACCOUNT, _serialize(fresh));
|
|
128
|
-
console.info(`[remote-pi] Generated new Pi-secret in keyring "${NEW_SERVICE}"`);
|
|
129
131
|
return fresh;
|
|
130
132
|
}
|
|
131
133
|
catch (err) {
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
// Path B: file fallback (typically headless Linux without a D-Bus
|
|
135
|
+
// session). Silent in the chat panel — for daemon mode, the
|
|
136
|
+
// existence of `~/.pi/remote/identity.json` IS the signal that the
|
|
137
|
+
// keyring path failed. Document this in CLAUDE.md / PROTOCOL.md
|
|
138
|
+
// so headless users know what to look for.
|
|
139
|
+
void err;
|
|
138
140
|
const fromFile = await _readKeypairFromFile();
|
|
139
141
|
if (fromFile)
|
|
140
142
|
return fromFile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/pairing/storage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/pairing/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/protocol/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type ClientMessage = {
|
|
|
8
8
|
type: "user_message";
|
|
9
9
|
id: string;
|
|
10
10
|
text: string;
|
|
11
|
+
images?: WireImage[];
|
|
11
12
|
} | {
|
|
12
13
|
type: "approve_tool";
|
|
13
14
|
id: string;
|
|
@@ -24,7 +25,38 @@ export type ClientMessage = {
|
|
|
24
25
|
type: "session_sync";
|
|
25
26
|
id: string;
|
|
26
27
|
limit?: number;
|
|
28
|
+
} | {
|
|
29
|
+
type: "session_new";
|
|
30
|
+
id: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: "session_compact";
|
|
33
|
+
id: string;
|
|
34
|
+
} | {
|
|
35
|
+
type: "model_set";
|
|
36
|
+
id: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
model_id: string;
|
|
39
|
+
} | {
|
|
40
|
+
type: "thinking_set";
|
|
41
|
+
id: string;
|
|
42
|
+
level: ThinkingLevel;
|
|
43
|
+
} | {
|
|
44
|
+
type: "list_models";
|
|
45
|
+
id: string;
|
|
27
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* Plan/30 — one inline image attachment on a `user_message`. Mirrors the
|
|
49
|
+
* SDK's `ImageContent` ({@link https }) split across the wire: `data` is the
|
|
50
|
+
* base64-encoded (compressed) image bytes, `mime` its content type
|
|
51
|
+
* (e.g. `"image/jpeg"`). The Pi maps `{ data, mime }` → the SDK's
|
|
52
|
+
* `{ type:"image", data, mimeType }` before handing it to the model.
|
|
53
|
+
*/
|
|
54
|
+
export interface WireImage {
|
|
55
|
+
/** Base64-encoded image bytes (compressed app-side). */
|
|
56
|
+
data: string;
|
|
57
|
+
/** MIME type, e.g. `"image/jpeg"`. Maps to the SDK's `mimeType`. */
|
|
58
|
+
mime: string;
|
|
59
|
+
}
|
|
28
60
|
export type Usage = {
|
|
29
61
|
input_tokens: number;
|
|
30
62
|
output_tokens: number;
|
|
@@ -36,6 +68,7 @@ export type SessionHistoryEvent = {
|
|
|
36
68
|
type: "user_input";
|
|
37
69
|
id: string;
|
|
38
70
|
text: string;
|
|
71
|
+
images?: WireImage[];
|
|
39
72
|
} | {
|
|
40
73
|
ts: number;
|
|
41
74
|
type: "tool_request";
|
|
@@ -54,6 +87,11 @@ export type SessionHistoryEvent = {
|
|
|
54
87
|
in_reply_to: string;
|
|
55
88
|
text: string;
|
|
56
89
|
usage?: Usage;
|
|
90
|
+
} | {
|
|
91
|
+
ts: number;
|
|
92
|
+
type: "compaction";
|
|
93
|
+
summary: string;
|
|
94
|
+
tokens_before: number;
|
|
57
95
|
};
|
|
58
96
|
export type ServerMessage = {
|
|
59
97
|
type: "pair_ok";
|
|
@@ -93,6 +131,7 @@ export type ServerMessage = {
|
|
|
93
131
|
type: "user_message";
|
|
94
132
|
id: string;
|
|
95
133
|
text: string;
|
|
134
|
+
images?: WireImage[];
|
|
96
135
|
} | {
|
|
97
136
|
type: "agent_chunk";
|
|
98
137
|
in_reply_to: string;
|
|
@@ -106,6 +145,11 @@ export type ServerMessage = {
|
|
|
106
145
|
in_reply_to: string;
|
|
107
146
|
text: string;
|
|
108
147
|
usage?: Usage;
|
|
148
|
+
} | {
|
|
149
|
+
type: "compaction";
|
|
150
|
+
summary: string;
|
|
151
|
+
tokens_before: number;
|
|
152
|
+
ts?: number;
|
|
109
153
|
} | {
|
|
110
154
|
type: "tool_request";
|
|
111
155
|
tool_call_id: string;
|
|
@@ -138,5 +182,64 @@ export type ServerMessage = {
|
|
|
138
182
|
events: SessionHistoryEvent[];
|
|
139
183
|
eos: boolean;
|
|
140
184
|
truncated: boolean;
|
|
185
|
+
} | {
|
|
186
|
+
type: "action_ok";
|
|
187
|
+
in_reply_to: string;
|
|
188
|
+
action: ActionName;
|
|
189
|
+
} | {
|
|
190
|
+
type: "action_error";
|
|
191
|
+
in_reply_to: string;
|
|
192
|
+
action: ActionName;
|
|
193
|
+
error: string;
|
|
194
|
+
} | {
|
|
195
|
+
type: "models_list";
|
|
196
|
+
in_reply_to: string;
|
|
197
|
+
models: WireModel[];
|
|
198
|
+
current?: WireModel;
|
|
141
199
|
};
|
|
200
|
+
/**
|
|
201
|
+
* Plan/28 — Stable names for the typed actions the app can request. Kept
|
|
202
|
+
* as a closed string union so a switch in either side gets exhaustiveness
|
|
203
|
+
* checking from the compiler.
|
|
204
|
+
*/
|
|
205
|
+
export type ActionName = "session_new" | "session_compact" | "model_set" | "thinking_set";
|
|
206
|
+
/**
|
|
207
|
+
* Plan/28 — Mirror of the SDK's `ThinkingLevel` (defined in
|
|
208
|
+
* `@mariozechner/pi-agent-core/types`). Re-declared locally so the wire
|
|
209
|
+
* protocol owns its own enum and we don't leak SDK-internal types onto
|
|
210
|
+
* the app's network surface.
|
|
211
|
+
*
|
|
212
|
+
* Note: `"xhigh"` is only honored by select model families — the SDK uses
|
|
213
|
+
* each `Model.thinkingLevelMap` to decide if the requested level is
|
|
214
|
+
* supported, falling back to a sensible neighbour when not. The app
|
|
215
|
+
* surfaces all 6 buttons but can grey out unsupported ones using the
|
|
216
|
+
* model's metadata if the picker fetches it later.
|
|
217
|
+
*/
|
|
218
|
+
export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
219
|
+
/**
|
|
220
|
+
* Plan/28 — Wire shape for one model entry in the app's model picker.
|
|
221
|
+
*
|
|
222
|
+
* Subset of the SDK's `Model<Api>` interface — only the fields the app
|
|
223
|
+
* actually renders. Cost / max-tokens / API class are left off the wire
|
|
224
|
+
* deliberately; if the app's picker grows to need them, they get added
|
|
225
|
+
* here and to the handler's mapping in `index.ts` in one diff.
|
|
226
|
+
*/
|
|
227
|
+
export interface WireModel {
|
|
228
|
+
/** Stable identifier inside the provider's catalog. E.g. `"claude-opus-4-7"`. */
|
|
229
|
+
id: string;
|
|
230
|
+
/** Display name for the picker row. E.g. `"Claude Opus 4.7"`. */
|
|
231
|
+
name: string;
|
|
232
|
+
/** Provider slug. E.g. `"anthropic"`, `"openai"`. */
|
|
233
|
+
provider: string;
|
|
234
|
+
/** Whether the model supports the thinking surface (`reasoning: true`
|
|
235
|
+
* in the SDK). Useful so the app can decide whether the thinking
|
|
236
|
+
* segmented control should be enabled when this model is selected. */
|
|
237
|
+
reasoning: boolean;
|
|
238
|
+
/** Context window in tokens, for display in the picker subtitle. */
|
|
239
|
+
context_window: number;
|
|
240
|
+
/** Plan/30: true when the model accepts image input (SDK `Model.input`
|
|
241
|
+
* includes `"image"`). The app uses it to enable/disable the attach
|
|
242
|
+
* button — a text-only model greys out image attachments. */
|
|
243
|
+
vision: boolean;
|
|
244
|
+
}
|
|
142
245
|
export type ByeReason = "peer_stop" | "session_replaced" | "shutdown";
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { Ed25519Keypair } from "../pairing/crypto.js";
|
|
6
|
+
/**
|
|
7
|
+
* Cross-PC mesh bridge composition — the single shared point for "turn a
|
|
8
|
+
* leader Broker + relay into a cross-PC router".
|
|
9
|
+
*
|
|
10
|
+
* Both consumers call this so the wiring lives in one place:
|
|
11
|
+
* - The Pi extension (`_ensureBrokerRemote`) injects its relay — the SAME
|
|
12
|
+
* RelayClient it also uses for app↔Pi pairing.
|
|
13
|
+
* - The MCP `MeshNode` creates its own RelayClient and passes it in.
|
|
14
|
+
*
|
|
15
|
+
* The function does NOT own the relay's lifecycle (the caller created it and
|
|
16
|
+
* tears it down). It only attaches the PiForwardClient + BrokerRemote on top.
|
|
17
|
+
*
|
|
18
|
+
* Sibling discovery is best-effort: on any failure we attach a BrokerRemote
|
|
19
|
+
* with an empty sibling set, and remote `peers_update` pushes fill the cache
|
|
20
|
+
* in later. Discovery warnings are routed to the silent `log` so they never
|
|
21
|
+
* bleed into a Pi TUI chat panel.
|
|
22
|
+
*/
|
|
23
|
+
export interface AttachBridgeOptions {
|
|
24
|
+
/** The leader's local Broker (from SessionPeer.localBroker()). */
|
|
25
|
+
broker: Broker;
|
|
26
|
+
/** Live relay connection. Caller owns its lifecycle. */
|
|
27
|
+
relay: RelayClient;
|
|
28
|
+
/** Relay URL in http(s):// form — for MeshClient sibling discovery. */
|
|
29
|
+
relayUrl: string;
|
|
30
|
+
/** This host's Ed25519 identity (machine Pi-key). */
|
|
31
|
+
keypair: Ed25519Keypair;
|
|
32
|
+
/** Diagnostic logger. Defaults to a no-op (avoids TUI leaks). */
|
|
33
|
+
log?: (msg: string) => void;
|
|
34
|
+
}
|
|
35
|
+
export interface CrossPcBridge {
|
|
36
|
+
brokerRemote: BrokerRemote;
|
|
37
|
+
piForward: PiForwardClient;
|
|
38
|
+
}
|
|
39
|
+
export declare function attachCrossPcBridge(opts: AttachBridgeOptions): Promise<CrossPcBridge>;
|
|
@@ -0,0 +1,41 @@
|
|
|
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 { discoverSelfLabel, discoverSiblings, fallbackLabel } from "../mesh/siblings.js";
|
|
5
|
+
import { listOwnerPubkeys } from "../pairing/storage.js";
|
|
6
|
+
export async function attachCrossPcBridge(opts) {
|
|
7
|
+
const log = opts.log ?? (() => { });
|
|
8
|
+
const piForward = new PiForwardClient(opts.relay);
|
|
9
|
+
const selfPubkeyB64 = Buffer.from(opts.keypair.publicKey).toString("base64");
|
|
10
|
+
let selfPcLabel = fallbackLabel(selfPubkeyB64);
|
|
11
|
+
let siblings = [];
|
|
12
|
+
try {
|
|
13
|
+
const meshClient = new MeshClient(opts.relayUrl);
|
|
14
|
+
const owners = await listOwnerPubkeys();
|
|
15
|
+
if (owners.length > 0) {
|
|
16
|
+
// Silent log: per-Owner fetch failures (relay 404 before any Owner
|
|
17
|
+
// published, transient HTTP errors) must not surface in a TUI.
|
|
18
|
+
const silent = { warn: (_m) => { } };
|
|
19
|
+
const [labelRes, sibs] = await Promise.all([
|
|
20
|
+
discoverSelfLabel({ client: meshClient, ownerEpks: owners, myPubkey: opts.keypair.publicKey, log: silent }),
|
|
21
|
+
discoverSiblings({ client: meshClient, ownerEpks: owners, myPubkey: opts.keypair.publicKey, log: silent }),
|
|
22
|
+
]);
|
|
23
|
+
selfPcLabel = labelRes.selfPcLabel;
|
|
24
|
+
siblings = sibs;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
// Best-effort — siblings populate later via remote peers_update push.
|
|
29
|
+
void err;
|
|
30
|
+
}
|
|
31
|
+
const brokerRemote = new BrokerRemote({
|
|
32
|
+
broker: opts.broker,
|
|
33
|
+
pi: piForward,
|
|
34
|
+
selfPcLabel,
|
|
35
|
+
selfPcPubkey: selfPubkeyB64,
|
|
36
|
+
siblings,
|
|
37
|
+
log,
|
|
38
|
+
});
|
|
39
|
+
return { brokerRemote, piForward };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/session/bridge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAuCzD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAyB;IACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAS,EAAE,GAAE,CAAC,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAElD,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC7E,IAAI,WAAW,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAC/C,IAAI,QAAQ,GAA4C,EAAE,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;QACxC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,mEAAmE;YACnE,+DAA+D;YAC/D,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAU,EAAQ,EAAE,GAAgB,CAAC,EAAE,CAAC;YAChE,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACzC,iBAAiB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;gBAC3G,gBAAgB,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;aAC3G,CAAC,CAAC;YACH,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;YACnC,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,sEAAsE;QACtE,KAAK,GAAG,CAAC;IACX,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC;QACpC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,EAAE,EAAE,SAAS;QACb,WAAW;QACX,YAAY,EAAE,aAAa;QAC3B,QAAQ;QACR,GAAG;KACJ,CAAC,CAAC;IAEH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SessionPeer, type AckResult } from "./peer.js";
|
|
2
|
+
import type { Envelope } from "./envelope.js";
|
|
3
|
+
import type { Broker } from "./broker.js";
|
|
4
|
+
import { RelayClient } from "../transport/relay_client.js";
|
|
5
|
+
import type { Ed25519Keypair } from "./../pairing/crypto.js";
|
|
6
|
+
/**
|
|
7
|
+
* MeshNode — the single composition point for "join the agent mesh".
|
|
8
|
+
*
|
|
9
|
+
* Wraps the two layers every mesh participant needs, and nothing else
|
|
10
|
+
* (pairing is app↔Pi and stays OUT of here):
|
|
11
|
+
*
|
|
12
|
+
* 1. **Local UDS mesh** — always. A `SessionPeer` joins (or leads) the
|
|
13
|
+
* broker at `sockPath`: `send` / `sendWithAck` / `request` /
|
|
14
|
+
* `onMessage`, leader election + failover for free.
|
|
15
|
+
*
|
|
16
|
+
* 2. **Cross-PC relay bridge** — optional, only when the node leads (the
|
|
17
|
+
* leader hosts the Broker, so it owns the `BrokerRemote`). Two ways to
|
|
18
|
+
* supply the relay:
|
|
19
|
+
* - **Self-managed** (MCP): pass `bridge: { relayUrl, cwd }` and the
|
|
20
|
+
* node creates + owns the RelayClient on connect-if-leader, with
|
|
21
|
+
* its own machine Pi-key.
|
|
22
|
+
* - **Injected** (Pi extension): call `attachBridge({ relay, … })`
|
|
23
|
+
* with the RelayClient the host already owns (and also uses for
|
|
24
|
+
* app↔Pi pairing). MeshNode never closes an injected relay.
|
|
25
|
+
*
|
|
26
|
+
* Both the Pi extension and the MCP mesh server build on this so the mesh
|
|
27
|
+
* wiring lives in one place. A follower never brings the bridge up —
|
|
28
|
+
* cross-PC routing works transitively through whoever is leader (a Pi, the
|
|
29
|
+
* daemon, or another MeshNode). On UDS failover that promotes this node to
|
|
30
|
+
* leader, the bridge re-attaches automatically against the fresh broker.
|
|
31
|
+
*/
|
|
32
|
+
/** Self-managed-relay bridge config (MCP path). */
|
|
33
|
+
export interface MeshSelfRelayBridge {
|
|
34
|
+
/** Relay URL in http(s):// form (converted to ws(s):// internally). */
|
|
35
|
+
relayUrl: string;
|
|
36
|
+
/** cwd — derives the relay room id and the room_meta. */
|
|
37
|
+
cwd: string;
|
|
38
|
+
/** Display name for room_meta. Defaults to the assigned mesh name. */
|
|
39
|
+
sessionName?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface MeshNodeOptions {
|
|
42
|
+
/** UDS broker socket path (e.g. ~/.pi/remote/sessions/local/broker.sock). */
|
|
43
|
+
sockPath: string;
|
|
44
|
+
/** Requested mesh name (broker may add a #N collision suffix). */
|
|
45
|
+
name: string;
|
|
46
|
+
/** Optional audit log path passed through to SessionPeer. */
|
|
47
|
+
auditPath?: string;
|
|
48
|
+
/** Self-managed relay bridge — brought up if this node leads. */
|
|
49
|
+
bridge?: MeshSelfRelayBridge;
|
|
50
|
+
/** Diagnostic logger. Defaults to a no-op (avoids leaking into TUIs). */
|
|
51
|
+
log?: (msg: string) => void;
|
|
52
|
+
}
|
|
53
|
+
export type { AckResult } from "./peer.js";
|
|
54
|
+
interface SiblingInfo {
|
|
55
|
+
pcLabel: string;
|
|
56
|
+
pcPubkey: string;
|
|
57
|
+
}
|
|
58
|
+
export declare class MeshNode {
|
|
59
|
+
private readonly peer_;
|
|
60
|
+
private readonly log;
|
|
61
|
+
private relay;
|
|
62
|
+
private relayOwned;
|
|
63
|
+
private brokerRemote;
|
|
64
|
+
private piForward;
|
|
65
|
+
private keypair;
|
|
66
|
+
private bridgeParams;
|
|
67
|
+
private reconnectWired;
|
|
68
|
+
constructor(opts: MeshNodeOptions);
|
|
69
|
+
/** Join (or lead) the mesh. Resolves with the assigned name. */
|
|
70
|
+
connect(): Promise<string>;
|
|
71
|
+
/**
|
|
72
|
+
* Attach a cross-PC bridge on top of an EXTERNALLY-owned relay (Pi path).
|
|
73
|
+
* Idempotent; only attaches when this node is the leader. Remembers the
|
|
74
|
+
* params so the bridge re-attaches after a UDS failover. Call again with a
|
|
75
|
+
* fresh relay after a relay reconnect.
|
|
76
|
+
*/
|
|
77
|
+
attachBridge(opts: {
|
|
78
|
+
relay: RelayClient;
|
|
79
|
+
relayUrl: string;
|
|
80
|
+
keypair?: Ed25519Keypair;
|
|
81
|
+
}): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Tear down the bridge AND forget its params (no auto re-attach until the
|
|
84
|
+
* next `attachBridge`/`connect`). Closes the relay only if MeshNode created
|
|
85
|
+
* it — an injected relay belongs to the host. Use on stop / relay drop.
|
|
86
|
+
*/
|
|
87
|
+
detachBridge(): void;
|
|
88
|
+
private _wireReconnect;
|
|
89
|
+
private _onReconnect;
|
|
90
|
+
private _maybeBridge;
|
|
91
|
+
private _detachBridgeKeepingParams;
|
|
92
|
+
/** Keep the cross-PC sibling set in sync (Pi SelfRevoke onMembersChanged). */
|
|
93
|
+
setSiblings(siblings: SiblingInfo[]): void;
|
|
94
|
+
/** Announce the local peer set to siblings (Pi broker peer_joined/left). */
|
|
95
|
+
onLocalPeersChanged(local: string[]): void;
|
|
96
|
+
/** True when the cross-PC relay bridge is active (this node is leader). */
|
|
97
|
+
hasBridge(): boolean;
|
|
98
|
+
/** The underlying SessionPeer — for consumers that need it directly (tools). */
|
|
99
|
+
peer(): SessionPeer;
|
|
100
|
+
/** Fire-and-forget send. `to` may be a name, `<pc>:<name>`, or "broadcast". */
|
|
101
|
+
send(to: string | string[], body: unknown, re?: string | null): Promise<void>;
|
|
102
|
+
/** Unicast send + await broker ACK (received/busy/denied/timeout). */
|
|
103
|
+
sendWithAck(to: string, body: unknown, re?: string | null, timeoutMs?: number): Promise<AckResult>;
|
|
104
|
+
/** Send + await the first reply whose `re` matches the outbound id. */
|
|
105
|
+
request(to: string, body: unknown, timeoutMs?: number): Promise<Envelope>;
|
|
106
|
+
/** Subscribe to inbound envelopes. Returns an unsubscribe fn. */
|
|
107
|
+
onMessage(handler: (env: Envelope) => void): () => void;
|
|
108
|
+
/** Subscribe to post-failover reconnects. Returns an unsubscribe fn. */
|
|
109
|
+
onReconnect(handler: () => void): () => void;
|
|
110
|
+
/** Assigned mesh name (after any #N collision suffix). */
|
|
111
|
+
name(): string;
|
|
112
|
+
/** "leader" | "follower". */
|
|
113
|
+
currentRole(): "leader" | "follower";
|
|
114
|
+
/** The locally-hosted Broker when leader, else null. */
|
|
115
|
+
localBroker(): Broker | null;
|
|
116
|
+
/**
|
|
117
|
+
* Aggregated mesh roster (local UDS peers + cross-PC `<pc>:<peer>`),
|
|
118
|
+
* excluding self. Asks the broker, which merges its remote router cache.
|
|
119
|
+
*/
|
|
120
|
+
listPeers(timeoutMs?: number): Promise<string[]>;
|
|
121
|
+
/** Tear down the bridge (if any) and leave the mesh. */
|
|
122
|
+
close(): Promise<void>;
|
|
123
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { SessionPeer } from "./peer.js";
|
|
2
|
+
import { RelayClient } from "../transport/relay_client.js";
|
|
3
|
+
import { attachCrossPcBridge } from "./bridge.js";
|
|
4
|
+
import { getOrCreateEd25519Keypair } from "../pairing/storage.js";
|
|
5
|
+
import { roomIdForCwd } from "../rooms.js";
|
|
6
|
+
import { toWebSocketUrl } from "../config.js";
|
|
7
|
+
export class MeshNode {
|
|
8
|
+
peer_;
|
|
9
|
+
log;
|
|
10
|
+
relay = null;
|
|
11
|
+
relayOwned = false;
|
|
12
|
+
brokerRemote = null;
|
|
13
|
+
piForward = null;
|
|
14
|
+
keypair = null;
|
|
15
|
+
bridgeParams = null;
|
|
16
|
+
reconnectWired = false;
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
this.log = opts.log ?? (() => { });
|
|
19
|
+
const peerOpts = { sockPath: opts.sockPath, name: opts.name };
|
|
20
|
+
if (opts.auditPath !== undefined)
|
|
21
|
+
peerOpts.auditPath = opts.auditPath;
|
|
22
|
+
this.peer_ = new SessionPeer(peerOpts);
|
|
23
|
+
if (opts.bridge) {
|
|
24
|
+
const p = { relayUrl: opts.bridge.relayUrl, cwd: opts.bridge.cwd };
|
|
25
|
+
if (opts.bridge.sessionName !== undefined)
|
|
26
|
+
p.sessionName = opts.bridge.sessionName;
|
|
27
|
+
this.bridgeParams = p;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Join (or lead) the mesh. Resolves with the assigned name. */
|
|
31
|
+
async connect() {
|
|
32
|
+
const name = await this.peer_.start();
|
|
33
|
+
this._wireReconnect();
|
|
34
|
+
if (this.bridgeParams)
|
|
35
|
+
await this._maybeBridge();
|
|
36
|
+
return name;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Attach a cross-PC bridge on top of an EXTERNALLY-owned relay (Pi path).
|
|
40
|
+
* Idempotent; only attaches when this node is the leader. Remembers the
|
|
41
|
+
* params so the bridge re-attaches after a UDS failover. Call again with a
|
|
42
|
+
* fresh relay after a relay reconnect.
|
|
43
|
+
*/
|
|
44
|
+
async attachBridge(opts) {
|
|
45
|
+
const p = { relayUrl: opts.relayUrl, injectedRelay: opts.relay };
|
|
46
|
+
if (opts.keypair !== undefined)
|
|
47
|
+
p.keypair = opts.keypair;
|
|
48
|
+
this.bridgeParams = p;
|
|
49
|
+
this._wireReconnect();
|
|
50
|
+
await this._maybeBridge();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Tear down the bridge AND forget its params (no auto re-attach until the
|
|
54
|
+
* next `attachBridge`/`connect`). Closes the relay only if MeshNode created
|
|
55
|
+
* it — an injected relay belongs to the host. Use on stop / relay drop.
|
|
56
|
+
*/
|
|
57
|
+
detachBridge() {
|
|
58
|
+
this._detachBridgeKeepingParams();
|
|
59
|
+
this.bridgeParams = null;
|
|
60
|
+
}
|
|
61
|
+
// ── Bridge internals ────────────────────────────────────────────────────────
|
|
62
|
+
_wireReconnect() {
|
|
63
|
+
if (this.reconnectWired)
|
|
64
|
+
return;
|
|
65
|
+
this.reconnectWired = true;
|
|
66
|
+
// SessionPeer.onReconnect fires only after a UDS re-election (failover),
|
|
67
|
+
// not on relay events. On failover the broker reference changes, so drop
|
|
68
|
+
// the stale bridge and re-attach against the fresh localBroker().
|
|
69
|
+
this.peer_.onReconnect(() => { void this._onReconnect(); });
|
|
70
|
+
}
|
|
71
|
+
async _onReconnect() {
|
|
72
|
+
if (!this.bridgeParams)
|
|
73
|
+
return;
|
|
74
|
+
this._detachBridgeKeepingParams();
|
|
75
|
+
await this._maybeBridge();
|
|
76
|
+
}
|
|
77
|
+
async _maybeBridge() {
|
|
78
|
+
if (this.brokerRemote)
|
|
79
|
+
return;
|
|
80
|
+
if (this.peer_.currentRole() !== "leader")
|
|
81
|
+
return;
|
|
82
|
+
const broker = this.peer_.localBroker();
|
|
83
|
+
if (!broker)
|
|
84
|
+
return;
|
|
85
|
+
const params = this.bridgeParams;
|
|
86
|
+
if (!params)
|
|
87
|
+
return;
|
|
88
|
+
let relay;
|
|
89
|
+
if (params.injectedRelay) {
|
|
90
|
+
relay = params.injectedRelay;
|
|
91
|
+
this.relayOwned = false;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (!this.keypair)
|
|
95
|
+
this.keypair = params.keypair ?? (await getOrCreateEd25519Keypair());
|
|
96
|
+
const roomId = roomIdForCwd(params.cwd);
|
|
97
|
+
const roomMeta = { name: params.sessionName ?? this.peer_.name(), cwd: params.cwd };
|
|
98
|
+
const r = new RelayClient(toWebSocketUrl(params.relayUrl), this.keypair);
|
|
99
|
+
try {
|
|
100
|
+
await r.connect({ roomId, roomMeta });
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
// UDS mesh still works; cross-PC stays unavailable until a leader
|
|
104
|
+
// with a healthy relay appears.
|
|
105
|
+
this.log(`mesh bridge: relay connect failed: ${String(err)}`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
relay = r;
|
|
109
|
+
this.relayOwned = true;
|
|
110
|
+
}
|
|
111
|
+
this.relay = relay;
|
|
112
|
+
if (!this.keypair)
|
|
113
|
+
this.keypair = params.keypair ?? (await getOrCreateEd25519Keypair());
|
|
114
|
+
const { brokerRemote, piForward } = await attachCrossPcBridge({
|
|
115
|
+
broker,
|
|
116
|
+
relay,
|
|
117
|
+
relayUrl: params.relayUrl,
|
|
118
|
+
keypair: this.keypair,
|
|
119
|
+
log: this.log,
|
|
120
|
+
});
|
|
121
|
+
this.brokerRemote = brokerRemote;
|
|
122
|
+
this.piForward = piForward;
|
|
123
|
+
}
|
|
124
|
+
_detachBridgeKeepingParams() {
|
|
125
|
+
this.brokerRemote?.detach();
|
|
126
|
+
this.brokerRemote = null;
|
|
127
|
+
this.piForward?.detach();
|
|
128
|
+
this.piForward = null;
|
|
129
|
+
if (this.relayOwned)
|
|
130
|
+
this.relay?.close();
|
|
131
|
+
this.relay = null;
|
|
132
|
+
this.relayOwned = false;
|
|
133
|
+
}
|
|
134
|
+
// ── Bridge passthroughs (no-op when no bridge / follower) ───────────────────
|
|
135
|
+
/** Keep the cross-PC sibling set in sync (Pi SelfRevoke onMembersChanged). */
|
|
136
|
+
setSiblings(siblings) {
|
|
137
|
+
this.brokerRemote?.setSiblings(siblings);
|
|
138
|
+
}
|
|
139
|
+
/** Announce the local peer set to siblings (Pi broker peer_joined/left). */
|
|
140
|
+
onLocalPeersChanged(local) {
|
|
141
|
+
this.brokerRemote?.onLocalPeersChanged(local);
|
|
142
|
+
}
|
|
143
|
+
/** True when the cross-PC relay bridge is active (this node is leader). */
|
|
144
|
+
hasBridge() {
|
|
145
|
+
return this.brokerRemote !== null;
|
|
146
|
+
}
|
|
147
|
+
// ── Mesh API (delegates to SessionPeer) ─────────────────────────────────────
|
|
148
|
+
/** The underlying SessionPeer — for consumers that need it directly (tools). */
|
|
149
|
+
peer() {
|
|
150
|
+
return this.peer_;
|
|
151
|
+
}
|
|
152
|
+
/** Fire-and-forget send. `to` may be a name, `<pc>:<name>`, or "broadcast". */
|
|
153
|
+
async send(to, body, re = null) {
|
|
154
|
+
return this.peer_.send(to, body, re);
|
|
155
|
+
}
|
|
156
|
+
/** Unicast send + await broker ACK (received/busy/denied/timeout). */
|
|
157
|
+
async sendWithAck(to, body, re = null, timeoutMs) {
|
|
158
|
+
return timeoutMs === undefined
|
|
159
|
+
? this.peer_.sendWithAck(to, body, re)
|
|
160
|
+
: this.peer_.sendWithAck(to, body, re, timeoutMs);
|
|
161
|
+
}
|
|
162
|
+
/** Send + await the first reply whose `re` matches the outbound id. */
|
|
163
|
+
async request(to, body, timeoutMs) {
|
|
164
|
+
return timeoutMs === undefined
|
|
165
|
+
? this.peer_.request(to, body)
|
|
166
|
+
: this.peer_.request(to, body, timeoutMs);
|
|
167
|
+
}
|
|
168
|
+
/** Subscribe to inbound envelopes. Returns an unsubscribe fn. */
|
|
169
|
+
onMessage(handler) {
|
|
170
|
+
return this.peer_.onMessage(handler);
|
|
171
|
+
}
|
|
172
|
+
/** Subscribe to post-failover reconnects. Returns an unsubscribe fn. */
|
|
173
|
+
onReconnect(handler) {
|
|
174
|
+
return this.peer_.onReconnect(handler);
|
|
175
|
+
}
|
|
176
|
+
/** Assigned mesh name (after any #N collision suffix). */
|
|
177
|
+
name() {
|
|
178
|
+
return this.peer_.name();
|
|
179
|
+
}
|
|
180
|
+
/** "leader" | "follower". */
|
|
181
|
+
currentRole() {
|
|
182
|
+
return this.peer_.currentRole();
|
|
183
|
+
}
|
|
184
|
+
/** The locally-hosted Broker when leader, else null. */
|
|
185
|
+
localBroker() {
|
|
186
|
+
return this.peer_.localBroker();
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Aggregated mesh roster (local UDS peers + cross-PC `<pc>:<peer>`),
|
|
190
|
+
* excluding self. Asks the broker, which merges its remote router cache.
|
|
191
|
+
*/
|
|
192
|
+
async listPeers(timeoutMs = 2_000) {
|
|
193
|
+
const reply = await this.peer_.request("broker", { type: "list_peers" }, timeoutMs);
|
|
194
|
+
const body = reply.body;
|
|
195
|
+
return (body?.peers ?? []).filter((p) => p !== this.peer_.name());
|
|
196
|
+
}
|
|
197
|
+
/** Tear down the bridge (if any) and leave the mesh. */
|
|
198
|
+
async close() {
|
|
199
|
+
this.detachBridge();
|
|
200
|
+
await this.peer_.leave();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=mesh_node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_node.js","sourceRoot":"","sources":["../../src/session/mesh_node.ts"],"names":[],"mappings":"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"}
|