@yefengr/remote-pi 0.7.4 → 0.7.5
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
package/docs/daemon.md
CHANGED
|
@@ -1,64 +1,31 @@
|
|
|
1
|
-
# Daemon mode — troubleshooting
|
|
1
|
+
# Daemon mode — operations and troubleshooting
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Each scenario starts with the symptom you'd actually observe, followed by
|
|
5
|
-
likely causes and how to fix.
|
|
3
|
+
Daemon mode is an explicit v2-registry opt-in for keeping selected Pi endpoints alive under one user-level supervisor. It is not part of ordinary interactive pairing.
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## 1. `remote-pi install` fails
|
|
5
|
+
Each registration has an opaque daemon/endpoint identifier, canonical cwd, display name, creation time, and persisted desired lifecycle:
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
[remote-pi] install failed: Error: supervisor script not found at
|
|
15
|
-
/Users/x/dist/bin/supervisord.js. Run `pnpm build` (dev) or
|
|
16
|
-
`npm install -g @yefengr/remote-pi` (prod) first.
|
|
7
|
+
```text
|
|
8
|
+
running | stopped
|
|
17
9
|
```
|
|
18
10
|
|
|
19
|
-
|
|
20
|
-
exist yet, or from a partial install.
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
# Dev clone:
|
|
24
|
-
cd pi-extension && pnpm build
|
|
25
|
-
|
|
26
|
-
# Production install:
|
|
27
|
-
npm install -g @yefengr/remote-pi # or pnpm install -g @yefengr/remote-pi
|
|
28
|
-
which pi-supervisord # confirm bin is on PATH
|
|
29
|
-
remote-pi install
|
|
30
|
-
```
|
|
11
|
+
A daemon process is a runtime of that stable endpoint. Restarting the daemon creates a new runtime identity without changing the endpoint card selected by the PWA.
|
|
31
12
|
|
|
32
|
-
|
|
13
|
+
---
|
|
33
14
|
|
|
34
|
-
|
|
35
|
-
re-run it and the supervisor unloads the old entry before bootstrapping
|
|
36
|
-
the new one. If it still fails:
|
|
15
|
+
## Install the supervisor once per computer
|
|
37
16
|
|
|
38
17
|
```bash
|
|
39
|
-
|
|
40
|
-
launchctl unload ~/Library/LaunchAgents/dev.remotepi.supervisord.plist 2>/dev/null
|
|
41
|
-
rm ~/Library/LaunchAgents/dev.remotepi.supervisord.plist
|
|
18
|
+
npm install -g @yefengr/remote-pi
|
|
42
19
|
remote-pi install
|
|
43
20
|
```
|
|
44
21
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
Linux without a logged-in graphical session (headless server). On most
|
|
48
|
-
distros `systemctl --user` requires `loginctl enable-linger <user>` so
|
|
49
|
-
the unit survives logout:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
loginctl enable-linger $USER
|
|
53
|
-
systemctl --user daemon-reload
|
|
54
|
-
remote-pi install
|
|
55
|
-
```
|
|
22
|
+
`install` configures `launchd` on macOS or `systemd --user` on Linux, links `remote-pi` and `pi-supervisord`, and starts the service. The service reads the v2 registry from `~/.pi/remote/daemons.json`.
|
|
56
23
|
|
|
57
|
-
|
|
24
|
+
The supervisor launches Pi in RPC mode without passing an extra extension argument. Pi settings are the only source for extension loading, model selection, providers, and tool permissions. Correct Pi settings before registering an unattended daemon.
|
|
58
25
|
|
|
59
|
-
|
|
26
|
+
### Service does not start at login
|
|
60
27
|
|
|
61
|
-
|
|
28
|
+
Check the service first:
|
|
62
29
|
|
|
63
30
|
```bash
|
|
64
31
|
# Linux
|
|
@@ -70,220 +37,137 @@ launchctl list | grep remotepi
|
|
|
70
37
|
tail -100 ~/.pi/remote/supervisord.log
|
|
71
38
|
```
|
|
72
39
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- **`pi: command not found`** in the log — Pi's binary isn't on the
|
|
76
|
-
PATH that the unit inherited. `remote-pi install` captures
|
|
77
|
-
`process.env.PATH` at install time; if you installed Pi *after*
|
|
78
|
-
running install, re-run `remote-pi install` to refresh.
|
|
79
|
-
- **`Cannot find module …`** — the path baked into the unit doesn't
|
|
80
|
-
match where `dist/bin/supervisord.js` actually lives. Happens if you
|
|
81
|
-
uninstalled then reinstalled the package to a different location.
|
|
82
|
-
Fix: `remote-pi uninstall && remote-pi install`.
|
|
83
|
-
- **Permission denied on UDS** — `~/.pi/remote/` exists with wrong
|
|
84
|
-
perms (rare; only happens if you ran `pi` as `sudo` once). Delete
|
|
85
|
-
the dir and let it re-create: `rm -rf ~/.pi/remote && remote-pi install`.
|
|
86
|
-
|
|
87
|
-
### Run the supervisor in the foreground for debugging
|
|
88
|
-
|
|
89
|
-
Bypass systemd/launchd and run it directly so you can see startup
|
|
90
|
-
errors live:
|
|
40
|
+
Common causes:
|
|
91
41
|
|
|
92
|
-
|
|
93
|
-
pi
|
|
94
|
-
|
|
95
|
-
```
|
|
42
|
+
- **`pi: command not found`** — reinstall the service after fixing the PATH seen by the user service.
|
|
43
|
+
- **Missing compiled package files** — build a development clone or reinstall the global package, then run `remote-pi install` again.
|
|
44
|
+
- **Linux user service unavailable after logout** — enable lingering where required by the distribution: `loginctl enable-linger $USER`.
|
|
96
45
|
|
|
97
|
-
|
|
98
|
-
in the unit/plist environment (PATH, HOME) — re-run `remote-pi install`.
|
|
46
|
+
For foreground diagnosis, run `pi-supervisord` in a terminal and stop it with Ctrl-C when done.
|
|
99
47
|
|
|
100
48
|
---
|
|
101
49
|
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
`remote-pi daemon status` shows one row with `state=crashed` and a
|
|
105
|
-
restart count near 4 (the supervisor gives up after exponential
|
|
106
|
-
backoff: 1s, 5s, 30s, 5min).
|
|
107
|
-
|
|
108
|
-
### Step 1 — read the daemon's stderr
|
|
50
|
+
## Register and control daemons
|
|
109
51
|
|
|
110
|
-
|
|
52
|
+
Registering is explicit and starts with desired state `running`:
|
|
111
53
|
|
|
112
54
|
```bash
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
# macOS
|
|
117
|
-
tail -f ~/.pi/remote/supervisord.log | grep '\[/Users/x/Movies\]'
|
|
55
|
+
remote-pi create ~/Projects/backend
|
|
56
|
+
remote-pi daemons
|
|
57
|
+
remote-pi daemon status
|
|
118
58
|
```
|
|
119
59
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
Reproduce the failure with full visibility:
|
|
60
|
+
The supervisor starts the registration immediately when it is online. At a future supervisor start, it restores only registrations whose desired state remains `running`. A stopped registration remains stopped.
|
|
123
61
|
|
|
124
62
|
```bash
|
|
125
|
-
|
|
126
|
-
|
|
63
|
+
remote-pi daemon start <daemon-id>
|
|
64
|
+
remote-pi daemon stop <daemon-id>
|
|
65
|
+
remote-pi daemon restart <daemon-id>
|
|
66
|
+
remote-pi daemon start # every registration
|
|
67
|
+
remote-pi daemon stop # every registration
|
|
68
|
+
remote-pi daemon restart # every registration
|
|
69
|
+
remote-pi remove <daemon-id>
|
|
70
|
+
remote-pi remove-cwd ~/Projects/backend
|
|
127
71
|
```
|
|
128
72
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
- **Local config missing.** `cd` into the daemon's folder and check
|
|
132
|
-
`.pi/remote-pi/config.json` exists with `auto_start_relay: true`.
|
|
133
|
-
Recreate via `remote-pi create <cwd>` (it provisions a default config
|
|
134
|
-
when missing).
|
|
135
|
-
- **Pi extension config drift.** Pi's own settings (model, API keys)
|
|
136
|
-
reset → daemon fails to authenticate to the provider. Run
|
|
137
|
-
`cd <cwd> && pi` interactively to fix.
|
|
138
|
-
- **Port/UDS collision.** Another Pi process is already running in
|
|
139
|
-
that cwd. The cwd-lock should reject the second one, but stale UDS
|
|
140
|
-
sockets sometimes linger; check `lsof ~/.pi/remote/locks/<roomId>.sock`.
|
|
73
|
+
`remove-cwd <cwd>` is idempotent: it succeeds whether or not that cwd currently has a registration. It is safe for external worktree cleanup integrations.
|
|
141
74
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
After fixing the underlying problem, kick the supervisor:
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
remote-pi daemon restart # bounces every daemon
|
|
148
|
-
```
|
|
75
|
+
The browser PWA may show multiple endpoints on the same computer. Pairing is independent for every computer, and revoking a pairing on one computer does not alter another computer's local pairing records.
|
|
149
76
|
|
|
150
77
|
---
|
|
151
78
|
|
|
152
|
-
##
|
|
79
|
+
## Read status as independent dimensions
|
|
153
80
|
|
|
154
|
-
|
|
155
|
-
Most common cause: the daemon never started OR it crashed past the
|
|
156
|
-
retry budget.
|
|
81
|
+
Do not infer health from a single summary label. `remote-pi daemon status` reports:
|
|
157
82
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
83
|
+
| Field | Interpretation |
|
|
84
|
+
|---|---|
|
|
85
|
+
| registration | The persisted registration is present; a missing cwd is marked missing |
|
|
86
|
+
| desired | Persistent operator intent: `running` or `stopped` |
|
|
87
|
+
| process | OS child lifecycle: absent, spawning, running, or exited |
|
|
88
|
+
| runtime | RPC readiness: pending, ready, or failed |
|
|
89
|
+
| relay | Disconnected, connecting, connected, or reconnecting |
|
|
90
|
+
| health | Derived stopped, starting, healthy, degraded, failed, or blocked state |
|
|
163
91
|
|
|
164
|
-
|
|
165
|
-
isn't actually spawning. Possible reasons:
|
|
166
|
-
- Registry empty: `remote-pi daemons` to verify.
|
|
167
|
-
- Child crashes faster than the status check: `daemon status` immediately
|
|
168
|
-
after start may still show `running` for a few seconds before the
|
|
169
|
-
exit event marks it crashed. Re-check 2-3 seconds later.
|
|
92
|
+
A runtime can be ready while the Relay reconnects. That is a **degraded** state, not a reason to restart Pi. The runtime remains available locally and reconnects through its normal transport path.
|
|
170
93
|
|
|
171
|
-
|
|
94
|
+
A deterministic bad configuration, unsupported startup condition, or exhausted retry budget becomes **blocked**. Read `last_error_code`, `last_error_message`, and `startup_stage`, correct the cause, then explicitly start or restart the daemon. The supervisor does not loop forever on a blocked failure.
|
|
172
95
|
|
|
173
|
-
|
|
96
|
+
---
|
|
174
97
|
|
|
175
|
-
|
|
98
|
+
## Missing and moved working directories
|
|
176
99
|
|
|
177
|
-
|
|
100
|
+
The registry records the canonical cwd that existed at registration time. A daemon send to a missing cwd is denied immediately. The supervisor then reconciles stale registrations after bounded confirmation: it stops any child, removes the registration, and prevents later restoration.
|
|
178
101
|
|
|
179
|
-
|
|
180
|
-
(daemons don't show QRs themselves):
|
|
102
|
+
If a project moved, register its new canonical cwd intentionally rather than editing the registry by hand:
|
|
181
103
|
|
|
182
104
|
```bash
|
|
183
|
-
|
|
184
|
-
pi
|
|
185
|
-
> /remote-pi devices # confirm the device is listed
|
|
186
|
-
> /remote-pi stop # stop interactive session — daemon takes over
|
|
187
|
-
remote-pi daemon restart
|
|
105
|
+
remote-pi create /new/path/to/project
|
|
106
|
+
remote-pi remove-cwd /old/path/to/project
|
|
188
107
|
```
|
|
189
108
|
|
|
190
|
-
|
|
109
|
+
A corrupted or pre-v2 registry is an operator-visible error. It is never treated as an empty registry, because doing so could overwrite registrations. Replace the registry only after inspecting and backing up its contents.
|
|
191
110
|
|
|
192
|
-
|
|
193
|
-
agent_name + `~/.pi/remote/config.json` relay). Verify with:
|
|
111
|
+
---
|
|
194
112
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
> /remote-pi status
|
|
199
|
-
```
|
|
113
|
+
## Scheduled prompts
|
|
114
|
+
|
|
115
|
+
Cron schedules prompt delivery; it never starts a daemon. A fire is accepted only when all of these are true:
|
|
200
116
|
|
|
201
|
-
The
|
|
202
|
-
|
|
117
|
+
1. The registration exists and its cwd is present.
|
|
118
|
+
2. Desired lifecycle is `running`.
|
|
119
|
+
3. The RPC runtime is ready.
|
|
120
|
+
4. The daemon is not busy, unless the job uses `--no-skip-busy`.
|
|
203
121
|
|
|
204
122
|
```bash
|
|
205
|
-
remote-pi
|
|
206
|
-
remote-pi
|
|
123
|
+
remote-pi cron add <daemon-id> "0 9 * * 1-5" "Summarize the new PRs" --tz America/Sao_Paulo
|
|
124
|
+
remote-pi cron list
|
|
125
|
+
remote-pi cron run <job-id>
|
|
126
|
+
remote-pi cron disable <job-id>
|
|
127
|
+
remote-pi cron log --tail 20
|
|
207
128
|
```
|
|
208
129
|
|
|
130
|
+
Schedules closer than 60 seconds are rejected. `--tz Area/City` uses a DST-aware timezone. `--catchup` allows one missed fire after supervisor startup. The cron audit at `~/.pi/remote/cron.jsonl` records every acceptance and skip, including desired-stopped, starting, retrying, failed, blocked, missing, disabled, busy, and rejected outcomes.
|
|
131
|
+
|
|
209
132
|
---
|
|
210
133
|
|
|
211
|
-
##
|
|
134
|
+
## Pairing and Relay diagnosis
|
|
212
135
|
|
|
213
|
-
|
|
214
|
-
having created entries.
|
|
136
|
+
Generate a fresh QR from an interactive endpoint:
|
|
215
137
|
|
|
216
|
-
```
|
|
217
|
-
|
|
138
|
+
```text
|
|
139
|
+
/remote-pi pair
|
|
140
|
+
/remote-pi devices
|
|
141
|
+
/remote-pi revoke <shortid>
|
|
218
142
|
```
|
|
219
143
|
|
|
220
|
-
The
|
|
144
|
+
The QR identifies the current endpoint and runtime. In the PWA, check that the expected device and endpoint card are selected. If a daemon was restarted, select its current runtime state and allow the endpoint to reconnect; a Relay reconnect should report degraded health rather than causing a Pi restart.
|
|
221
145
|
|
|
222
|
-
|
|
223
|
-
{
|
|
224
|
-
"daemons": [
|
|
225
|
-
{ "cwd": "/Users/x/Movies" },
|
|
226
|
-
{ "cwd": "/Users/x/Projects/backend" }
|
|
227
|
-
]
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Fix manually if needed (it's a JSON list of `{cwd}` entries), or wipe
|
|
232
|
-
and re-create:
|
|
146
|
+
Confirm both sides use the same Relay URL:
|
|
233
147
|
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
remote-pi
|
|
237
|
-
remote-pi create ~/Projects/backend --name "Backend"
|
|
238
|
-
remote-pi daemon restart
|
|
148
|
+
```text
|
|
149
|
+
/remote-pi config
|
|
150
|
+
/remote-pi set-relay https://relay.example.com
|
|
239
151
|
```
|
|
240
152
|
|
|
153
|
+
After correcting a Relay URL, restart only the affected endpoint if it does not reconnect on its own.
|
|
154
|
+
|
|
241
155
|
---
|
|
242
156
|
|
|
243
|
-
##
|
|
157
|
+
## Logs and reset
|
|
244
158
|
|
|
245
|
-
|
|
159
|
+
| Platform | Command |
|
|
160
|
+
|---|---|
|
|
161
|
+
| Linux | `journalctl --user -u remote-pi-supervisord -f` |
|
|
162
|
+
| macOS | `tail -f ~/.pi/remote/supervisord.log` |
|
|
163
|
+
|
|
164
|
+
For a complete service reset:
|
|
246
165
|
|
|
247
166
|
```bash
|
|
248
|
-
remote-pi uninstall
|
|
249
|
-
|
|
250
|
-
npm uninstall -g remote-pi
|
|
167
|
+
remote-pi uninstall
|
|
168
|
+
npm uninstall -g @yefengr/remote-pi
|
|
251
169
|
npm install -g @yefengr/remote-pi
|
|
252
170
|
remote-pi install
|
|
253
|
-
# Then re-pair + re-create daemons from scratch.
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
This is the "nuke everything" path. After this, the only state left is
|
|
257
|
-
each cwd's `<cwd>/.pi/remote-pi/config.json` — which you can either
|
|
258
|
-
keep (re-create restores the daemon) or delete (full reset).
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## 8. Diagnostic commands cheat-sheet
|
|
263
|
-
|
|
264
|
-
```bash
|
|
265
|
-
# Where is the supervisor's UDS?
|
|
266
|
-
ls -la ~/.pi/remote/supervisor.sock
|
|
267
|
-
|
|
268
|
-
# Talk to the supervisor manually (raw JSONL):
|
|
269
|
-
echo '{"op":"list"}' | nc -U ~/.pi/remote/supervisor.sock
|
|
270
|
-
|
|
271
|
-
# Where are the daemon configs?
|
|
272
|
-
find ~/Projects -name "config.json" -path "*/.pi/remote-pi/*" 2>/dev/null
|
|
273
|
-
|
|
274
|
-
# Where are the cwd locks?
|
|
275
|
-
ls ~/.pi/remote/locks/
|
|
276
|
-
|
|
277
|
-
# Where are the paired devices?
|
|
278
|
-
cat ~/.pi/remote/peers.json
|
|
279
|
-
|
|
280
|
-
# What Pi binary is the supervisor about to spawn?
|
|
281
|
-
remote-pi install --dry-run # (not implemented; check ~/Library/LaunchAgents or systemd unit manually)
|
|
282
|
-
|
|
283
|
-
# Quick liveness check
|
|
284
|
-
remote-pi daemon status
|
|
285
171
|
```
|
|
286
172
|
|
|
287
|
-
|
|
288
|
-
output of `remote-pi daemon status`, the recent supervisor log, and
|
|
289
|
-
the contents of `~/.pi/remote/daemons.json`.
|
|
173
|
+
Uninstalling the service preserves registrations. Remove individual registrations with `remote-pi remove` or `remote-pi remove-cwd`; do not delete registry state unless a deliberate full reset is required.
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yefengr/remote-pi",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"description": "Browser PWA remote control
|
|
7
|
+
"description": "Browser PWA remote control for Pi coding agent endpoints over a Relay.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
@@ -12,6 +12,15 @@
|
|
|
12
12
|
"remote-pi": "dist/index.js",
|
|
13
13
|
"pi-supervisord": "dist/bin/supervisord.js"
|
|
14
14
|
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"dev": "tsx src/index.ts",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"verify": "pnpm typecheck && pnpm test && pnpm build",
|
|
21
|
+
"prepublishOnly": "pnpm verify",
|
|
22
|
+
"publish:npm": "bash ./publish-npm.sh"
|
|
23
|
+
},
|
|
15
24
|
"keywords": [
|
|
16
25
|
"pi",
|
|
17
26
|
"pi-package",
|
|
@@ -21,10 +30,7 @@
|
|
|
21
30
|
"browser",
|
|
22
31
|
"pwa",
|
|
23
32
|
"coding-agent",
|
|
24
|
-
"
|
|
25
|
-
"agent-network",
|
|
26
|
-
"uds",
|
|
27
|
-
"broker",
|
|
33
|
+
"endpoint",
|
|
28
34
|
"qr-pairing",
|
|
29
35
|
"websocket"
|
|
30
36
|
],
|
|
@@ -47,7 +53,6 @@
|
|
|
47
53
|
},
|
|
48
54
|
"files": [
|
|
49
55
|
"dist",
|
|
50
|
-
"skills",
|
|
51
56
|
"service-templates",
|
|
52
57
|
"docs",
|
|
53
58
|
"README.md",
|
|
@@ -56,6 +61,14 @@
|
|
|
56
61
|
"engines": {
|
|
57
62
|
"node": ">=20.0.0"
|
|
58
63
|
},
|
|
64
|
+
"pnpm": {
|
|
65
|
+
"onlyBuiltDependencies": [
|
|
66
|
+
"@google/genai",
|
|
67
|
+
"esbuild",
|
|
68
|
+
"koffi",
|
|
69
|
+
"protobufjs"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
59
72
|
"devDependencies": {
|
|
60
73
|
"@types/node": "^25.8.0",
|
|
61
74
|
"@types/ws": "^8.18.1",
|
|
@@ -67,7 +80,6 @@
|
|
|
67
80
|
"dependencies": {
|
|
68
81
|
"@earendil-works/pi-coding-agent": "^0.79.10",
|
|
69
82
|
"@earendil-works/pi-tui": "^0.79.10",
|
|
70
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
71
83
|
"@napi-rs/keyring": "^1.3.0",
|
|
72
84
|
"@noble/ed25519": "^3.1.0",
|
|
73
85
|
"croner": "^10.0.1",
|
|
@@ -75,13 +87,5 @@
|
|
|
75
87
|
"typebox": "^1.1.38",
|
|
76
88
|
"ws": "^8.21.0",
|
|
77
89
|
"zod": "^4.4.3"
|
|
78
|
-
},
|
|
79
|
-
"scripts": {
|
|
80
|
-
"build": "tsc",
|
|
81
|
-
"typecheck": "tsc --noEmit",
|
|
82
|
-
"dev": "tsx src/index.ts",
|
|
83
|
-
"test": "vitest run",
|
|
84
|
-
"verify": "pnpm typecheck && pnpm test && pnpm build",
|
|
85
|
-
"publish:npm": "pnpm verify && pnpm publish --access public"
|
|
86
90
|
}
|
|
87
|
-
}
|
|
91
|
+
}
|
package/dist/daemon/id.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stable 8-character hex id for a daemon, derived from the cwd it manages.
|
|
3
|
-
*
|
|
4
|
-
* Derivation: `sha256(realpath(cwd))` truncated to 8 hex chars (32 bits ≈
|
|
5
|
-
* 4 billion). Collision risk is negligible at fleet sizes a single user
|
|
6
|
-
* will ever have (<1000 daemons), and 8 hex characters are short enough
|
|
7
|
-
* to type on the CLI (`/remote-pi send a1b2c3d4 "..."`).
|
|
8
|
-
*
|
|
9
|
-
* Same scheme as `roomIdForCwd` in `src/rooms.ts` — but we use hex
|
|
10
|
-
* instead of base64url so the id has no `_`/`-` (cleaner double-click
|
|
11
|
-
* selection in terminals).
|
|
12
|
-
*
|
|
13
|
-
* Symlinks resolve to a single canonical id via `realpath`, so
|
|
14
|
-
* `/Users/x/Movies` and `/Users/x/link-to-Movies` map to the same daemon.
|
|
15
|
-
* Falls back to the raw path when realpath fails (cwd doesn't exist —
|
|
16
|
-
* shouldn't happen in production but covers test sandboxes).
|
|
17
|
-
*
|
|
18
|
-
* plan/41 audit (2026-06-08): this stays **per-cwd** (no name axis). The
|
|
19
|
-
* multiagent-per-folder model (plan/38/41) applies to the App↔Pi room and the
|
|
20
|
-
* mesh address; a *supervisor daemon* is **one per cwd** by design — the
|
|
21
|
-
* registry keys exactly one entry per cwd (`registry.ts`), so a daemon id never
|
|
22
|
-
* needs the name to disambiguate. Decision: leave `daemonIdForCwd` cwd-only.
|
|
23
|
-
*/
|
|
24
|
-
export declare function daemonIdForCwd(cwd: string): string;
|
package/dist/daemon/id.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { realpathSync } from "node:fs";
|
|
3
|
-
/**
|
|
4
|
-
* Stable 8-character hex id for a daemon, derived from the cwd it manages.
|
|
5
|
-
*
|
|
6
|
-
* Derivation: `sha256(realpath(cwd))` truncated to 8 hex chars (32 bits ≈
|
|
7
|
-
* 4 billion). Collision risk is negligible at fleet sizes a single user
|
|
8
|
-
* will ever have (<1000 daemons), and 8 hex characters are short enough
|
|
9
|
-
* to type on the CLI (`/remote-pi send a1b2c3d4 "..."`).
|
|
10
|
-
*
|
|
11
|
-
* Same scheme as `roomIdForCwd` in `src/rooms.ts` — but we use hex
|
|
12
|
-
* instead of base64url so the id has no `_`/`-` (cleaner double-click
|
|
13
|
-
* selection in terminals).
|
|
14
|
-
*
|
|
15
|
-
* Symlinks resolve to a single canonical id via `realpath`, so
|
|
16
|
-
* `/Users/x/Movies` and `/Users/x/link-to-Movies` map to the same daemon.
|
|
17
|
-
* Falls back to the raw path when realpath fails (cwd doesn't exist —
|
|
18
|
-
* shouldn't happen in production but covers test sandboxes).
|
|
19
|
-
*
|
|
20
|
-
* plan/41 audit (2026-06-08): this stays **per-cwd** (no name axis). The
|
|
21
|
-
* multiagent-per-folder model (plan/38/41) applies to the App↔Pi room and the
|
|
22
|
-
* mesh address; a *supervisor daemon* is **one per cwd** by design — the
|
|
23
|
-
* registry keys exactly one entry per cwd (`registry.ts`), so a daemon id never
|
|
24
|
-
* needs the name to disambiguate. Decision: leave `daemonIdForCwd` cwd-only.
|
|
25
|
-
*/
|
|
26
|
-
export function daemonIdForCwd(cwd) {
|
|
27
|
-
let target;
|
|
28
|
-
try {
|
|
29
|
-
target = realpathSync(cwd);
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
target = cwd;
|
|
33
|
-
}
|
|
34
|
-
return createHash("sha256").update(target).digest("hex").slice(0, 8);
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=id.js.map
|
package/dist/daemon/id.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../src/daemon/id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvE,CAAC"}
|
package/dist/mcp/mesh_result.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
export function formatMeshAckResult(to, ack) {
|
|
2
|
-
switch (ack.status) {
|
|
3
|
-
case "received":
|
|
4
|
-
return textResult(`Delivered to ${ack.target ?? to}`);
|
|
5
|
-
case "busy":
|
|
6
|
-
return errorResult(`NOT delivered — "${to}" came back BUSY, which only happens when an ` +
|
|
7
|
-
`OUT-OF-DATE broker leader dropped the message (busy was removed in the ` +
|
|
8
|
-
`current version). Restart the agent that leads the local broker (the ` +
|
|
9
|
-
`oldest Pi/remote-pi process) so it picks up the new build, then resend.`);
|
|
10
|
-
case "denied":
|
|
11
|
-
return errorResult(formatDenied(to, ack));
|
|
12
|
-
case "timeout":
|
|
13
|
-
return errorResult(formatTimeout(to, ack));
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function formatDenied(to, ack) {
|
|
17
|
-
const errorSuffix = ack.error ? ` (${ack.error})` : "";
|
|
18
|
-
if (ack.reason === "not_authorized") {
|
|
19
|
-
return `Relay did not authorize delivery to ${to}${errorSuffix}. ` +
|
|
20
|
-
`Do not blindly retry; verify authorization first.`;
|
|
21
|
-
}
|
|
22
|
-
if (ack.reason === "bad_envelope") {
|
|
23
|
-
return `Relay rejected the envelope for ${to}${errorSuffix}. ` +
|
|
24
|
-
`Do not blindly retry; correct the envelope first.`;
|
|
25
|
-
}
|
|
26
|
-
return `${to} denied the message`;
|
|
27
|
-
}
|
|
28
|
-
function formatTimeout(to, ack) {
|
|
29
|
-
if (ack.reason === "offline") {
|
|
30
|
-
const errorSuffix = ack.error ? ` (${ack.error})` : "";
|
|
31
|
-
return `Immediate Relay offline transport error for ${to}${errorSuffix}; ` +
|
|
32
|
-
`reported as timeout without waiting for an ACK.`;
|
|
33
|
-
}
|
|
34
|
-
return `No ACK from ${to} (timeout) — peer may be offline`;
|
|
35
|
-
}
|
|
36
|
-
function textResult(text) {
|
|
37
|
-
return { content: [{ type: "text", text }] };
|
|
38
|
-
}
|
|
39
|
-
function errorResult(text) {
|
|
40
|
-
return { content: [{ type: "text", text }], isError: true };
|
|
41
|
-
}
|
|
42
|
-
//# sourceMappingURL=mesh_result.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mesh_result.js","sourceRoot":"","sources":["../../src/mcp/mesh_result.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,mBAAmB,CAAC,EAAU,EAAE,GAAc;IAC5D,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;QACnB,KAAK,UAAU;YACb,OAAO,UAAU,CAAC,gBAAgB,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;QACxD,KAAK,MAAM;YACT,OAAO,WAAW,CAChB,oBAAoB,EAAE,+CAA+C;gBACrE,yEAAyE;gBACzE,uEAAuE;gBACvE,yEAAyE,CAC1E,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,WAAW,CAAC,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;QAC5C,KAAK,SAAS;YACZ,OAAO,WAAW,CAAC,aAAa,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,EAAU,EAAE,GAAc;IAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,IAAI,GAAG,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;QACpC,OAAO,uCAAuC,EAAE,GAAG,WAAW,IAAI;YAChE,mDAAmD,CAAC;IACxD,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QAClC,OAAO,mCAAmC,EAAE,GAAG,WAAW,IAAI;YAC5D,mDAAmD,CAAC;IACxD,CAAC;IACD,OAAO,GAAG,EAAE,qBAAqB,CAAC;AACpC,CAAC;AAED,SAAS,aAAa,CAAC,EAAU,EAAE,GAAc;IAC/C,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,+CAA+C,EAAE,GAAG,WAAW,IAAI;YACxE,iDAAiD,CAAC;IACtD,CAAC;IACD,OAAO,eAAe,EAAE,kCAAkC,CAAC;AAC7D,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* MCP server that bridges Claude Code to the remote-pi agent mesh.
|
|
4
|
-
*
|
|
5
|
-
* Spawned by Claude Code as an MCP server subprocess (stdio).
|
|
6
|
-
* Joins the mesh through the shared `MeshNode` abstraction — the SAME
|
|
7
|
-
* composition the Pi extension uses — so Claude is a first-class mesh
|
|
8
|
-
* participant: it can lead the local UDS broker when no Pi/daemon is up,
|
|
9
|
-
* and (as leader) bring up its own cross-PC relay bridge with its own
|
|
10
|
-
* Pi-key. As a follower it rides the existing leader's bridge.
|
|
11
|
-
*
|
|
12
|
-
* Launched by `remote-pi claude` (registers this in Claude's local MCP
|
|
13
|
-
* scope). Args: [--cwd <path>] [--name <agentName>] [--no-bridge]
|
|
14
|
-
* Env: REMOTE_PI_MCP_CWD, REMOTE_PI_MCP_NAME
|
|
15
|
-
*/
|
|
16
|
-
export {};
|