remote-pi 0.2.1 → 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 (44) 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 +749 -208
  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/protocol/types.d.ts +103 -0
  31. package/dist/session/bridge.d.ts +39 -0
  32. package/dist/session/bridge.js +41 -0
  33. package/dist/session/bridge.js.map +1 -0
  34. package/dist/session/mesh_node.d.ts +123 -0
  35. package/dist/session/mesh_node.js +203 -0
  36. package/dist/session/mesh_node.js.map +1 -0
  37. package/dist/session/setup_wizard.d.ts +6 -23
  38. package/dist/session/setup_wizard.js +6 -15
  39. package/dist/session/setup_wizard.js.map +1 -1
  40. package/dist/transport/relay_client.d.ts +8 -0
  41. package/dist/transport/relay_client.js +50 -2
  42. package/dist/transport/relay_client.js.map +1 -1
  43. package/package.json +4 -2
  44. package/skills/claude-agent-network/SKILL.md +239 -0
@@ -1 +1 @@
1
- {"version":3,"file":"setup_wizard.js","sourceRoot":"","sources":["../../src/session/setup_wizard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup_wizard.js","sourceRoot":"","sources":["../../src/session/setup_wizard.ts"],"names":[],"mappings":"AAqBA,MAAM,GAAG,GAAG,KAAK,CAAC;AAClB,MAAM,EAAE,GAAG,IAAI,CAAC;AAChB,MAAM,YAAY,GAAG,YAAY,CAAC;AAElC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAY,EACZ,QAAwB;IAExB,MAAM,UAAU,GAAG,MAAM,QAAQ,CAC/B,EAAE,EACF,aAAa,EACb,QAAQ,CAAC,UAAU,CACpB,CAAC;IACF,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAErC,EAAE,CAAC,MAAM,EAAE,CACT,6JAA6J,EAC7J,MAAM,CACP,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,MAAM,CACpC,8EAA8E,EAC9E,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAC3C,CAAC;IACF,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,gBAAgB,GAAG,cAAc,KAAK,GAAG,CAAC;IAEhD,mBAAmB;IACnB,MAAM,OAAO,GAAG;QACd,oBAAoB,UAAU,EAAE;QAChC,oBAAoB,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;KAClD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACjE,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAEjC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,QAAQ,CACrB,EAAY,EACZ,KAAa,EACb,YAAoB;IAEpB,MAAM,aAAa,GAAG,GAAG,KAAK,cAAc,YAAY,GAAG,CAAC;IAC5D,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK;QAClB,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,CAAC;QACjD,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IACjE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,GAAG,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,wEAAwE;IACxE,0DAA0D;IAC1D,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;AACrD,CAAC"}
@@ -49,6 +49,9 @@ export declare class RelayClient extends EventEmitter {
49
49
  private readonly url;
50
50
  private readonly keypair;
51
51
  private ws;
52
+ /** Epoch ms of the last inbound frame (message / relay ping / pong). */
53
+ private lastActivityAt;
54
+ private livenessTimer;
52
55
  constructor(url: string, keypair: Ed25519Keypair);
53
56
  /**
54
57
  * Connects and completes Ed25519 auth. Resolves when relay is ready.
@@ -74,6 +77,11 @@ export declare class RelayClient extends EventEmitter {
74
77
  */
75
78
  sendControl(frame: object): void;
76
79
  close(): void;
80
+ /** Force-close the WS when no inbound frame has arrived for
81
+ * `LIVENESS_TIMEOUT_MS` — see the constant's doc for why. `terminate()`
82
+ * fires `close`, which the owner turns into a reconnect. */
83
+ private _startLiveness;
84
+ private _stopLiveness;
77
85
  private _authenticate;
78
86
  /** Waits for the next single WS message with a timeout. */
79
87
  private _nextMsg;
@@ -2,6 +2,17 @@ import { EventEmitter } from "node:events";
2
2
  import WebSocket from "ws";
3
3
  import { ed25519Sign } from "../pairing/crypto.js";
4
4
  const AUTH_TIMEOUT_MS = 5_000;
5
+ /**
6
+ * Liveness watchdog. The relay sends a WS Ping every ~25s (relay `peer.rs`),
7
+ * so a healthy connection sees inbound frames at least that often. If NOTHING
8
+ * arrives for this long the socket is silently dead — NAT/router idle drop,
9
+ * laptop sleep, or the relay/Cloudflare reaping the connection WITHOUT a clean
10
+ * close frame. That half-open case never fires `close`, so reconnect never
11
+ * triggers and a background daemon sits "online" but dead after a few idle
12
+ * hours. We force-close on timeout so `close` drives the caller's reconnect.
13
+ */
14
+ const LIVENESS_TIMEOUT_MS = 70_000; // ~2.8 missed relay pings → confidently dead
15
+ const LIVENESS_CHECK_MS = 20_000;
5
16
  /** Relay rejected hello because another peer already holds (pubkey, room_id). */
6
17
  export class RoomAlreadyOpenError extends Error {
7
18
  roomId;
@@ -32,6 +43,9 @@ export class RelayClient extends EventEmitter {
32
43
  url;
33
44
  keypair;
34
45
  ws = null;
46
+ /** Epoch ms of the last inbound frame (message / relay ping / pong). */
47
+ lastActivityAt = 0;
48
+ livenessTimer = null;
35
49
  constructor(url, keypair) {
36
50
  super();
37
51
  this.url = url;
@@ -59,8 +73,12 @@ export class RelayClient extends EventEmitter {
59
73
  ws.on("open", async () => {
60
74
  try {
61
75
  await this._authenticate(ws, options);
62
- // Auth done — wire persistent message handler
76
+ // Auth done — wire persistent message handler. Every inbound frame
77
+ // (data, plus the relay's keepalive ping/pong below) refreshes the
78
+ // liveness clock.
79
+ this.lastActivityAt = Date.now();
63
80
  ws.on("message", (raw) => {
81
+ this.lastActivityAt = Date.now();
64
82
  const text = Buffer.isBuffer(raw) ? raw.toString() : String(raw);
65
83
  for (const line of text.split("\n")) {
66
84
  const trimmed = line.trim();
@@ -68,7 +86,17 @@ export class RelayClient extends EventEmitter {
68
86
  this.emit("message", trimmed);
69
87
  }
70
88
  });
71
- ws.on("close", () => this.emit("close"));
89
+ // The relay pings every ~25s; `ws` auto-replies Pong (keeping the
90
+ // relay's view of us alive). The relay ignores client pings rather
91
+ // than ponging, so these inbound pings — not a ping/pong we initiate
92
+ // — are our liveness signal.
93
+ ws.on("ping", () => { this.lastActivityAt = Date.now(); });
94
+ ws.on("pong", () => { this.lastActivityAt = Date.now(); });
95
+ ws.on("close", () => {
96
+ this._stopLiveness();
97
+ this.emit("close");
98
+ });
99
+ this._startLiveness(ws);
72
100
  resolve();
73
101
  }
74
102
  catch (err) {
@@ -97,9 +125,29 @@ export class RelayClient extends EventEmitter {
97
125
  this.ws.send(JSON.stringify(frame));
98
126
  }
99
127
  close() {
128
+ this._stopLiveness();
100
129
  this.ws?.close();
101
130
  this.ws = null;
102
131
  }
132
+ // ── Liveness watchdog ─────────────────────────────────────────────────────
133
+ /** Force-close the WS when no inbound frame has arrived for
134
+ * `LIVENESS_TIMEOUT_MS` — see the constant's doc for why. `terminate()`
135
+ * fires `close`, which the owner turns into a reconnect. */
136
+ _startLiveness(ws) {
137
+ this._stopLiveness();
138
+ this.livenessTimer = setInterval(() => {
139
+ if (Date.now() - this.lastActivityAt > LIVENESS_TIMEOUT_MS) {
140
+ this._stopLiveness();
141
+ ws.terminate();
142
+ }
143
+ }, LIVENESS_CHECK_MS);
144
+ }
145
+ _stopLiveness() {
146
+ if (this.livenessTimer) {
147
+ clearInterval(this.livenessTimer);
148
+ this.livenessTimer = null;
149
+ }
150
+ }
103
151
  // ── Auth ────────────────────────────────────────────────────────────────────
104
152
  async _authenticate(ws, opts) {
105
153
  const pubkeyB64 = Buffer.from(this.keypair.publicKey).toString("base64");
@@ -1 +1 @@
1
- {"version":3,"file":"relay_client.js","sourceRoot":"","sources":["../../src/transport/relay_client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relay_client.js","sourceRoot":"","sources":["../../src/transport/relay_client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remote-pi",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "Mobile remote control and local agent mesh for the Pi coding agent. Pair your phone via QR over a relay, watch tool calls in real time, run multi-Pi sessions over a local Unix Domain Socket broker, and let agents talk to each other through structured request/reply.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -76,10 +76,12 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@mariozechner/pi-coding-agent": "^0.73.1",
79
+ "@modelcontextprotocol/sdk": "^1.29.0",
79
80
  "@napi-rs/keyring": "^1.3.0",
80
81
  "@noble/ed25519": "^3.1.0",
81
82
  "qrcode-terminal": "^0.12.0",
82
83
  "typebox": "^1.1.38",
83
- "ws": "^8.20.1"
84
+ "ws": "^8.20.1",
85
+ "zod": "^4.4.3"
84
86
  }
85
87
  }
@@ -0,0 +1,239 @@
1
+ ---
2
+ name: agent-network
3
+ description: Use when the remote-pi mesh tools (`list_peers`, `agent_send`, `get_messages`) are available — you are a Claude agent connected to the remote-pi agent mesh over a local broker. This skill teaches how to discover who's online (`list_peers`), how to send messages with delivery status (`agent_send` + ACK), how incoming messages arrive (`get_messages` at the start of each turn, plus channel push), how to reply (echo `re`), and how cross-PC addressing works (`<pc_label>:<peer>`).
4
+ ---
5
+
6
+ # Agent Network (Claude ↔ remote-pi mesh)
7
+
8
+ You are connected to the **remote-pi agent mesh** through an MCP server.
9
+ Other agents — other Claude sessions, Pi coding agents on this machine, and
10
+ agents on the Owner's other PCs (via the relay) — can send you messages, and
11
+ you can send messages to them.
12
+
13
+ Read this to the end before acting. The protocol is **event-driven**, not
14
+ request/reply. Getting the receive model wrong leaves coordination broken.
15
+
16
+ You have exactly three tools: `list_peers`, `agent_send`, `get_messages`.
17
+
18
+ ---
19
+
20
+ ## The most important rule: check your inbox every turn
21
+
22
+ Incoming messages are buffered for you. **At the start of every turn, call
23
+ `get_messages`** to drain and read anything other agents sent you:
24
+
25
+ ```
26
+ get_messages()
27
+ → "[2026-05-30T12:00:01Z] from=backend re=<your-id>
28
+ id=<msg-id>
29
+ { "shape": { "sub": "string", "exp": "number" } }"
30
+ ```
31
+
32
+ - Returns all pending messages and clears the buffer (call once per turn).
33
+ - Returns `(no messages)` when nothing is waiting — that's normal, keep working.
34
+ - A channel push may also surface a message mid-session (a `📨 Message from …`
35
+ notification). When it does, still call `get_messages` to get the full,
36
+ structured payload (`from`, `id`, `re`, `body`) — the push is just a nudge.
37
+
38
+ **If a message arrived, someone wanted your attention. Don't ignore it.**
39
+ You only ever receive messages addressed to you — the broker filters before
40
+ delivery.
41
+
42
+ ---
43
+
44
+ ## First thing in a new session: `list_peers`
45
+
46
+ Before sending anything, find out who's actually online:
47
+
48
+ ```
49
+ list_peers()
50
+ → backend
51
+ frontend
52
+ casa:agent-1
53
+ trab:worker
54
+ ```
55
+
56
+ Synchronous (resolves in milliseconds — not another agent's turn). Use it:
57
+
58
+ - At the start of a session, to see what mesh you're in
59
+ - Before any `agent_send` whose target name is uncertain
60
+ - After a while, to refresh (peers join/leave over time)
61
+
62
+ **Entry shape:**
63
+ - `backend` → local peer (this machine, same broker)
64
+ - `casa:agent-1` → cross-PC peer on the PC labeled `casa` (the Owner's other
65
+ machine, reached through the relay)
66
+
67
+ You are excluded from the result — no need to filter yourself out.
68
+
69
+ ---
70
+
71
+ ## Anatomy of a message (envelope)
72
+
73
+ `get_messages` shows you, per message: `from`, `id`, `re`, and `body`.
74
+
75
+ | Field | Meaning |
76
+ |---|---|
77
+ | `from` | Who sent it. Use this verbatim as your `to` when replying. |
78
+ | `id` | Unique id of this message. Echo it as `re` when you reply. |
79
+ | `re` | If set, this message is itself a REPLY to an earlier `id` of yours. |
80
+ | `body` | Free-form content — string or JSON, sender's choice. |
81
+
82
+ ---
83
+
84
+ ## Sending: `agent_send` returns an ACK status
85
+
86
+ `agent_send({ to, body, re? })` is how you talk to peers. Every **unicast**
87
+ call returns a status telling you what happened at the recipient. **Always
88
+ inspect the status — it dictates what to do next.**
89
+
90
+ | Status | Means | What you do |
91
+ |---|---|---|
92
+ | `received` | Peer was idle; broker delivered the envelope; peer will process it on its next turn. | Move on. Any reply arrives later — check `get_messages` on future turns. |
93
+ | `busy` | Peer is mid-turn — envelope **dropped**. | Retry 2× with backoff (~2s, ~5s). Still busy → abandon or escalate. You own the retry. |
94
+ | `denied` | Peer explicitly refused. | Do NOT retry. Report to the user. |
95
+ | `timeout` | No ACK (~5s). Transport error — broker down, or peer vanished. | Treat as transient. Retry once after ~10s, then escalate. |
96
+
97
+ For `to: "broadcast"`, there's no single ACK — it's fire-and-forget
98
+ ("Broadcast sent").
99
+
100
+ **Replies bypass the busy gate.** A message with `re=<some-id>` (an answer to
101
+ something the recipient asked) is always delivered — it resolves their pending
102
+ state instead of starting a new turn. So if you fan out questions to several
103
+ peers, every reply reaches you even while they're busy.
104
+
105
+ ---
106
+
107
+ ## Receiving: replies arrive on a later turn
108
+
109
+ You **do not block** waiting for a reply. The model is event-driven:
110
+
111
+ 1. You call `agent_send` → status `received`.
112
+ 2. Your turn continues / ends.
113
+ 3. **Later** the peer finishes its own work and sends a reply.
114
+ 4. The reply lands in your inbox. You see it the next time you call
115
+ `get_messages`, with `re` set to the `id` you originally sent.
116
+
117
+ No wait/sleep/poll-loop. Just call `get_messages` at the start of your turns.
118
+
119
+ ### Walk-through
120
+
121
+ ```
122
+ agent_send({ to: "backend", body: { q: "what's the JWT shape?" } })
123
+ → Delivered to backend # status received; remember the message id
124
+ ```
125
+
126
+ Your turn continues. A turn or two later:
127
+
128
+ ```
129
+ get_messages()
130
+ → "[…] from=backend re=<your-id>
131
+ id=<new-id>
132
+ { "shape": { "sub": "string", "exp": "number", "roles": ["string"] } }"
133
+ ```
134
+
135
+ You correlate by `re` — it matches the send you made. Now you have your answer.
136
+
137
+ ---
138
+
139
+ ## Replying to a message
140
+
141
+ When you receive (via `get_messages`):
142
+
143
+ ```
144
+ from=orchestrator id=abc-uuid re=(none)
145
+ { "task": "Implement POST /auth/login" }
146
+ ```
147
+
148
+ Reply with `re` set to that `id`, and `to` set to the sender's `from`:
149
+
150
+ ```
151
+ agent_send({
152
+ to: "orchestrator",
153
+ body: { status: "done", files_changed: [...] },
154
+ re: "abc-uuid"
155
+ })
156
+ ```
157
+
158
+ Without `re`, the sender gets your message but can't match it to the
159
+ question — coordination drifts. **Always echo `re` on a reply.**
160
+
161
+ ---
162
+
163
+ ## Asking multiple peers at once
164
+
165
+ Fire multiple `agent_send` in one turn — each returns its own ACK. Replies
166
+ arrive on future turns as peers finish.
167
+
168
+ ```
169
+ agent_send({ to: "backend", body: { q: "JWT shape?" } }) // received
170
+ agent_send({ to: "frontend", body: { q: "theme tokens?" } }) // received
171
+ agent_send({ to: "infra", body: { q: "ETA for Y?" } }) // busy — retry
172
+ ```
173
+
174
+ Track which `id` maps to which question. Don't assume replies arrive in send
175
+ order — use `re` to identify what each reply answers.
176
+
177
+ ---
178
+
179
+ ## Cross-PC addressing (`<pc_label>:<peer>`)
180
+
181
+ When the Owner has paired multiple PCs, remote peers appear with a prefix:
182
+
183
+ ```
184
+ list_peers() → backend frontend casa:agent-1 trab:worker
185
+ ```
186
+
187
+ Send to a remote peer with the prefixed name verbatim:
188
+
189
+ ```
190
+ agent_send({ to: "casa:agent-1", body: { ... } })
191
+ ```
192
+
193
+ The relay routes it across the mesh; `received | busy | denied | timeout`
194
+ semantics are identical to local. When you **reply** to a cross-PC message,
195
+ use the sender's `from` verbatim (it already carries the prefix) as your `to`.
196
+ You never prefix your own name — the broker handles that.
197
+
198
+ Cross-PC failure notes:
199
+ - `denied` → the remote broker has no peer by that name (left, or stale cache
200
+ → call `list_peers` again).
201
+ - `timeout` → the other PC is offline or the relay is unreachable.
202
+
203
+ ---
204
+
205
+ ## Broadcast and multicast
206
+
207
+ - `to: "broadcast"` → every other peer. Use for announcements
208
+ ("wave 2 started"), never for questions (replies would be uncorrelated).
209
+ - Broadcast skips ACK — you don't know who received it. For delivery
210
+ confirmation, use individual unicast sends.
211
+
212
+ ---
213
+
214
+ ## When in doubt
215
+
216
+ - **Received a task you don't understand** → reply with `body.status:"error"`,
217
+ echoing the original `id` in `re`. Don't go silent.
218
+ - **Received a `re` you never sent** → late reply to something already wrapped
219
+ up. Ignore. Don't reply to a reply.
220
+ - **No messages ever arrive** → normal. You only receive when addressed. Keep
221
+ working; just keep calling `get_messages` each turn.
222
+ - **`timeout` on send** → broker restarting (failover) or peer vanished. Retry
223
+ once after ~10s, then escalate.
224
+
225
+ ---
226
+
227
+ ## Single-page summary
228
+
229
+ 1. **Every turn**: `get_messages()` first — drain your inbox.
230
+ 2. **Discover**: `list_peers()` → locals + `<pc>:<peer>` cross-PC. Synchronous.
231
+ 3. **Send**: `agent_send({to, body, re?})` → inspect the status.
232
+ 4. **Unicast status**: `received | busy | denied | timeout`. Retry on `busy`
233
+ (backoff); abandon on `denied`; investigate on `timeout`.
234
+ 5. **Broadcast**: fire-and-forget, no ACK.
235
+ 6. **Reply**: set `re` to their `id`, `to` to their `from` (prefix and all).
236
+ 7. You never receive your own messages. The broker does not queue — if a peer
237
+ is busy, your message is dropped; you own the retry.
238
+
239
+ Re-read when in doubt.