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.
Files changed (48) hide show
  1. package/README.md +44 -0
  2. package/dist/actions/handlers.d.ts +116 -0
  3. package/dist/actions/handlers.js +152 -0
  4. package/dist/actions/handlers.js.map +1 -0
  5. package/dist/actions/registry.d.ts +25 -0
  6. package/dist/actions/registry.js +34 -0
  7. package/dist/actions/registry.js.map +1 -0
  8. package/dist/bin/supervisord.js +43 -1
  9. package/dist/bin/supervisord.js.map +1 -1
  10. package/dist/commands/builtin_mirror.d.ts +58 -0
  11. package/dist/commands/builtin_mirror.js +71 -0
  12. package/dist/commands/builtin_mirror.js.map +1 -0
  13. package/dist/commands/list_commands.d.ts +60 -0
  14. package/dist/commands/list_commands.js +73 -0
  15. package/dist/commands/list_commands.js.map +1 -0
  16. package/dist/daemon/control_protocol.d.ts +8 -0
  17. package/dist/daemon/control_protocol.js.map +1 -1
  18. package/dist/daemon/rpc_child.d.ts +24 -0
  19. package/dist/daemon/rpc_child.js +41 -2
  20. package/dist/daemon/rpc_child.js.map +1 -1
  21. package/dist/daemon/supervisor.d.ts +11 -0
  22. package/dist/daemon/supervisor.js +56 -4
  23. package/dist/daemon/supervisor.js.map +1 -1
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +753 -209
  26. package/dist/index.js.map +1 -1
  27. package/dist/mcp/mesh_server.d.ts +16 -0
  28. package/dist/mcp/mesh_server.js +207 -0
  29. package/dist/mcp/mesh_server.js.map +1 -0
  30. package/dist/pairing/storage.js +12 -10
  31. package/dist/pairing/storage.js.map +1 -1
  32. package/dist/protocol/types.d.ts +103 -0
  33. package/dist/session/bridge.d.ts +39 -0
  34. package/dist/session/bridge.js +41 -0
  35. package/dist/session/bridge.js.map +1 -0
  36. package/dist/session/mesh_node.d.ts +123 -0
  37. package/dist/session/mesh_node.js +203 -0
  38. package/dist/session/mesh_node.js.map +1 -0
  39. package/dist/session/setup_wizard.d.ts +6 -23
  40. package/dist/session/setup_wizard.js +6 -15
  41. package/dist/session/setup_wizard.js.map +1 -1
  42. package/dist/session/tools.js +0 -6
  43. package/dist/session/tools.js.map +1 -1
  44. package/dist/transport/relay_client.d.ts +8 -0
  45. package/dist/transport/relay_client.js +50 -2
  46. package/dist/transport/relay_client.js.map +1 -1
  47. package/package.json +4 -2
  48. package/skills/claude-agent-network/SKILL.md +239 -0
@@ -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
- const deleted = await backend.delete(OLD_SERVICE, ACCOUNT);
121
- console.info(`[remote-pi] Migrated Pi-secret from "${OLD_SERVICE}" to "${NEW_SERVICE}" ` +
122
- `(old entry deleted: ${deleted})`);
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
- // ── Path B: file fallback (typically headless Linux) ───────────────
133
- console.warn("[remote-pi] WARNING: keyring unavailable, falling back to file-based " +
134
- "storage at " + IDENTITY_FILE + " (mode 0600). Set up GNOME Keyring/" +
135
- "KWallet for better security. " +
136
- `Set PI_KEY_INSECURE_FALLBACK=true to suppress this warning. ` +
137
- `Cause: ${String(err)}`);
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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"}
@@ -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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"}