miki-moni 0.3.1

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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +283 -0
  3. package/README.zh-CN.md +275 -0
  4. package/README.zh-TW.md +275 -0
  5. package/bin/miki.mjs +49 -0
  6. package/dist/web/assets/favicon-DFpLtP36.svg +13 -0
  7. package/dist/web/assets/index--89DkyV1.css +1 -0
  8. package/dist/web/assets/index-CyPlxvOn.js +64 -0
  9. package/dist/web/index.html +20 -0
  10. package/dist/web/pair-info.html +138 -0
  11. package/dist/web-phone/assets/app-CyQWCdKZ.js +64 -0
  12. package/dist/web-phone/assets/index-D5BUh7Uf.js +1 -0
  13. package/dist/web-phone/assets/index-D8vY_9ld.css +1 -0
  14. package/dist/web-phone/index.html +20 -0
  15. package/hooks/miki-emit.ps1 +56 -0
  16. package/package.json +89 -0
  17. package/shared/i18n.ts +915 -0
  18. package/src/cli/i18n-cli.ts +149 -0
  19. package/src/cli/miki.ts +168 -0
  20. package/src/cli/pair.ts +534 -0
  21. package/src/cli/prompt.ts +6 -0
  22. package/src/cli/pushable-iter.ts +45 -0
  23. package/src/cli/setup-self-host.ts +292 -0
  24. package/src/cli/setup-wizard.ts +130 -0
  25. package/src/cli/wrap.ts +742 -0
  26. package/src/config.ts +121 -0
  27. package/src/crypto.ts +66 -0
  28. package/src/data-dir.ts +31 -0
  29. package/src/ext-registry.ts +47 -0
  30. package/src/hook-handler.ts +86 -0
  31. package/src/index.ts +279 -0
  32. package/src/install-hooks.ts +107 -0
  33. package/src/notifier.ts +21 -0
  34. package/src/pairing.ts +100 -0
  35. package/src/protocol-ext.ts +46 -0
  36. package/src/relay-client.ts +468 -0
  37. package/src/relay-protocol.ts +57 -0
  38. package/src/server.ts +1134 -0
  39. package/src/session-resolver.ts +437 -0
  40. package/src/session-store.ts +131 -0
  41. package/src/types.ts +33 -0
  42. package/src/vscode-bridge.ts +407 -0
  43. package/src/wrap-process.ts +183 -0
  44. package/tools/tray.ps1 +286 -0
  45. package/worker/package.json +24 -0
  46. package/worker/src/daemon-relay.ts +348 -0
  47. package/worker/src/env.ts +11 -0
  48. package/worker/src/handshake.ts +63 -0
  49. package/worker/src/index.ts +81 -0
  50. package/worker/src/pairing-code.ts +39 -0
  51. package/worker/src/pairing-coordinator.ts +145 -0
  52. package/worker/wrangler-selfhost.toml +36 -0
  53. package/worker/wrangler.toml +29 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WarmBed / Miki-Moni contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,283 @@
1
+ # Miki-Moni
2
+
3
+ **[English](README.md) · [繁體中文](README.zh-TW.md) · [简体中文](README.zh-CN.md)**
4
+
5
+ > 巫女 (Miki the Monitor) — watches your Claude Code sessions and pings you when one needs attention.
6
+
7
+ Aggregate the state of every VSCode Claude Code panel into a single local dashboard. Connect to it from your phone or another laptop through an end-to-end encrypted relay.
8
+
9
+ <p align="center">
10
+ <img src="docs/images/dashboard-desktop.png" width="800" alt="Desktop dashboard — session cards with live transcript">
11
+ <br />
12
+ <em>Desktop dashboard at <code>http://127.0.0.1:8765</code></em>
13
+ </p>
14
+
15
+ <table>
16
+ <tr>
17
+ <td align="center" width="33%">
18
+ <img src="docs/images/dashboard-phone.png" width="280" alt="Phone dashboard — same content, single-column mobile layout">
19
+ <br /><em>Phone dashboard (mobile viewport)</em>
20
+ </td>
21
+ <td align="center" width="33%">
22
+ <img src="docs/images/phone-pair-screen.png" width="280" alt="Phone pairing screen — QR scan + 16-char code">
23
+ <br /><em>Phone pairing screen — scan QR or type code</em>
24
+ </td>
25
+ <td align="center" width="33%">
26
+ <img src="docs/images/cli-banner.png" width="280" alt="CLI banner — miki start prints QR + URL + 16-char code on startup">
27
+ <br /><em><code>miki start</code> prints QR + URL + code on every startup</em>
28
+ </td>
29
+ </tr>
30
+ </table>
31
+
32
+ ---
33
+
34
+ ## Why
35
+
36
+ - Three Claude Code panels open across two VSCode windows. One finishes; you don't notice for 20 minutes.
37
+ - You walk away from your desk; you want to peek at "did it finish yet?" from your phone without VPN-ing in.
38
+ - A teammate's machine has the project loaded; you want a read-only view from yours.
39
+
40
+ Miki-Moni gives you **one dashboard** that aggregates every Claude Code session (across windows, projects, machines) and lets you respond from anywhere.
41
+
42
+ **Resume any session from any terminal.** Started a session in VSCode and your editor crashed? Closed the wrong window? Switched to a different terminal? Every session — VSCode-spawned or CLI-spawned — is resumable with its **full context** by running `miki claude -r <session-uuid>`. The dashboard exposes a one-click *Open CLI* button on each session card; from your phone, just keep prompting the same session through the relay. No more "I lost my Claude context" — the session UUID is the durable handle, not the window that started it.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ npm install -g miki-moni
48
+ miki start
49
+ ```
50
+
51
+ Or from source (for contributing / unreleased changes):
52
+
53
+ ```bash
54
+ git clone https://github.com/WarmBed/Miki-Moni
55
+ cd Miki-Moni
56
+ pnpm install
57
+ pnpm build:all
58
+ pnpm link --global # makes `miki` available on PATH
59
+ miki start
60
+ ```
61
+
62
+ On first run, a setup wizard asks:
63
+
64
+ 1. **Language** — English / 繁體中文 / 简体中文
65
+ 2. **Relay mode** — pick one:
66
+ - **Hosted** (default) — uses the author's free `relay.f1telemetrystationpro.org`. Zero setup.
67
+ - **Self-host** — auto-deploys a Cloudflare Worker + Pages site to *your* CF account (needs `wrangler`).
68
+ - **Local-only** — no phone access; dashboard at `127.0.0.1:8765` only.
69
+
70
+ Then it prints a permanent pairing QR + 16-char code:
71
+
72
+ ```
73
+ 📱 Phone pairing — scan QR, open URL, or type the 16-char code:
74
+
75
+ [QR code]
76
+
77
+ URL: https://miki-moni.pages.dev/#t=XXXX...&r=wss://...
78
+ Code: XXXX-XXXX-XXXX-XXXX
79
+ Local: http://127.0.0.1:8765
80
+ (QR / URL / Code are permanent — rotate with `miki pair --rotate`)
81
+ ```
82
+
83
+ That QR works permanently — scan once on each device you want to pair. Rotate when leaked.
84
+
85
+ ## Three deployment modes
86
+
87
+ | | Hosted | Self-host | Local-only |
88
+ |---|---|---|---|
89
+ | **Setup** | 0 sec | ~5 min wizard | 0 sec |
90
+ | **Needs CF account** | No | Yes | No |
91
+ | **Phone access** | Yes | Yes | No |
92
+ | **Trust author's infra** | Yes ([§ Security](#security)) | No | N/A |
93
+ | **Bandwidth limits** | Author's CF free tier (100k req/day) | Your CF free tier | N/A |
94
+ | **Rotate later** | `miki setup` | `miki setup` | `miki setup` |
95
+
96
+ ## Architecture
97
+
98
+ ```
99
+ ┌──────────────────────────────────────────────────────────────────────────┐
100
+ │ │
101
+ │ ╭─ Your machine ────────────────────────────────────────────────────╮ │
102
+ │ │ │ │
103
+ │ │ miki-moni daemon (Node, 127.0.0.1:8765) │ │
104
+ │ │ POST /event GET /sessions POST /focus /send WS /ws │ │
105
+ │ │ │ │
106
+ │ │ ▲ ▲ ▲ │ │
107
+ │ │ PS hooks web dashboard RelayClient │ │
108
+ │ │ (~/.claude/ (browser at 127.0.0.1) │ │
109
+ │ │ settings.json) │ │
110
+ │ ╰────────────────────────────────────────────────────┬──────────────╯ │
111
+ │ │ E2E encrypted │
112
+ │ │ envelope │
113
+ │ ╭────────────▼─────────────╮ │
114
+ │ │ Cloudflare Worker relay │ │
115
+ │ │ (zero-knowledge: routes │ │
116
+ │ │ encrypted blobs only) │ │
117
+ │ ╰────────────┬─────────────╯ │
118
+ │ │ E2E encrypted │
119
+ │ ▼ │
120
+ │ ╭──────────────────────────╮ │
121
+ │ │ Phone / 2nd laptop / │ │
122
+ │ │ tablet (web PWA) │ │
123
+ │ │ · scans QR → auto-pair │ │
124
+ │ │ · sees same dashboard │ │
125
+ │ ╰──────────────────────────╯ │
126
+ └──────────────────────────────────────────────────────────────────────────┘
127
+ ```
128
+
129
+ **Encryption**: X25519 ECDH at pair time → per-peer shared secret → NaCl `secretbox` on every envelope. The relay never holds keys; only the daemon and the paired phone can read content.
130
+
131
+ **Auth**: each phone holds an Ed25519 signing keypair (in IndexedDB). On reconnect, it signs `daemon_id || utc_minute` — relay verifies before routing. Revoke per-device with `miki pair --revoke <peer_id>`.
132
+
133
+ ## Dashboard features
134
+
135
+ Top bar:
136
+
137
+ | | What it does |
138
+ |---|---|
139
+ | **Counters** (`5 active · 0 idle · 56 total`) | Click to filter the grid to that status (click again to clear) |
140
+ | **➕ New CLI** | Open a new wrapped Claude session in a fresh folder (`miki claude --fresh`) |
141
+ | **⚙️ Settings** | Send key (Enter vs Ctrl/⌘+Enter), theme (light/dark), language (en / 繁中 / 简中) |
142
+ | **WS status dot** | Green = receiving live updates · amber = reconnecting |
143
+
144
+ Session cards:
145
+
146
+ | Element | What it does |
147
+ |---|---|
148
+ | **Project name + cwd** | Header — click to expand the card / view full transcript |
149
+ | **🖥️ VSCode / 📟 CLI badge** | Toggles how *send* / *focus* dispatches. **VSCode**: prompt fills the VSCode panel via `vscode://anthropic.claude-code/open?session=…`. **CLI**: prompt goes through the wrap CLI's WebSocket directly. |
150
+ | **Permission badge** (`✏️ auto edit`, `🚀 bypass`) | Only on wrapped CLI sessions started with `--permission-mode acceptEdits` / `--bypass-permissions`. Locked for the session lifetime. |
151
+ | **Transcript view** | Live-rendered Claude turns. Toggle tool calls. Limit slider (10 / 50 / 200 / all). |
152
+ | **Send composer** | Multi-line prompt input. Enter or Ctrl/⌘+Enter to send (per your settings choice). Supports image attachment via paste/drop. |
153
+ | **Open CLI button** ⭐ | **Take over the session from a CLI, with full context.** Spawns `wt.exe` (Windows Terminal) running `miki claude -r <session-uuid>` — Claude resumes from the exact turn the VSCode panel was on. Works regardless of where the session was originally started; the panel can be closed, crashed, or on a different window. Pair with the phone dashboard and you keep prompting the same session from anywhere. |
154
+ | **Focus button** | `POST /focus` — raises the matching VSCode window (or new CLI tab) to foreground. |
155
+
156
+ ## CLI reference
157
+
158
+ | Command | What it does |
159
+ |---|---|
160
+ | `miki start` | Run daemon + print pairing banner. First run launches the setup wizard. |
161
+ | `miki setup` | Re-run the wizard (change language, switch relay mode, etc.) |
162
+ | `miki pair` | Show the current permanent QR + paired-phones list. |
163
+ | `miki pair --rotate` | Generate a new pair token (invalidates the old QR; paired phones keep working). |
164
+ | `miki pair --list` | List paired phones with their IDs + paired timestamps. |
165
+ | `miki pair --revoke <peer_id>` | Remove a phone from local config AND tell the relay to drop it. |
166
+ | `miki pair --new` | One-shot ephemeral token (10 min TTL) — legacy / debugging. |
167
+ | `miki claude [...args]` | Wrap a Claude Code session and auto-spawn the daemon if down. |
168
+ | `miki install-hooks` | Merge Claude Code hooks into `~/.claude/settings.json` so non-wrapped panels show up too. |
169
+
170
+ Verbose daemon logs: `MIKI_LOG_LEVEL=info miki start`. Full trace always in `~/.miki-moni/miki-moni.log`.
171
+
172
+ ## Security
173
+
174
+ ### What the phone can and can't do
175
+
176
+ Designed conservatively to keep the threat model small:
177
+
178
+ | The phone **can** | The phone **cannot** |
179
+ |---|---|
180
+ | See live session state + transcript | Run arbitrary shell commands on your machine |
181
+ | Pre-fill a prompt into a VSCode panel (`/focus`) | Auto-submit a prompt without your VSCode keystroke (Anthropic's design) |
182
+ | Push a prompt through the wrap CLI WebSocket for sessions started with `miki claude` | Spawn new processes or read files outside the session transcript |
183
+ | Trigger a focus on an existing panel | Bypass Claude Code's tool-permission prompts (those still gate every tool call) |
184
+
185
+ ### Trust boundaries
186
+
187
+ The daemon binds **`127.0.0.1` only** — nothing on the public network can reach it, ever. Remote access flows through the encrypted relay, not the local HTTP port.
188
+
189
+ The daemon trusts any process running on the same machine to call `/event`, `/send`, `/focus`, and connect to `/ws_ext`. This is intentional (so Claude Code hooks and the VSCode helper extension don't need a token) but means: **anything that runs as your user can talk to the daemon**. See [`docs/security/hooks-trust-model.md`](docs/security/hooks-trust-model.md) and [`docs/security/extension-ws-trust-model.md`](docs/security/extension-ws-trust-model.md) for the full local-trust analysis and hardening options.
190
+
191
+ ### Risk table
192
+
193
+ Ordered by realism:
194
+
195
+ | Risk | Mitigation |
196
+ |---|---|
197
+ | 🔴 **Pairing QR leaks** (screenshot in chat, photo of screen, posted publicly) | Permanent QR means anyone with it can pair. Treat the QR like an SSH key. Rotate immediately if leaked: `miki pair --rotate`. |
198
+ | 🟡 **Paired phone stolen** | Phone holds an Ed25519 signing key that grants relay access. Revoke from the daemon: `miki pair --revoke <peer_id>`. |
199
+ | 🟡 **Local machine compromised** | The daemon trusts loopback. Any malicious process running as your user can read sessions and intercept prompts via `/ws_ext`. Treat `~/.miki-moni/` (private keys, paired-phone records) like `~/.ssh/`. |
200
+ | 🟢 Brute-force pair token | 16 Crockford base32 chars ≈ 80 bits of entropy. Computationally infeasible. |
201
+ | 🟢 Relay sees content | Zero-knowledge by design — relay only routes opaque ciphertext, never holds shared secrets. |
202
+ | 🟡 You trust the hosted relay operator | Self-host avoids this entirely. The author can see metadata (peer IDs, timing, sizes) and theoretically swap the PWA bundle. Source is open; verify or self-host. |
203
+ | 🟢 DDoS on hosted relay | Cloudflare rate-limit binding caps at 30 req/60s per IP. Worst case: your daily quota burns. |
204
+
205
+ ## Self-host (manual)
206
+
207
+ The `miki setup` wizard automates this end-to-end, but if you prefer manual:
208
+
209
+ ```bash
210
+ # In a cloned cc-hub source tree:
211
+ cd worker
212
+ wrangler login
213
+ wrangler deploy --config wrangler-selfhost.toml --name my-relay
214
+ wrangler pages project create my-phone --production-branch=main
215
+ wrangler pages deploy ../dist/web-phone --project-name my-phone --branch=main
216
+ ```
217
+
218
+ Then edit `~/.miki-moni/config.json`:
219
+
220
+ ```json
221
+ {
222
+ "remote": {
223
+ "worker_url": "wss://my-relay.<your-cf-username>.workers.dev",
224
+ "phone_pwa_url": "https://my-phone.pages.dev/"
225
+ }
226
+ }
227
+ ```
228
+
229
+ `miki start` will pick up the new endpoints on next run.
230
+
231
+ ## Development
232
+
233
+ ```bash
234
+ git clone https://github.com/WarmBed/Miki-Moni
235
+ cd Miki-Moni
236
+ pnpm install
237
+ pnpm typecheck
238
+ pnpm test # daemon + worker test suites
239
+ pnpm dev # tsx watch src/index.ts
240
+ ```
241
+
242
+ Source tree:
243
+
244
+ | Path | Purpose |
245
+ |---|---|
246
+ | `src/` | Node daemon (express + ws + better-sqlite3) — hooks, pairing, RelayClient |
247
+ | `web/` | Desktop / phone full dashboard (Preact + Tailwind + Vite) |
248
+ | `web-phone/` | Phone bootstrap shell (QR scanner + tunnel setup) — mounts web/ |
249
+ | `worker/` | Cloudflare Worker relay (DaemonRelay + PairingCoordinator DOs) |
250
+ | `extension/` | VSCode helper extension — handles `claude-vscode.send` |
251
+ | `hooks/` | Claude Code hook scripts (PowerShell) — POST events to daemon |
252
+ | `bin/miki.mjs` | npm-published CLI entry |
253
+
254
+ ## Branches
255
+
256
+ - `main` — versioned releases (current: v0.0.0)
257
+ - `dev` — active development; every change gets a `package.json` version bump
258
+
259
+ ## Related projects
260
+
261
+ **[Happy](https://happy.engineering)** (`slopus/happy-cli`, MIT) solves an overlapping itch — controlling Claude Code from your phone — from a different angle. Both can coexist on the same machine.
262
+
263
+ | | Miki-Moni | Happy |
264
+ |---|---|---|
265
+ | Primary entry point | VSCode panel — hooks pull every panel into a dashboard | Terminal wrapper that replaces `claude` |
266
+ | Relay | Cloudflare Worker; self-host in ~5 min on your own CF account | Author-hosted socket.io server (`api.cluster-fluster.com`) |
267
+ | Phone client | Web PWA — scan QR, no app install | Native iOS / Android apps |
268
+ | Supported agents | Claude Code | Claude Code, Codex, Gemini, generic ACP |
269
+ | Voice input | — | Yes |
270
+ | Multi-session visual dashboard | Yes — aggregates across windows | Sessions managed independently |
271
+ | Replaces `claude`? | No — hooks in alongside | Yes — spawns `claude` itself |
272
+ | Remote spawn (start a session away from your desk) | — | Yes (`happy daemon`) |
273
+ | End-to-end encrypted relay | Yes (X25519 + NaCl secretbox) | Yes (X25519 + NaCl secretbox + AES-GCM) |
274
+
275
+ Use Happy if you want a polished mobile-first experience across multiple AI agents and don't mind a SaaS relay. Use Miki-Moni if you live in VSCode, want a single dashboard for many parallel panels, or want to self-host the relay on your own CF account in minutes.
276
+
277
+ ## License
278
+
279
+ MIT — see [LICENSE](LICENSE).
280
+
281
+ ## Credits
282
+
283
+ Built with [Anthropic Claude](https://claude.ai/code) via [Claude Code](https://github.com/anthropics/claude-code).
@@ -0,0 +1,275 @@
1
+ # Miki-Moni
2
+
3
+ **[English](README.md) · [繁體中文](README.zh-TW.md) · [简体中文](README.zh-CN.md)**
4
+
5
+ > 巫女 (Miki the Monitor) — 看着你所有 Claude Code session,要回应的时候叫你。
6
+
7
+ 把散落在各个 VSCode 窗口的 Claude Code panel 收进一张本机仪表板,手机或第二台笔电可以通过端对端加密 relay 连进来。
8
+
9
+ <p align="center">
10
+ <img src="docs/images/dashboard-desktop.png" width="800" alt="桌面 dashboard — session 卡片含实时 transcript">
11
+ <br />
12
+ <em>本机 dashboard:<code>http://127.0.0.1:8765</code></em>
13
+ </p>
14
+
15
+ <table>
16
+ <tr>
17
+ <td align="center" width="33%">
18
+ <img src="docs/images/dashboard-phone.png" width="280" alt="手机 dashboard — 同样内容、单列移动版">
19
+ <br /><em>手机 dashboard(移动设备)</em>
20
+ </td>
21
+ <td align="center" width="33%">
22
+ <img src="docs/images/phone-pair-screen.png" width="280" alt="手机配对画面 — 扫 QR + 16 码输入">
23
+ <br /><em>手机配对画面 — 扫 QR 或输入 16 码</em>
24
+ </td>
25
+ <td align="center" width="33%">
26
+ <img src="docs/images/cli-banner.png" width="280" alt="CLI banner — miki start 启动时打印 QR + URL + 16 码">
27
+ <br /><em><code>miki start</code> 每次启动打印 QR + URL + 16 码</em>
28
+ </td>
29
+ </tr>
30
+ </table>
31
+
32
+ ---
33
+
34
+ ## 为什么
35
+
36
+ - 两个 VSCode 窗口开了三个 Claude Code panel,其中一个跑完了,你 20 分钟后才发现
37
+ - 离开桌前想瞥一眼"跑完没?"但不想 VPN 进来
38
+ - 同事机器有项目,你想只读看一眼
39
+
40
+ Miki-Moni 给你**一张 dashboard** 收齐所有 Claude session(跨窗口、跨项目、跨机器),任何地方都能响应。
41
+
42
+ **任何 session 都能从任何 terminal 接管继续做。** VSCode 起的、CLI 起的都一样,editor 崩了、窗口误关、想换个 terminal 继续做 — 一句 `miki claude -r <session-uuid>` 把**完整上下文**接回来。dashboard 每张 session 卡都有一键"Open CLI"按钮;手机端就直接通过 relay 对同一个 session 继续打字。再也不会"Claude 上下文掉了" — session UUID 是耐用的把手,不是起它的那个窗口。
43
+
44
+ ## 安装
45
+
46
+ ```bash
47
+ npm install -g miki-moni
48
+ miki start
49
+ ```
50
+
51
+ 或从 source 装(要贡献 / 用未 release 的改动):
52
+
53
+ ```bash
54
+ git clone https://github.com/WarmBed/Miki-Moni
55
+ cd Miki-Moni
56
+ pnpm install
57
+ pnpm build:all
58
+ pnpm link --global # 把 `miki` 加到 PATH
59
+ miki start
60
+ ```
61
+
62
+ 首次启动会跳设置 wizard:
63
+
64
+ 1. **语言** — English / 繁體中文 / 简体中文
65
+ 2. **Relay 模式** — 三选一:
66
+ - **Hosted**(默认)— 用作者免费 `relay.f1telemetrystationpro.org`,零设置
67
+ - **Self-host** — 自动部署 Cloudflare Worker + Pages 到你 CF 账号(需要 `wrangler`)
68
+ - **Local-only** — 不连手机,只用本机 `127.0.0.1:8765`
69
+
70
+ 然后打印永久配对 QR + 16 码:
71
+
72
+ ```
73
+ 📱 Phone pairing — scan QR, open URL, or type the 16-char code:
74
+
75
+ [QR]
76
+
77
+ URL: https://miki-moni.pages.dev/#t=XXXX...&r=wss://...
78
+ Code: XXXX-XXXX-XXXX-XXXX
79
+ Local: http://127.0.0.1:8765
80
+ (QR / URL / Code 永久有效 — `miki pair --rotate` 可换)
81
+ ```
82
+
83
+ 那个 QR 永久有效,每台要配对的设备扫一次就好。泄漏时 rotate 即可。
84
+
85
+ ## 三种部署模式
86
+
87
+ | | Hosted | Self-host | Local-only |
88
+ |---|---|---|---|
89
+ | **设置时间** | 0 秒 | 约 5 分钟 wizard | 0 秒 |
90
+ | **需要 CF 账号** | 否 | 是 | 否 |
91
+ | **手机可用** | 是 | 是 | 否 |
92
+ | **信任作者基础设施** | 是([§ 安全](#安全)) | 否 | N/A |
93
+ | **流量限制** | 作者 CF 免费层(10 万 req/天) | 你自己 CF 免费层 | N/A |
94
+ | **随时切换** | `miki setup` | `miki setup` | `miki setup` |
95
+
96
+ ## 架构
97
+
98
+ ```
99
+ ┌──────────────────────────────────────────────────────────────────────────┐
100
+ │ 你的电脑 │
101
+ │ ╭─────────────────────────────────────────────────────────────╮ │
102
+ │ │ miki-moni daemon (Node, 127.0.0.1:8765) │ │
103
+ │ │ POST /event GET /sessions POST /focus /send WS /ws │ │
104
+ │ │ ▲ ▲ ▲ │ │
105
+ │ │ PS hooks 浏览器 dashboard RelayClient │ │
106
+ │ ╰────────────────────────────────────────────┬────────────────╯ │
107
+ │ │ E2E 加密 envelope │
108
+ │ ╭─────────────▼────────────╮ │
109
+ │ │ Cloudflare Worker relay │ │
110
+ │ │ (零知识:只路由密文) │ │
111
+ │ ╰─────────────┬────────────╯ │
112
+ │ ▼ │
113
+ │ ╭──────────────────────────╮ │
114
+ │ │ 手机 / 第二台笔电 / 平板 │ │
115
+ │ │ · 扫 QR → 自动配对 │ │
116
+ │ │ · 看到一样的 dashboard │ │
117
+ │ ╰──────────────────────────╯ │
118
+ └──────────────────────────────────────────────────────────────────────────┘
119
+ ```
120
+
121
+ **加密**:配对时 X25519 ECDH → per-peer shared secret → 每个 envelope 用 NaCl `secretbox`。Relay 没有 key;只有 daemon 跟配对好的手机能解内容。
122
+
123
+ **认证**:每台手机握一对 Ed25519 签名 keypair(IndexedDB)。重连时签 `daemon_id || utc_minute`,relay 验签才放行。`miki pair --revoke <peer_id>` 删单个设备。
124
+
125
+ ## Dashboard 功能
126
+
127
+ 上方工具栏:
128
+
129
+ | | 作用 |
130
+ |---|---|
131
+ | **计数器**(`5 进行中 · 0 闲置 · 56 总览`) | 点击筛选只看那个状态,再点取消 |
132
+ | **➕ 新增 CLI** | 在指定文件夹开新 wrapped session(`miki claude --fresh`) |
133
+ | **⚙️ 设置** | 发送键(Enter vs Ctrl/⌘+Enter)、主题(亮/暗)、语言 |
134
+ | **WS 灯号** | 绿=实时更新中 · 黄=重连中 |
135
+
136
+ Session 卡片:
137
+
138
+ | 元素 | 作用 |
139
+ |---|---|
140
+ | **项目名 + cwd** | 卡片标题 — 点开查看完整 transcript |
141
+ | **🖥️ VSCode / 📟 CLI 切换** | 决定 *发送 / focus* 走哪边。**VSCode**:用 `vscode://anthropic.claude-code/open?session=…` 把 prompt 预填 VSCode panel。**CLI**:直接打 wrap CLI 的 WebSocket。 |
142
+ | **权限 badge**(`✏️ auto edit` / `🚀 bypass`) | 只有跑 `miki claude --permission-mode acceptEdits` / `--bypass-permissions` 的 wrap CLI session 才显示,整个 session lifetime 锁定不能改 |
143
+ | **Transcript view** | 实时渲染 Claude 对话。可开关 tool call。滚动门槛 10 / 50 / 200 / 全部。 |
144
+ | **发送输入框** | 多行 prompt。Enter 或 Ctrl/⌘+Enter 发送(按你的设置)。支持粘贴/拖图片。 |
145
+ | **开 CLI 按钮** ⭐ | **从 CLI 接管这个 session,完整上下文都在。** 开 `wt.exe`(Windows Terminal)跑 `miki claude -r <session-uuid>` — Claude 从 VSCode panel 停的那回合接着做。原本从哪起的都不重要;panel 可以已关、已 crash、在另一个窗口。配上手机 dashboard,同一个 session 你在哪都能继续打 |
146
+ | **Focus 按钮** | `POST /focus` — 把对应 VSCode 窗口(或 CLI tab)提到最前 |
147
+
148
+ ## CLI 命令
149
+
150
+ | 命令 | 用途 |
151
+ |---|---|
152
+ | `miki start` | 跑 daemon + 打印配对 banner。第一次跑会跳 wizard |
153
+ | `miki setup` | 重跑 wizard(换语言、切 relay 模式等) |
154
+ | `miki pair` | 打印当前永久 QR + 已配对手机清单 |
155
+ | `miki pair --rotate` | 换新 token(旧 QR 失效;已配对手机照常工作) |
156
+ | `miki pair --list` | 列已配对手机 |
157
+ | `miki pair --revoke <peer_id>` | 删除某台手机(本机 config + relay 都清) |
158
+ | `miki pair --new` | 一次性 token(10 分钟 TTL)— 旧机制 / debug 用 |
159
+ | `miki claude [...args]` | 包一个 Claude session,daemon 没跑会自动起 |
160
+ | `miki install-hooks` | 把 Claude Code hooks 装进 `~/.claude/settings.json`,没 wrap 的 panel 也会出现在 dashboard |
161
+
162
+ 启动时看详细 log:`MIKI_LOG_LEVEL=info miki start`。完整 trace 永远在 `~/.miki-moni/miki-moni.log`。
163
+
164
+ ## 安全
165
+
166
+ ### 手机能做什么、不能做什么
167
+
168
+ 刻意把手机端能力压到最小,威胁模型才好顾:
169
+
170
+ | 手机**可以** | 手机**不可以** |
171
+ |---|---|
172
+ | 看实时 session 状态 + transcript | 在你电脑上跑任意 shell 命令 |
173
+ | Pre-fill prompt 进 VSCode panel(`/focus`) | 不经你 VSCode 按键自动送出 prompt(Anthropic 设计) |
174
+ | 对 `miki claude` 起的 session 从 wrap CLI WebSocket 推 prompt | 开新 process 或读 session 外的文件 |
175
+ | Focus 已存在的 panel | 绕过 Claude Code 工具权限提示(每个工具调用一样会问你) |
176
+
177
+ ### 信赖边界
178
+
179
+ daemon **只绑 `127.0.0.1`** — 公网永远戳不到。远端走加密 relay,不走本机 HTTP port。
180
+
181
+ daemon 信任**所有跟你同账号**的本机程序去打 `/event`、`/send`、`/focus`、`/ws_ext`。这是故意的(Claude Code hooks 跟 VSCode helper extension 才不用带 token),但代价是:**任何以你身份跑的程序都能跟 daemon 讲话**。完整本机信赖分析跟硬化选项见 [`docs/security/hooks-trust-model.md`](docs/security/hooks-trust-model.md) 跟 [`docs/security/extension-ws-trust-model.md`](docs/security/extension-ws-trust-model.md)。
182
+
183
+ ### 风险表
184
+
185
+ 按可能性排序:
186
+
187
+ | 风险 | 缓解 |
188
+ |---|---|
189
+ | 🔴 **配对 QR 泄漏**(截图、贴到聊天室、被路人拍) | 永久 QR = 任何人扫到都能 pair。把 QR 当 SSH key 看待。泄漏立刻 rotate:`miki pair --rotate` |
190
+ | 🟡 **配对手机被偷** | 手机握 Ed25519 签名 key 才能连 relay。从 daemon 删:`miki pair --revoke <peer_id>` |
191
+ | 🟡 **本机被入侵** | daemon 信任 loopback。任何以你身份跑的恶意程序可读 session、可从 `/ws_ext` 拦 prompt。`~/.miki-moni/`(私钥、配对记录)请当 `~/.ssh/` 那样保护 |
192
+ | 🟢 暴力猜 token | 16 字符 Crockford base32 ≈ 80 bits entropy,宇宙热寂前猜不到 |
193
+ | 🟢 Relay 看到内容 | 零知识架构 — relay 只路由密文,不持有 shared secret |
194
+ | 🟡 信任 hosted relay 维护者 | Self-host 完全摆脱这层信任。作者看得到 metadata(peer ID、时间、大小),理论上可改 PWA bundle。源码公开,可自行 audit 或 self-host。 |
195
+ | 🟢 Hosted relay 被 DDoS | Cloudflare rate limit 限 30 req/60 秒/IP。最坏:你的当日配额烧光 |
196
+
197
+ ## Self-host(手动)
198
+
199
+ `miki setup` wizard 自动做完,但要手动的话:
200
+
201
+ ```bash
202
+ # 在 clone 好的 cc-hub source 树:
203
+ cd worker
204
+ wrangler login
205
+ wrangler deploy --config wrangler-selfhost.toml --name my-relay
206
+ wrangler pages project create my-phone --production-branch=main
207
+ wrangler pages deploy ../dist/web-phone --project-name my-phone --branch=main
208
+ ```
209
+
210
+ 然后编 `~/.miki-moni/config.json`:
211
+
212
+ ```json
213
+ {
214
+ "remote": {
215
+ "worker_url": "wss://my-relay.<你 CF 账号>.workers.dev",
216
+ "phone_pwa_url": "https://my-phone.pages.dev/"
217
+ }
218
+ }
219
+ ```
220
+
221
+ 下次 `miki start` 就会用新 endpoints。
222
+
223
+ ## 开发
224
+
225
+ ```bash
226
+ git clone https://github.com/WarmBed/Miki-Moni
227
+ cd Miki-Moni
228
+ pnpm install
229
+ pnpm typecheck
230
+ pnpm test # daemon + worker tests
231
+ pnpm dev # tsx watch src/index.ts
232
+ ```
233
+
234
+ Source 结构:
235
+
236
+ | 路径 | 用途 |
237
+ |---|---|
238
+ | `src/` | Node daemon(express + ws + better-sqlite3)— hooks、配对、RelayClient |
239
+ | `web/` | 桌面 / 手机完整 dashboard(Preact + Tailwind + Vite) |
240
+ | `web-phone/` | 手机 bootstrap(QR 扫描器 + tunnel 设置)— mount web/ |
241
+ | `worker/` | Cloudflare Worker relay(DaemonRelay + PairingCoordinator DOs) |
242
+ | `extension/` | VSCode helper extension — handle `claude-vscode.send` |
243
+ | `hooks/` | Claude Code hook 脚本(PowerShell)— POST event 到 daemon |
244
+ | `bin/miki.mjs` | npm 发布的 CLI 入口 |
245
+
246
+ ## 分支
247
+
248
+ - `main` — 版本化 release(当前:v0.0.0)
249
+ - `dev` — 开发中;每改动 bump `package.json` version
250
+
251
+ ## 相关项目
252
+
253
+ **[Happy](https://happy.engineering)**(`slopus/happy-cli`, MIT)切的痛点有重叠 — 从手机操控 Claude Code — 但角度不同。两者可以同一台机器并存。
254
+
255
+ | | Miki-Moni | Happy |
256
+ |---|---|---|
257
+ | 主入口 | VSCode panel — hooks 把每个 panel 拉进 dashboard | 取代 `claude` 的 terminal wrapper |
258
+ | Relay | Cloudflare Worker;可以 5 分钟 self-host 到自己 CF 账号 | 作者自架 socket.io server(`api.cluster-fluster.com`) |
259
+ | 手机端 | Web PWA — 扫 QR 就能用,免装 app | 原生 iOS / Android app |
260
+ | 支持 agent | Claude Code | Claude Code、Codex、Gemini、通用 ACP |
261
+ | 语音输入 | — | 有 |
262
+ | 多 session 可视化 dashboard | 有 — 跨窗口聚合 | 各 session 独立管 |
263
+ | 取代 `claude` 吗 | 不取代 — hooks 并存 | 取代,自己 spawn `claude` |
264
+ | 远端 spawn(人不在桌前也能起新 session) | — | 有(`happy daemon`) |
265
+ | 加密 relay | 有(X25519 + NaCl secretbox) | 有(X25519 + NaCl secretbox + AES-GCM) |
266
+
267
+ 想要打磨好的手机原生体验、跨多个 AI agent、不介意 SaaS relay → 用 Happy。住在 VSCode 里、想要一张 dashboard 收齐多个并行 panel、想 self-host 到自己 CF → 用 Miki-Moni。
268
+
269
+ ## 许可证
270
+
271
+ MIT — 见 [LICENSE](LICENSE)。
272
+
273
+ ## Credits
274
+
275
+ 用 [Anthropic Claude](https://claude.ai/code) 通过 [Claude Code](https://github.com/anthropics/claude-code) 写出来的。