@tt-a1i/hive 1.7.0 → 2.0.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 (251) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.en.md +73 -11
  3. package/README.md +41 -8
  4. package/dist/src/cli/hive-remote.d.ts +46 -0
  5. package/dist/src/cli/hive-remote.js +257 -0
  6. package/dist/src/cli/hive-update.js +7 -2
  7. package/dist/src/cli/hive.d.ts +6 -0
  8. package/dist/src/cli/hive.js +64 -0
  9. package/dist/src/cli/team.d.ts +22 -0
  10. package/dist/src/cli/team.js +255 -5
  11. package/dist/src/server/agent-command-resolver.js +10 -3
  12. package/dist/src/server/agent-exit-classification.d.ts +6 -0
  13. package/dist/src/server/agent-exit-classification.js +6 -0
  14. package/dist/src/server/agent-manager-support.d.ts +2 -1
  15. package/dist/src/server/agent-manager-support.js +59 -15
  16. package/dist/src/server/agent-manager.d.ts +3 -0
  17. package/dist/src/server/agent-manager.js +22 -7
  18. package/dist/src/server/agent-run-bootstrap.d.ts +14 -0
  19. package/dist/src/server/agent-run-bootstrap.js +11 -4
  20. package/dist/src/server/agent-run-exit-handler.js +14 -8
  21. package/dist/src/server/agent-run-starter.d.ts +3 -1
  22. package/dist/src/server/agent-run-starter.js +22 -5
  23. package/dist/src/server/agent-run-sync.js +13 -5
  24. package/dist/src/server/agent-runtime-types.d.ts +1 -0
  25. package/dist/src/server/agent-runtime.d.ts +2 -1
  26. package/dist/src/server/agent-runtime.js +9 -2
  27. package/dist/src/server/agent-startup-instructions.d.ts +2 -1
  28. package/dist/src/server/agent-startup-instructions.js +8 -4
  29. package/dist/src/server/agent-stdin-dispatcher.d.ts +4 -2
  30. package/dist/src/server/agent-stdin-dispatcher.js +35 -3
  31. package/dist/src/server/command-preset-defaults.d.ts +6 -1
  32. package/dist/src/server/command-preset-defaults.js +56 -0
  33. package/dist/src/server/fs-browse.d.ts +2 -0
  34. package/dist/src/server/fs-browse.js +165 -31
  35. package/dist/src/server/fs-pick-folder.js +6 -69
  36. package/dist/src/server/fs-sandbox.d.ts +5 -3
  37. package/dist/src/server/fs-sandbox.js +5 -3
  38. package/dist/src/server/hive-team-guidance.js +18 -6
  39. package/dist/src/server/machine-name.d.ts +2 -0
  40. package/dist/src/server/machine-name.js +13 -0
  41. package/dist/src/server/open-target-commands.d.ts +1 -0
  42. package/dist/src/server/open-target-commands.js +4 -1
  43. package/dist/src/server/orchestrator-autostart.js +1 -1
  44. package/dist/src/server/platform-path.d.ts +1 -0
  45. package/dist/src/server/platform-path.js +14 -1
  46. package/dist/src/server/post-start-input-writer.js +50 -13
  47. package/dist/src/server/preset-launch-support.js +1 -0
  48. package/dist/src/server/recovery-summary.d.ts +2 -1
  49. package/dist/src/server/recovery-summary.js +2 -1
  50. package/dist/src/server/remote-audit-store.d.ts +51 -0
  51. package/dist/src/server/remote-audit-store.js +108 -0
  52. package/dist/src/server/remote-config-keys.d.ts +17 -0
  53. package/dist/src/server/remote-config-keys.js +27 -0
  54. package/dist/src/server/remote-control-constants.d.ts +30 -0
  55. package/dist/src/server/remote-control-constants.js +29 -0
  56. package/dist/src/server/remote-device-session.d.ts +40 -0
  57. package/dist/src/server/remote-device-session.js +22 -0
  58. package/dist/src/server/remote-device-store.d.ts +36 -0
  59. package/dist/src/server/remote-device-store.js +67 -0
  60. package/dist/src/server/remote-frame-bridge.d.ts +102 -0
  61. package/dist/src/server/remote-frame-bridge.js +791 -0
  62. package/dist/src/server/remote-gateway-client.d.ts +14 -0
  63. package/dist/src/server/remote-gateway-client.js +36 -0
  64. package/dist/src/server/remote-loopback-auth.d.ts +6 -0
  65. package/dist/src/server/remote-loopback-auth.js +112 -0
  66. package/dist/src/server/remote-pairing-tunnel.d.ts +59 -0
  67. package/dist/src/server/remote-pairing-tunnel.js +146 -0
  68. package/dist/src/server/remote-pairing.d.ts +58 -0
  69. package/dist/src/server/remote-pairing.js +237 -0
  70. package/dist/src/server/remote-tunnel.d.ts +113 -0
  71. package/dist/src/server/remote-tunnel.js +514 -0
  72. package/dist/src/server/restart-policy-support.d.ts +4 -1
  73. package/dist/src/server/restart-policy-support.js +3 -1
  74. package/dist/src/server/restart-policy.d.ts +1 -1
  75. package/dist/src/server/restart-policy.js +19 -3
  76. package/dist/src/server/route-types.d.ts +1 -1
  77. package/dist/src/server/routes-dispatches.js +1 -1
  78. package/dist/src/server/routes-fs.js +3 -3
  79. package/dist/src/server/routes-marketplace.js +2 -2
  80. package/dist/src/server/routes-open-workspace.js +1 -1
  81. package/dist/src/server/routes-remote.d.ts +2 -0
  82. package/dist/src/server/routes-remote.js +166 -0
  83. package/dist/src/server/routes-runtime.js +6 -6
  84. package/dist/src/server/routes-settings.js +16 -16
  85. package/dist/src/server/routes-tasks.js +2 -2
  86. package/dist/src/server/routes-team-memory.d.ts +2 -0
  87. package/dist/src/server/routes-team-memory.js +154 -0
  88. package/dist/src/server/routes-team-recall.d.ts +2 -0
  89. package/dist/src/server/routes-team-recall.js +119 -0
  90. package/dist/src/server/routes-team.js +31 -9
  91. package/dist/src/server/routes-ui.js +11 -1
  92. package/dist/src/server/routes-workflow-schedules.js +3 -3
  93. package/dist/src/server/routes-workflows.js +5 -5
  94. package/dist/src/server/routes-workspace-memory-dreams.d.ts +2 -0
  95. package/dist/src/server/routes-workspace-memory-dreams.js +105 -0
  96. package/dist/src/server/routes-workspace-memory.d.ts +2 -0
  97. package/dist/src/server/routes-workspace-memory.js +215 -0
  98. package/dist/src/server/routes-workspaces.js +9 -9
  99. package/dist/src/server/routes.js +10 -0
  100. package/dist/src/server/runtime-database.d.ts +1 -0
  101. package/dist/src/server/runtime-database.js +27 -2
  102. package/dist/src/server/runtime-restart-policy.d.ts +3 -1
  103. package/dist/src/server/runtime-restart-policy.js +2 -1
  104. package/dist/src/server/runtime-store-contract.d.ts +37 -0
  105. package/dist/src/server/runtime-store-dream.d.ts +23 -0
  106. package/dist/src/server/runtime-store-dream.js +16 -0
  107. package/dist/src/server/runtime-store-helpers.d.ts +20 -0
  108. package/dist/src/server/runtime-store-helpers.js +81 -7
  109. package/dist/src/server/runtime-store-memory.d.ts +33 -0
  110. package/dist/src/server/runtime-store-memory.js +37 -0
  111. package/dist/src/server/runtime-store-remote.d.ts +5 -0
  112. package/dist/src/server/runtime-store-remote.js +45 -0
  113. package/dist/src/server/runtime-store-workflows.js +2 -0
  114. package/dist/src/server/runtime-store.js +14 -3
  115. package/dist/src/server/session-capture-claude.d.ts +1 -1
  116. package/dist/src/server/session-capture-claude.js +7 -4
  117. package/dist/src/server/session-capture-codex.js +4 -5
  118. package/dist/src/server/session-capture-gemini.js +4 -5
  119. package/dist/src/server/session-capture-opencode.d.ts +4 -4
  120. package/dist/src/server/session-capture-opencode.js +20 -12
  121. package/dist/src/server/session-capture-qwen.d.ts +5 -0
  122. package/dist/src/server/session-capture-qwen.js +104 -0
  123. package/dist/src/server/session-capture.d.ts +17 -0
  124. package/dist/src/server/session-capture.js +16 -0
  125. package/dist/src/server/sqlite-schema-v23.d.ts +2 -0
  126. package/dist/src/server/sqlite-schema-v23.js +43 -0
  127. package/dist/src/server/sqlite-schema-v24.d.ts +2 -0
  128. package/dist/src/server/sqlite-schema-v24.js +34 -0
  129. package/dist/src/server/sqlite-schema-v25.d.ts +2 -0
  130. package/dist/src/server/sqlite-schema-v25.js +127 -0
  131. package/dist/src/server/sqlite-schema-v26.d.ts +2 -0
  132. package/dist/src/server/sqlite-schema-v26.js +56 -0
  133. package/dist/src/server/sqlite-schema-v27.d.ts +6 -0
  134. package/dist/src/server/sqlite-schema-v27.js +92 -0
  135. package/dist/src/server/sqlite-schema-v28.d.ts +2 -0
  136. package/dist/src/server/sqlite-schema-v28.js +19 -0
  137. package/dist/src/server/sqlite-schema-v29.d.ts +2 -0
  138. package/dist/src/server/sqlite-schema-v29.js +27 -0
  139. package/dist/src/server/sqlite-schema-v30.d.ts +2 -0
  140. package/dist/src/server/sqlite-schema-v30.js +27 -0
  141. package/dist/src/server/sqlite-schema-v31.d.ts +2 -0
  142. package/dist/src/server/sqlite-schema-v31.js +30 -0
  143. package/dist/src/server/sqlite-schema.d.ts +1 -1
  144. package/dist/src/server/sqlite-schema.js +49 -1
  145. package/dist/src/server/startup-command-parser.js +5 -1
  146. package/dist/src/server/tasks-file-watcher.d.ts +2 -0
  147. package/dist/src/server/tasks-file-watcher.js +15 -6
  148. package/dist/src/server/tasks-file.js +30 -5
  149. package/dist/src/server/tasks-websocket-server.js +4 -0
  150. package/dist/src/server/team-authz.d.ts +1 -1
  151. package/dist/src/server/team-authz.js +13 -1
  152. package/dist/src/server/team-list-enrichment.js +3 -1
  153. package/dist/src/server/team-memory-digest.d.ts +52 -0
  154. package/dist/src/server/team-memory-digest.js +200 -0
  155. package/dist/src/server/team-memory-dream-applier.d.ts +5 -0
  156. package/dist/src/server/team-memory-dream-applier.js +234 -0
  157. package/dist/src/server/team-memory-dream-http-serializers.d.ts +13 -0
  158. package/dist/src/server/team-memory-dream-http-serializers.js +12 -0
  159. package/dist/src/server/team-memory-dream-ops.d.ts +40 -0
  160. package/dist/src/server/team-memory-dream-ops.js +153 -0
  161. package/dist/src/server/team-memory-dream-reverter.d.ts +22 -0
  162. package/dist/src/server/team-memory-dream-reverter.js +221 -0
  163. package/dist/src/server/team-memory-dream-run-store.d.ts +23 -0
  164. package/dist/src/server/team-memory-dream-run-store.js +211 -0
  165. package/dist/src/server/team-memory-dream-runner.d.ts +37 -0
  166. package/dist/src/server/team-memory-dream-runner.js +178 -0
  167. package/dist/src/server/team-memory-dream-scheduler.d.ts +32 -0
  168. package/dist/src/server/team-memory-dream-scheduler.js +115 -0
  169. package/dist/src/server/team-memory-dream-store.d.ts +19 -0
  170. package/dist/src/server/team-memory-dream-store.js +16 -0
  171. package/dist/src/server/team-memory-dream-types.d.ts +104 -0
  172. package/dist/src/server/team-memory-dream-types.js +23 -0
  173. package/dist/src/server/team-memory-export.d.ts +22 -0
  174. package/dist/src/server/team-memory-export.js +220 -0
  175. package/dist/src/server/team-memory-feature.d.ts +12 -0
  176. package/dist/src/server/team-memory-feature.js +12 -0
  177. package/dist/src/server/team-memory-http-serializers.d.ts +102 -0
  178. package/dist/src/server/team-memory-http-serializers.js +46 -0
  179. package/dist/src/server/team-memory-injection.d.ts +31 -0
  180. package/dist/src/server/team-memory-injection.js +49 -0
  181. package/dist/src/server/team-memory-store.d.ts +116 -0
  182. package/dist/src/server/team-memory-store.js +513 -0
  183. package/dist/src/server/team-operations.d.ts +5 -1
  184. package/dist/src/server/team-operations.js +46 -16
  185. package/dist/src/server/team-recall-store.d.ts +38 -0
  186. package/dist/src/server/team-recall-store.js +205 -0
  187. package/dist/src/server/terminal-input-profile.d.ts +1 -1
  188. package/dist/src/server/terminal-input-profile.js +8 -0
  189. package/dist/src/server/terminal-ws-server.js +6 -0
  190. package/dist/src/server/ui-auth-helpers.d.ts +1 -1
  191. package/dist/src/server/ui-auth-helpers.js +7 -1
  192. package/dist/src/server/ui-auth.d.ts +3 -0
  193. package/dist/src/server/ui-auth.js +21 -1
  194. package/dist/src/server/workflow-cli-policy.d.ts +2 -3
  195. package/dist/src/server/workflow-cli-policy.js +3 -3
  196. package/dist/src/server/workflow-runner.d.ts +1 -0
  197. package/dist/src/server/workflow-runner.js +9 -4
  198. package/dist/src/server/workspace-path-validation.js +6 -2
  199. package/dist/src/server/workspace-store.d.ts +1 -1
  200. package/dist/src/server/workspace-store.js +35 -9
  201. package/dist/src/shared/fs-browse.d.ts +1 -0
  202. package/dist/src/shared/fs-browse.js +1 -0
  203. package/dist/src/shared/path-input.d.ts +12 -0
  204. package/dist/src/shared/path-input.js +22 -0
  205. package/dist/src/shared/remote-bridge-routing.d.ts +19 -0
  206. package/dist/src/shared/remote-bridge-routing.js +141 -0
  207. package/dist/src/shared/remote-crypto.d.ts +138 -0
  208. package/dist/src/shared/remote-crypto.js +427 -0
  209. package/dist/src/shared/remote-pairing-code.d.ts +7 -0
  210. package/dist/src/shared/remote-pairing-code.js +47 -0
  211. package/dist/src/shared/remote-protocol.d.ts +160 -0
  212. package/dist/src/shared/remote-protocol.js +526 -0
  213. package/dist/src/shared/team-memory.d.ts +11 -0
  214. package/dist/src/shared/team-memory.js +10 -0
  215. package/dist/src/shared/team-recall.d.ts +1 -0
  216. package/dist/src/shared/team-recall.js +1 -0
  217. package/dist/src/shared/types.d.ts +4 -5
  218. package/package.json +12 -5
  219. package/scripts/postinstall-native-artifacts.mjs +113 -0
  220. package/web/dist/assets/AddWorkerDialog-C86CwNgQ.js +2 -0
  221. package/web/dist/assets/AddWorkspaceFlow-Bm2Jz34D.js +1 -0
  222. package/web/dist/assets/FirstRunWizard-XzBoEpA5.js +1 -0
  223. package/web/dist/assets/MarketplaceDrawer-BFfGT8hH.js +67 -0
  224. package/web/dist/assets/TaskGraphDrawer-_uVH_0C1.js +1 -0
  225. package/web/dist/assets/{WhatsNewDialog-CHkZeINH.js → WhatsNewDialog-DkJHmkMs.js} +1 -1
  226. package/web/dist/assets/WorkerModal-BtMJEOG9.js +1 -0
  227. package/web/dist/assets/WorkflowsDrawer-CiIdHS6_.js +1 -0
  228. package/web/dist/assets/WorkspaceMemoryDrawer-C6sNocl_.js +1 -0
  229. package/web/dist/assets/WorkspaceTaskDrawer-CyhhEB1Z.js +1 -0
  230. package/web/dist/assets/index-BAiLYajK.css +1 -0
  231. package/web/dist/assets/index-K-GG8UwR.js +73 -0
  232. package/web/dist/assets/search-BtRkkEmS.js +1 -0
  233. package/web/dist/assets/square-terminal-lEeQUWb3.js +1 -0
  234. package/web/dist/cli-icons/agy.png +0 -0
  235. package/web/dist/cli-icons/cursor.ico +0 -0
  236. package/web/dist/cli-icons/grok.ico +0 -0
  237. package/web/dist/cli-icons/qwen.png +0 -0
  238. package/web/dist/index.html +8 -3
  239. package/web/dist/sw.js +1 -1
  240. package/scripts/fix-runtime-artifacts.mjs +0 -33
  241. package/web/dist/assets/AddWorkerDialog-BRUxpa3f.js +0 -2
  242. package/web/dist/assets/AddWorkspaceDialog-D56x5JCb.js +0 -1
  243. package/web/dist/assets/FirstRunWizard-BFVaMIsE.js +0 -1
  244. package/web/dist/assets/MarketplaceDrawer-DeEZ35dN.js +0 -76
  245. package/web/dist/assets/WorkerModal-BBCuMLIa.js +0 -1
  246. package/web/dist/assets/WorkspaceTaskDrawer-CpZHAcj1.js +0 -1
  247. package/web/dist/assets/WorkspaceTerminalPanels-7If2mDyp.js +0 -1
  248. package/web/dist/assets/WorkspaceTerminalPanels-DDGTF8rc.css +0 -1
  249. package/web/dist/assets/index-5zh61jMg.css +0 -1
  250. package/web/dist/assets/index-CxNL0O-C.js +0 -73
  251. package/web/dist/assets/path-join-7MR1s7b1.js +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,57 @@
2
2
 
3
3
  All notable user-facing changes will be documented in this file.
4
4
 
5
+ ## 2.0.1 - 2026-06-09
6
+
7
+ Team memory, worker-card polish, and release-channel cleanup.
8
+
9
+ - Adds ambient team memory so Hive can retain useful workspace context and
10
+ surface it again when you need the team to remember prior decisions,
11
+ constraints, or project notes.
12
+ - Refines the Memory and Workflows drawers with better desktop/mobile layouts,
13
+ clearer tabs, and a search field that stays out of the way on wide screens.
14
+ - Redesigns worker cards for stronger scanability: clearer status treatment,
15
+ higher contrast, cleaner role text, and an in-place rename flow instead of a
16
+ separate edit dialog.
17
+ - Clarifies pending dispatch status so queued or waiting worker activity is
18
+ easier to understand while the Orchestrator is coordinating work.
19
+ - Publishes the current remote/mobile build under the original official
20
+ `@tt-a1i/hive` package name.
21
+
22
+ ## 2.0.0 - 2026-06-07
23
+
24
+ Remote access, mobile control, and the production gateway.
25
+
26
+ - Adds optional Remote access so you can open your running Hive from a phone
27
+ browser. Remote is off by default; when enabled, the phone connects through
28
+ an end-to-end encrypted tunnel and gets the same authority as the local
29
+ desktop browser.
30
+ - Ships the Cloudflare Workers gateway stack for identity and routing: GitHub
31
+ and Google sign-in, Durable Object relay, D1-backed daemon/device records,
32
+ rate limiting, version-pinned mobile bundles, and deployment runbooks for
33
+ self-hosting or pointing Hive at an existing gateway.
34
+ - Adds the desktop trust-root pairing flow. The desktop creates a short-lived
35
+ pairing code, the phone enters it after selecting the machine, both sides
36
+ show a 6-digit SAS code, and the device is stored only after desktop
37
+ confirmation.
38
+ - Adds remote device management: list paired devices, revoke them from
39
+ Settings or the CLI, drop live sessions immediately from the Settings panel,
40
+ and review an audit trail of remote requests and denials.
41
+ - Adds `hive remote login`, `status`, `logout`, `devices`, and `revoke` for
42
+ linking the machine to a gateway account and managing paired devices from
43
+ the host itself.
44
+ - Adds the mobile Hive shell: sign-in/connect screens, machine list, bottom
45
+ navigation, workspace switching, full-screen team/task panels, and
46
+ remote-aware reconnect and update prompts.
47
+ - Makes phone terminals writable through the terminal itself. Worker terminals
48
+ can be opened full-screen, mobile focus mode hides surrounding chrome while
49
+ you work, and terminal touch scrolling now tracks the finger more closely
50
+ with smoother normal-buffer glide and faster alternate-screen movement.
51
+ - Preserves local-first behavior: local `127.0.0.1` Hive keeps working without
52
+ a gateway, remote access is path-whitelisted to Hive's own `/api/*` and
53
+ `/ws/*`, and paired phones cannot approve new devices or turn Remote access
54
+ back on after it has been disabled.
55
+
5
56
  ## 1.7.0 - 2026-06-05
6
57
 
7
58
  Hermes joins the roster.
package/README.en.md CHANGED
@@ -9,7 +9,7 @@
9
9
  </p>
10
10
 
11
11
  **Hive is a browser-native workbench where a team of agents works together — one orchestrates, the rest execute, all on your laptop.** The orchestrator
12
- is a real `claude` / `codex` / `opencode` / `gemini` / `hermes` process — not you, and
12
+ is a real `agy` / `claude` / `codex` / `opencode` / `gemini` / `hermes` / `qwen` process — not you, and
13
13
  not a script — and so are the workers it dispatches to. Every agent runs as
14
14
  a real PTY on your machine, talks through a small `team` protocol that Hive
15
15
  injects into each agent's shell, and shares a markdown task graph at
@@ -76,6 +76,12 @@ npm install -g @tt-a1i/hive
76
76
  hive
77
77
  ```
78
78
 
79
+ If npm prints `npm warn allow-scripts` or `prebuild-install@7.1.3 deprecated`
80
+ during install, first check whether the command ends with `added ... packages`.
81
+ Those warnings usually come from npm's install-script review plus native
82
+ binary setup for `node-pty`, `better-sqlite3`, and `esbuild`; they do not mean
83
+ Hive failed to install. The troubleshooting section below breaks them down.
84
+
79
85
  Open the printed local URL, usually `http://127.0.0.1:3000/`. Use
80
86
  `hive --port 4010` when you need a specific local port.
81
87
 
@@ -172,11 +178,15 @@ Three details matter:
172
178
 
173
179
  | Preset | Command expected on `PATH` | Default bypass mode | Session resume |
174
180
  | --- | --- | --- | --- |
181
+ | Antigravity CLI | `agy` | `--dangerously-skip-permissions` | `--conversation <session_id>` |
175
182
  | Claude Code | `claude` | `--dangerously-skip-permissions`, `--permission-mode=bypassPermissions` | `--resume <session_id>` |
176
183
  | Codex | `codex` | `--dangerously-bypass-approvals-and-sandbox` | `resume <session_id>` |
177
184
  | OpenCode | `opencode` | Config-driven in `~/.config/opencode/opencode.json` | `--session <session_id>` |
178
185
  | Gemini | `gemini` | `--yolo` | `--resume <session_id>` |
179
186
  | Hermes | `hermes` | `--yolo` | `--resume <session_id>` |
187
+ | Qwen Code | `qwen` | `--approval-mode yolo` | `--resume <session_id>` |
188
+ | Cursor CLI | `cursor` | `--force` | Session id capture not wired yet |
189
+ | Grok Build | `grok` | `--always-approve` | Session id capture not wired yet |
180
190
  | Custom | Any executable | User configured | User configured |
181
191
 
182
192
  Hive does not install these CLIs for you. Install and authenticate them in the
@@ -199,11 +209,46 @@ same shell environment you use to start Hive.
199
209
  - `.hive/tasks.md` editor with external-file conflict handling.
200
210
  - Background PTY preservation and best-effort native session resume.
201
211
  - A What's New dialog after upgrades with curated release highlights.
202
- - Local SQLite metadata under `~/.config/hive` by default, or `$HIVE_DATA_DIR`
203
- when set.
204
-
205
- Hive does not provide sandboxing, multi-user auth, cloud hosting, or any
206
- bundled agent model. It coordinates the CLIs you already run locally.
212
+ - Local SQLite metadata under `%APPDATA%\hive` on Windows and `~/.config/hive`
213
+ on macOS / Linux by default, or `$HIVE_DATA_DIR` when set.
214
+
215
+ Hive does not provide sandboxing, multi-user auth, or any bundled agent
216
+ model. It coordinates the CLIs you already run locally.
217
+
218
+ ## Remote Access (optional, off by default)
219
+
220
+ If you want to reach your running Hive from your phone while you're away,
221
+ turn on the optional **Remote access** feature. Once enabled, a phone browser
222
+ logs in at a gateway with GitHub or Google, pairs once with the desktop, and
223
+ then reaches the **full** Hive web UI over an end-to-end encrypted tunnel — a
224
+ paired phone is a trusted device with the **same authority** as the local
225
+ browser.
226
+
227
+ A few things to be clear about:
228
+
229
+ - **Off by default.** With it off there are no outbound connections and
230
+ nothing listening — behavior is exactly what it is today.
231
+ - **Requires a gateway.** The tunnel is relayed through a gateway (your
232
+ local daemon dials out to it — no open ports, no router changes). The
233
+ gateway URL is configurable: **self-host** a Cloudflare Workers gateway,
234
+ or point at one that's already deployed. There is **no turnkey hosted
235
+ service** — you stand the gateway up yourself.
236
+ - **Data and execution stay local.** The gateway only does identity (OAuth
237
+ login) and routing; it never sees plaintext, only relays ciphertext. If the
238
+ gateway is down, everything on local `127.0.0.1` keeps working.
239
+ - **End-to-end encrypted.** Every data frame between the phone and the daemon
240
+ is end-to-end encrypted; the gateway sees only ciphertext and routing
241
+ headers. The honest caveat: the phone's crypto code is served by the gateway
242
+ (the classic limit of web-delivered E2E, like Proton or WhatsApp Web),
243
+ mitigated by SRI, versioned bundles, and PWA caching that forms a TOFU
244
+ baseline. We don't claim "secure even if the gateway is compromised."
245
+ - **Trust root stays on the desktop.** Pairing a new device must be confirmed
246
+ in person at the computer (a desktop dialog plus a 6-digit SAS check); a
247
+ paired phone can't approve new devices on its own. Devices can be revoked at
248
+ any time.
249
+
250
+ See [docs/remote-access.md](docs/remote-access.md) for the full enable,
251
+ login (`hive remote login`), pairing, revoke, and self-host-gateway walkthrough.
207
252
 
208
253
  ## Platform Support
209
254
 
@@ -211,7 +256,7 @@ bundled agent model. It coordinates the CLIs you already run locally.
211
256
  | --- | --- | --- |
212
257
  | macOS | Tier 1 | Main development and release verification target. |
213
258
  | Linux | Tier 1 | CI verified. Native folder picking expects `zenity`; manual path entry works without it. |
214
- | Windows | Tier 2 | CI runs a Windows test subset and a packaged-install smoke. Folder picking uses Windows PowerShell and the package includes `team.cmd`. Treat as best-effort — full Windows verification before each release is manual. |
259
+ | Windows | Tier 2 | CI runs a Windows test subset and a packaged-install smoke. Workspace selection uses Hive's in-browser server filesystem picker by default, starting at "This PC" so other drives are visible; the package includes `team.cmd`. Treat as best-effort — full Windows verification before each release is manual. |
215
260
 
216
261
  All platforms require Node.js 22+. Hive depends on native packages
217
262
  (`node-pty` and `better-sqlite3`), so native install tooling may be required
@@ -241,7 +286,7 @@ Read [SECURITY.md](SECURITY.md) before using Hive with sensitive repositories.
241
286
 
242
287
  | Data | Location |
243
288
  | --- | --- |
244
- | Runtime metadata | `~/.config/hive` or `$HIVE_DATA_DIR` |
289
+ | Runtime metadata | Windows: `%APPDATA%\hive`; macOS / Linux: `~/.config/hive`; or `$HIVE_DATA_DIR` |
245
290
  | Workspace tasks | `<workspace>/.hive/tasks.md` |
246
291
  | Internal `team` command | Packaged under `dist/bin/`, injected into PTYs |
247
292
  | Web UI assets | Served by the runtime from the packaged `web/dist` build |
@@ -267,6 +312,19 @@ Hive depends on `node-pty` and `better-sqlite3`, which use native binaries. Use
267
312
  Node.js 22+, keep your package manager cache clean, and verify your platform
268
313
  build tools are available.
269
314
 
315
+ When install succeeds but npm prints warnings, read them by source:
316
+
317
+ | warning | Source | What to do |
318
+ | --- | --- | --- |
319
+ | `allow-scripts @tt-a1i/hive` | Hive's postinstall fixes executable bits for packaged native / PTY helpers. | Safe to ignore after a successful install. |
320
+ | `allow-scripts better-sqlite3` | SQLite native bindings download a prebuilt binary, then fall back to local build. | Safe to ignore after success; check build tools only if install fails. |
321
+ | `allow-scripts node-pty` | The terminal PTY binding prepares platform binaries. | Safe to ignore after success; check build tools only if install fails. |
322
+ | `allow-scripts esbuild` | esbuild verifies/selects the binary package for the current platform. | Safe to ignore after a successful install. |
323
+
324
+ This is npm 11's install-script review notice. The current npm release still
325
+ treats it as advisory; future npm versions may require explicit approval. To
326
+ review the list yourself, run `npm approve-scripts --allow-scripts-pending`.
327
+
270
328
  If npm prints a deprecated warning for `prebuild-install@7.1.3`, it is safe to
271
329
  ignore. The warning comes from `better-sqlite3`'s native binary download chain;
272
330
  it is an upstream installer maintenance notice, not a Hive install failure, and
@@ -276,10 +334,14 @@ does not affect runtime behavior.
276
334
 
277
335
  Install `zenity`, or paste the workspace path manually.
278
336
 
279
- **Folder picker does not open on Windows**
337
+ **Folder picker on Windows**
280
338
 
281
- Verify Windows PowerShell is available as `powershell.exe`, or paste the
282
- workspace path manually.
339
+ Hive uses the in-browser server filesystem browser by default on Windows
340
+ instead of launching the PowerShell native folder picker. This avoids the
341
+ system dialog getting hidden behind the browser window. The browser starts at
342
+ "This PC" and lists accessible drives, so `C:\`, `D:\`, and other drives are
343
+ reachable. If the target directory is not visible in the browser list, expand
344
+ "Advanced: paste path" and enter the absolute path directly.
283
345
 
284
346
  **Tasks file conflict banner appears**
285
347
 
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  <img src="./assets/hive-hero.png" alt="Hive 本机多 agent 协作工作台" />
9
9
  </p>
10
10
 
11
- **Hive 是浏览器里的 Agent 协作工作台——一群 Agent 在你本机各自开工,一个当 Orchestrator 派活、归总进展,其余各司其职。** Orchestrator 本身就是一个真实的 `claude` / `codex` / `opencode` / `gemini` / `hermes` 进程——不是你、也不是脚本——它派单的 Worker 同样是真 CLI agent。所有 agent 都是本机真实的 PTY 进程,通过 Hive 注入到 shell 里的小型 `team` 协议互相通信,共享 `<workspace>/.hive/tasks.md` 这份 markdown 任务图。
11
+ **Hive 是浏览器里的 Agent 协作工作台——一群 Agent 在你本机各自开工,一个当 Orchestrator 派活、归总进展,其余各司其职。** Orchestrator 本身就是一个真实的 `agy` / `claude` / `codex` / `opencode` / `gemini` / `hermes` / `qwen` 进程——不是你、也不是脚本——它派单的 Worker 同样是真 CLI agent。所有 agent 都是本机真实的 PTY 进程,通过 Hive 注入到 shell 里的小型 `team` 协议互相通信,共享 `<workspace>/.hive/tasks.md` 这份 markdown 任务图。
12
12
 
13
13
  写代码、做调研、起草文档、做翻译——凡是能拆给一群人协作的脑力活,都可以让一群 Agent 合伙干。
14
14
 
@@ -58,6 +58,8 @@ npm install -g @tt-a1i/hive
58
58
  hive
59
59
  ```
60
60
 
61
+ 安装时如果看到 `npm warn allow-scripts` 或 `prebuild-install@7.1.3 deprecated`,先看最后是否显示 `added ... packages`。这些 warning 多数来自 npm 对安装脚本的安全审查,以及 `node-pty` / `better-sqlite3` / `esbuild` 这类原生依赖的二进制安装链路;不代表 Hive 启动失败。下面的故障排查里有逐项解释。
62
+
61
63
  打开终端打印出来的本机地址,通常是 `http://127.0.0.1:3000/`。如果你想指定端口,可以用 `hive --port 4010`。
62
64
 
63
65
  升级到最新版本:
@@ -122,11 +124,15 @@ Workspace 任务图:
122
124
 
123
125
  | 预设 | `PATH` 上的命令 | 默认 bypass 模式 | 会话恢复 |
124
126
  | --- | --- | --- | --- |
127
+ | Antigravity CLI | `agy` | `--dangerously-skip-permissions` | `--conversation <session_id>` |
125
128
  | Claude Code | `claude` | `--dangerously-skip-permissions`、`--permission-mode=bypassPermissions` | `--resume <session_id>` |
126
129
  | Codex | `codex` | `--dangerously-bypass-approvals-and-sandbox` | `resume <session_id>` |
127
130
  | OpenCode | `opencode` | 由 `~/.config/opencode/opencode.json` 配置 | `--session <session_id>` |
128
131
  | Gemini | `gemini` | `--yolo` | `--resume <session_id>` |
129
132
  | Hermes | `hermes` | `--yolo` | `--resume <session_id>` |
133
+ | Qwen Code | `qwen` | `--approval-mode yolo` | `--resume <session_id>` |
134
+ | Cursor CLI | `cursor` | `--force` | 暂未自动捕获 session id |
135
+ | Grok Build | `grok` | `--always-approve` | 暂未自动捕获 session id |
130
136
  | 自定义 | 任意可执行文件 | 自己配 | 自己配 |
131
137
 
132
138
  Hive 不替你安装这些 CLI。请在启动 Hive 的同一个 shell 环境里先装好、登录好。
@@ -142,9 +148,23 @@ Hive 不替你安装这些 CLI。请在启动 Hive 的同一个 shell 环境里
142
148
  - `.hive/tasks.md` 编辑器,带外部文件冲突处理。
143
149
  - PTY 后台保留 + 尽力使用各 CLI 原生 session 恢复。
144
150
  - 升级后的 What's New 弹窗,用简短 release highlights 告诉你新版改了什么。
145
- - 元数据存在本机 SQLite,默认在 `~/.config/hive`,或者通过 `$HIVE_DATA_DIR` 指定。
151
+ - 元数据存在本机 SQLite,Windows 默认在 `%APPDATA%\hive`,macOS / Linux 默认在 `~/.config/hive`,也可以通过 `$HIVE_DATA_DIR` 指定。
152
+
153
+ Hive **不**提供 sandbox 隔离、多用户认证,也不自带任何 agent 模型。它只负责调度你已经在用的本机 CLI。
154
+
155
+ ## 远程访问(可选,默认关闭)
156
+
157
+ 如果想在外面用手机查看、操作正在本机跑着的 Hive,可以开启可选的 **Remote access**。开启后,手机浏览器在网关上用 GitHub / Google 登录、跟桌面完成一次配对,就能通过端到端加密隧道访问**完整**的 Hive Web UI——已配对的手机是与本地浏览器**等权**的受信任设备。
158
+
159
+ 需要清楚的几点:
146
160
 
147
- Hive **不**提供 sandbox 隔离、多用户认证、云端托管,也不自带任何 agent 模型。它只负责调度你已经在用的本机 CLI。
161
+ - **默认关闭**。不开就没有任何出站连接、没有监听,行为跟现在一模一样。
162
+ - **需要一个网关**。隧道要经过一个网关中转(你本机的 daemon 主动出站连它,不开端口、不动路由器)。网关地址可配置:可以 **自己 self-host** 一个 Cloudflare Workers 网关,也可以接一个已部署的网关。Hive **没有**现成的一键托管服务——这一步要你自己搭。
163
+ - **数据和执行永远在本机**。网关只做身份(OAuth 登录)和路由,看不到明文——它只转发密文。网关挂了,本机 `127.0.0.1` 上的一切照常。
164
+ - **端到端加密**。手机 ↔ daemon 之间所有数据帧端到端加密,网关只见密文和路由头。诚实的边界:手机端的加密代码由网关分发(web 端 E2E 的经典局限,跟 Proton / WhatsApp Web 同类),缓解手段是 SRI + 版本化 bundle + PWA 缓存形成 TOFU。我们不宣传"网关被攻破也绝对安全"。
165
+ - **信任根在桌面**。新设备配对必须人在电脑前确认(桌面弹窗 + 6 位 SAS 短码校验);已配对手机不能凭自己批准新设备。设备随时可吊销。
166
+
167
+ 完整的开启、登录(`hive remote login`)、配对、吊销和 self-host 网关步骤见 [docs/remote-access.md](docs/remote-access.md)。
148
168
 
149
169
  ## 平台支持
150
170
 
@@ -167,7 +187,7 @@ Hive 是本机开发工具,**不是**托管服务。
167
187
 
168
188
  | 数据 | 位置 |
169
189
  | --- | --- |
170
- | Runtime 元数据 | `~/.config/hive` `$HIVE_DATA_DIR` |
190
+ | Runtime 元数据 | Windows: `%APPDATA%\hive`;macOS / Linux: `~/.config/hive`;或 `$HIVE_DATA_DIR` |
171
191
  | Workspace 任务图 | `<workspace>/.hive/tasks.md` |
172
192
  | 内部 `team` 命令 | 包内 `dist/bin/`,通过 PATH 注入 PTY |
173
193
  | Web UI 资源 | 由 runtime 从包内 `web/dist` 直接服务 |
@@ -190,15 +210,26 @@ hive --port 4020
190
210
 
191
211
  Hive 依赖 `node-pty` 和 `better-sqlite3`,它们用原生二进制。确认 Node.js 22+,清干净 package manager 缓存,并准备好你平台的构建工具(macOS Xcode CLI、Linux build-essential + python3、Windows VS Build Tools)。
192
212
 
213
+ 安装成功但看到 npm warning 时,可以按来源判断:
214
+
215
+ | warning | 来源 | 处理 |
216
+ | --- | --- | --- |
217
+ | `allow-scripts @tt-a1i/hive` | Hive 的 postinstall 会修正打包后的 native/PTY helper 权限。 | 安装成功后可忽略。 |
218
+ | `allow-scripts better-sqlite3` | SQLite 原生绑定需要下载预编译二进制,失败时会本机构建。 | 安装成功后可忽略;失败再检查构建工具链。 |
219
+ | `allow-scripts node-pty` | 终端 PTY 原生绑定需要准备平台二进制。 | 安装成功后可忽略;失败再检查构建工具链。 |
220
+ | `allow-scripts esbuild` | esbuild 会校验/选择当前平台的二进制包。 | 安装成功后可忽略。 |
221
+
222
+ 这是 npm 11 的安装脚本审查提示。当前 npm 版本仍是提示性质,未来可能要求用户显式批准这些脚本。你想审查时可以运行 `npm approve-scripts --allow-scripts-pending` 查看待审列表。
223
+
193
224
  安装时如果看到 `prebuild-install@7.1.3` 的 deprecated warning,可以忽略。它来自 `better-sqlite3` 的原生二进制下载链路,只是上游安装器维护状态提示,不代表 Hive 安装失败,也不会影响运行。
194
225
 
195
226
  **Linux 上目录选择器不弹**
196
227
 
197
228
  装 `zenity`,或者直接在对话框里粘路径。
198
229
 
199
- **Windows 上目录选择器不弹**
230
+ **Windows 上目录选择器**
200
231
 
201
- 确认 `powershell.exe` `PATH` 上,或者直接粘路径。
232
+ Windows 版默认使用浏览器内的服务器文件系统浏览器来添加 Workspace,不再弹 PowerShell 原生目录选择器。浏览器会从“此电脑”开始列出可访问盘符,所以可以进入 `C:\`、`D:\` 等其他盘;如果目标目录不在浏览器列表里,可以展开“高级:粘贴路径”直接输入绝对路径。
202
233
 
203
234
  **Tasks 文件冲突 banner 出现**
204
235
 
@@ -271,9 +302,11 @@ Hive 目前处于 alpha 阶段,核心流程已可用。当前重点是继续
271
302
  - **Claude Code 的 [Auto Dream](https://claudefa.st/blog/guide/mechanics/auto-dream)(俗称"做梦")** 走 **离线批处理** 路线:`/dream` 触发(或 24h 自动),Claude 在云端把 JSONL 会话归并去重抽模式,产出新版本 memory 库给你审查再采纳——像人类的 REM 睡眠,**清醒 / 睡眠二相**。
272
303
  - **Hermes Agent** 反过来走 **嵌入式 / 在场** 路线:不睡,每 N 轮对话后台 fork 一个 sub-agent review,结果直接落进本地的 **多层记忆**——`MEMORY.md`(事实/规则)·`USER.md`(用户画像)·SQLite + FTS5(情景检索)·Honcho(第三人称表征)·`skills/`(程序性记忆)——而且 agent 允许边走边改自己的 skill 文件,记忆和能力是一回事。
273
304
 
274
- 但 **这些都是单 agent 内部的记忆**。Hive 是多 agent 协作工作台,下一步要做的事是把它们打通:让整支团队 **共享一座长时记忆库**——Worker A 今天踩的坑,明天 Orchestrator 派给 Worker B 时能自动调来当上下文。
305
+ 但 **这些都是单 agent 内部的记忆**。Hive 是多 agent 协作工作台,正在把它们打通:让整支团队 **共享一座长时记忆库**——Worker A 今天踩的坑,明天 Orchestrator 派给 Worker B 时能自动调来当上下文。
306
+
307
+ 第一阶段先走本地优先:Hive 用 SQLite 保存协作历史和显式团队记忆,支持 `team recall` / `team memory`、派单和恢复时的自动注入、`<workspace>/.hive/memory.md` 单向导出,以及离线 Dream 整理。Dream 会按 workspace 空闲和增量阈值批处理协议消息,自动应用去重/改写/归档/新增,并保留 diff 报告和整次 run 的回滚入口。
275
308
 
276
- 底层我们计划接 **[EverOS](https://github.com/EverMind-AI/EverOS)**([EverMind](https://evermind.ai/) 出品的开源长时记忆 OS,目前在 LoCoMo / LongMemEval / HaluMem 三个记忆 benchmark 上 SOTA)当跨 agent 的记忆后端。它的四层架构(Agentic / Memory / Index / API+MCP)跟 Hive 的多 PTY 协作模型很搭:每个 agent 各跑各的 CLI session,团队级的事实和模式凝在 EverOS,Orchestrator 派单时一并喂给 worker。
309
+ 下一阶段再接 **[EverOS](https://github.com/EverMind-AI/EverOS)**([EverMind](https://evermind.ai/) 出品的开源长时记忆 OS,目前在 LoCoMo / LongMemEval / HaluMem 三个记忆 benchmark 上 SOTA)这类外部 provider。EverOS 的四层架构(Agentic / Memory / Index / API+MCP)跟 Hive 的多 PTY 协作模型很搭:每个 agent 各跑各的 CLI session,团队级的事实和模式凝在 provider,Orchestrator 派单时一并喂给 worker。
277
310
 
278
311
  进度跟踪:[#6](https://github.com/tt-a1i/hive/issues/6)——想看进度或提建议,在 issue 留 +1。
279
312
 
@@ -0,0 +1,46 @@
1
+ import { DEFAULT_GATEWAY_URL, REMOTE_DAEMON_ID_KEY, REMOTE_DAEMON_TOKEN_KEY, REMOTE_ENABLED_KEY, REMOTE_GATEWAY_URL_KEY } from '../server/remote-config-keys.js';
2
+ import { type RemoteDeviceRecord } from '../server/remote-device-store.js';
3
+ export { DEFAULT_GATEWAY_URL, REMOTE_DAEMON_ID_KEY, REMOTE_DAEMON_TOKEN_KEY, REMOTE_ENABLED_KEY, REMOTE_GATEWAY_URL_KEY, };
4
+ export declare const HIVE_REMOTE_USAGE: string;
5
+ export interface RemoteConfigStore {
6
+ get(key: string): {
7
+ value: string | null;
8
+ } | undefined;
9
+ set(key: string, value: string | null): void;
10
+ }
11
+ export interface RemoteDeviceListStore {
12
+ list(includeRevoked?: boolean): RemoteDeviceRecord[];
13
+ /** Idempotent; false if the device is unknown or already revoked. */
14
+ revoke(deviceId: string, now?: number): boolean;
15
+ }
16
+ export interface DaemonCodeResponse {
17
+ code: string;
18
+ expiresAt: number;
19
+ pollIntervalMs: number;
20
+ }
21
+ export interface DaemonTokenResponse {
22
+ daemonId: string;
23
+ daemonToken: string;
24
+ }
25
+ export interface GatewayClient {
26
+ requestCode(gatewayUrl: string): Promise<DaemonCodeResponse>;
27
+ exchangeToken(gatewayUrl: string, code: string, name?: string): Promise<DaemonTokenResponse | null>;
28
+ }
29
+ export declare const defaultGatewayClient: GatewayClient;
30
+ export interface RunHiveRemoteOptions {
31
+ /** Inject a fake gateway client (tests). */
32
+ client?: GatewayClient;
33
+ /** Inject an in-memory config store (tests); defaults to the runtime DB. */
34
+ config?: RemoteConfigStore;
35
+ /** Inject a device store (tests); defaults to the runtime DB's device store. */
36
+ deviceStore?: RemoteDeviceListStore;
37
+ /** Inject a clock for poll-timeout tests. */
38
+ now?: () => number;
39
+ /** Inject the poll delay so tests don't actually wait. */
40
+ sleep?: (ms: number) => Promise<void>;
41
+ /** stdout sink (defaults to console.log). */
42
+ log?: (line: string) => void;
43
+ /** stderr sink (defaults to console.error). */
44
+ error?: (line: string) => void;
45
+ }
46
+ export declare const runHiveRemoteCommand: (argv: string[], options?: RunHiveRemoteOptions) => Promise<number>;
@@ -0,0 +1,257 @@
1
+ import { createAppStateStore } from '../server/app-state-store.js';
2
+ import { getMachineName } from '../server/machine-name.js';
3
+ import { DEFAULT_GATEWAY_URL, REMOTE_DAEMON_ID_KEY, REMOTE_DAEMON_TOKEN_KEY, REMOTE_ENABLED_KEY, REMOTE_GATEWAY_URL_KEY, } from '../server/remote-config-keys.js';
4
+ import { createRemoteDeviceStore } from '../server/remote-device-store.js';
5
+ import { openRuntimeDatabase } from '../server/runtime-database.js';
6
+ import { resolveDataDir } from './hive.js';
7
+ // Re-export so existing callers (and the CLI tests) can keep importing the keys
8
+ // from here; the canonical definitions live in remote-config-keys.ts, shared
9
+ // with the daemon-side tunnel so the on-disk contract can't drift between sides.
10
+ export { DEFAULT_GATEWAY_URL, REMOTE_DAEMON_ID_KEY, REMOTE_DAEMON_TOKEN_KEY, REMOTE_ENABLED_KEY, REMOTE_GATEWAY_URL_KEY, };
11
+ // `hive remote` — manage the daemon's connection to the remote-access gateway.
12
+ //
13
+ // hive remote login [--gateway <url>] bind this machine to a Hive account
14
+ // hive remote status show connection + enabled state
15
+ // hive remote logout forget the gateway token, disable remote
16
+ // hive remote devices list paired phones/devices
17
+ // hive remote revoke <deviceId> revoke a paired device
18
+ //
19
+ // login drives the gateway's daemon-binding flow (gateway/src/daemon.ts):
20
+ // POST /daemon/code -> { code, expiresAt, pollIntervalMs } (print URL + code)
21
+ // ... human approves in their logged-in browser at /daemon/approve?code=... ...
22
+ // POST /daemon/token -> 401 not_approved (keep polling) | 200 { daemonId, daemonToken }
23
+ //
24
+ // The token is account-scoped and is local RCE on this machine, so it lands in
25
+ // app_state (the same SQLite the daemon reads) and is NEVER printed back.
26
+ // `enabled` defaults OFF for the whole subsystem; a successful login flips it on.
27
+ // Off == zero behavior change: no token, no outbound tunnel (see remote-tunnel).
28
+ export const HIVE_REMOTE_USAGE = [
29
+ 'Usage:',
30
+ ' hive remote login [--gateway <url>] Link this machine to your Hive account.',
31
+ ' hive remote status Show remote-access connection state.',
32
+ ' hive remote logout Forget the gateway token and disable remote.',
33
+ ' hive remote devices List paired devices.',
34
+ ' hive remote revoke <deviceId> Revoke a paired device.',
35
+ '',
36
+ 'Remote access lets you reach this Hive from a phone through the gateway over',
37
+ 'an end-to-end encrypted tunnel. It is OFF until you log in, and `logout`',
38
+ 'turns it off again. The gateway only relays ciphertext — it never sees your',
39
+ 'data or terminals.',
40
+ '',
41
+ 'Options:',
42
+ ` --gateway <url> Gateway base URL (default: ${DEFAULT_GATEWAY_URL}).`,
43
+ ' -h, --help Print this help.',
44
+ ].join('\n');
45
+ const openConfigStore = () => {
46
+ const db = openRuntimeDatabase(resolveDataDir());
47
+ return { store: createAppStateStore(db), close: () => db.close() };
48
+ };
49
+ const readConfig = (store, key) => store.get(key)?.value ?? null;
50
+ const openDeviceStore = () => {
51
+ const db = openRuntimeDatabase(resolveDataDir());
52
+ return { store: createRemoteDeviceStore(db), close: () => db.close() };
53
+ };
54
+ const trimSlash = (url) => url.replace(/\/+$/, '');
55
+ const postJson = async (url, body, token) => {
56
+ const headers = { 'content-type': 'application/json' };
57
+ if (token)
58
+ headers.authorization = `Bearer ${token}`;
59
+ return fetch(url, { method: 'POST', headers, body: JSON.stringify(body) });
60
+ };
61
+ // Default client: real fetch against the gateway. The contracts mirror
62
+ // gateway/src/daemon.ts exactly (field names, the 401 not_approved poll signal).
63
+ export const defaultGatewayClient = {
64
+ async requestCode(gatewayUrl) {
65
+ const res = await postJson(`${trimSlash(gatewayUrl)}/daemon/code`, {});
66
+ if (!res.ok)
67
+ throw new Error(`gateway /daemon/code failed: ${res.status}`);
68
+ const body = (await res.json());
69
+ if (typeof body.code !== 'string' || typeof body.expiresAt !== 'number') {
70
+ throw new Error('gateway /daemon/code returned an unexpected response');
71
+ }
72
+ return {
73
+ code: body.code,
74
+ expiresAt: body.expiresAt,
75
+ pollIntervalMs: typeof body.pollIntervalMs === 'number' ? body.pollIntervalMs : 2000,
76
+ };
77
+ },
78
+ async exchangeToken(gatewayUrl, code, name) {
79
+ const payload = { code };
80
+ if (name)
81
+ payload.name = name;
82
+ const res = await postJson(`${trimSlash(gatewayUrl)}/daemon/token`, payload);
83
+ // 401 == not yet approved (or expired). 429 == the gateway throttled this poll. Both mean "keep
84
+ // polling until the code's expiresAt" — a transient 429 mid-wait must NOT kill the login (the
85
+ // gateway sizes the /daemon/token budget for the poll cadence, but we stay robust if it ever
86
+ // trips). Any other non-2xx is a hard failure.
87
+ if (res.status === 401 || res.status === 429)
88
+ return null;
89
+ if (!res.ok)
90
+ throw new Error(`gateway /daemon/token failed: ${res.status}`);
91
+ const body = (await res.json());
92
+ if (typeof body.daemonId !== 'string' || typeof body.daemonToken !== 'string') {
93
+ throw new Error('gateway /daemon/token returned an unexpected response');
94
+ }
95
+ return { daemonId: body.daemonId, daemonToken: body.daemonToken };
96
+ },
97
+ };
98
+ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
99
+ const readGatewayFlag = (argv) => {
100
+ const index = argv.indexOf('--gateway');
101
+ if (index === -1)
102
+ return undefined;
103
+ const value = argv[index + 1];
104
+ if (!value || value.startsWith('-')) {
105
+ throw new Error('Usage: hive remote login [--gateway <url>]');
106
+ }
107
+ return value;
108
+ };
109
+ const approveUrl = (gatewayUrl, code) => `${trimSlash(gatewayUrl)}/daemon/approve?code=${encodeURIComponent(code)}`;
110
+ const runLogin = async (argv, store, client, now, sleep, log) => {
111
+ const gatewayUrl = readGatewayFlag(argv) ?? readConfig(store, REMOTE_GATEWAY_URL_KEY) ?? DEFAULT_GATEWAY_URL;
112
+ const { code, expiresAt, pollIntervalMs } = await client.requestCode(gatewayUrl);
113
+ log('To link this machine, open the approval page in a browser where you are');
114
+ log('logged in to your Hive account, and confirm the code matches:');
115
+ log('');
116
+ log(` ${approveUrl(gatewayUrl, code)}`);
117
+ log('');
118
+ log(` Code: ${code}`);
119
+ log('');
120
+ log('Waiting for approval…');
121
+ const machineName = getMachineName() ?? undefined;
122
+ // Poll until the human approves or the code expires. The gateway hands back
123
+ // null (HTTP 401) until approval flips the code; we never bail early.
124
+ for (;;) {
125
+ const token = await client.exchangeToken(gatewayUrl, code, machineName);
126
+ if (token) {
127
+ store.set(REMOTE_GATEWAY_URL_KEY, gatewayUrl);
128
+ store.set(REMOTE_DAEMON_ID_KEY, token.daemonId);
129
+ store.set(REMOTE_DAEMON_TOKEN_KEY, token.daemonToken);
130
+ store.set(REMOTE_ENABLED_KEY, 'true');
131
+ log('');
132
+ log('This machine is linked. Remote access is now enabled.');
133
+ log('Restart the Hive runtime (or it will connect on next start) to bring');
134
+ log('the tunnel online. Pair a phone from Settings → Remote access.');
135
+ return 0;
136
+ }
137
+ if (now() >= expiresAt) {
138
+ log('');
139
+ log('The login code expired before it was approved. Run `hive remote login` again.');
140
+ return 1;
141
+ }
142
+ await sleep(pollIntervalMs);
143
+ }
144
+ };
145
+ const runStatus = (store, log) => {
146
+ const enabled = readConfig(store, REMOTE_ENABLED_KEY) === 'true';
147
+ const gatewayUrl = readConfig(store, REMOTE_GATEWAY_URL_KEY);
148
+ const daemonId = readConfig(store, REMOTE_DAEMON_ID_KEY);
149
+ const loggedIn = readConfig(store, REMOTE_DAEMON_TOKEN_KEY) !== null;
150
+ log(`Remote access: ${enabled ? 'enabled' : 'disabled'}`);
151
+ log(`Logged in: ${loggedIn ? 'yes' : 'no'}`);
152
+ // The token is secret and is intentionally never printed.
153
+ if (gatewayUrl)
154
+ log(`Gateway: ${gatewayUrl}`);
155
+ if (daemonId)
156
+ log(`Machine id: ${daemonId}`);
157
+ if (!loggedIn)
158
+ log('Run `hive remote login` to link this machine.');
159
+ return 0;
160
+ };
161
+ const runLogout = (store, log) => {
162
+ const wasLoggedIn = readConfig(store, REMOTE_DAEMON_TOKEN_KEY) !== null;
163
+ store.set(REMOTE_DAEMON_TOKEN_KEY, null);
164
+ store.set(REMOTE_DAEMON_ID_KEY, null);
165
+ store.set(REMOTE_ENABLED_KEY, 'false');
166
+ log(wasLoggedIn
167
+ ? 'Logged out. Remote access is disabled and the gateway token has been forgotten.'
168
+ : 'Not logged in. Remote access is disabled.');
169
+ return 0;
170
+ };
171
+ const runDevices = (store, log) => {
172
+ const devices = store.list(true); // include revoked so the operator sees the full roster
173
+ if (devices.length === 0) {
174
+ log('No paired devices. Pair a phone from Settings → Remote access.');
175
+ return 0;
176
+ }
177
+ for (const device of devices) {
178
+ const lastSeen = device.lastActive ? new Date(device.lastActive).toISOString() : 'never';
179
+ const status = device.revokedAt ? ' (revoked)' : '';
180
+ log(`${device.id} ${device.name} last active ${lastSeen}${status}`);
181
+ }
182
+ return 0;
183
+ };
184
+ const runRevoke = (deviceId, store, log, error) => {
185
+ if (!deviceId) {
186
+ error('Usage: hive remote revoke <deviceId>');
187
+ return 1;
188
+ }
189
+ const revoked = store.revoke(deviceId);
190
+ if (!revoked) {
191
+ error(`Unknown or already-revoked device: ${deviceId}`);
192
+ return 1;
193
+ }
194
+ // The daemon's provider reads live sessions fresh, so the device is refused on its
195
+ // next frame. To tear down an IN-PROGRESS session immediately, revoke from
196
+ // Settings → Remote access (which fires the live closed-loop disconnect).
197
+ log(`Revoked device ${deviceId}. It is refused on its next connection.`);
198
+ return 0;
199
+ };
200
+ export const runHiveRemoteCommand = async (argv, options = {}) => {
201
+ if (argv.length === 0 || argv.includes('--help') || argv.includes('-h')) {
202
+ const log = options.log ?? console.log;
203
+ log(HIVE_REMOTE_USAGE);
204
+ return argv.length === 0 ? 1 : 0;
205
+ }
206
+ const [subcommand, ...rest] = argv;
207
+ const client = options.client ?? defaultGatewayClient;
208
+ const now = options.now ?? Date.now;
209
+ const sleep = options.sleep ?? defaultSleep;
210
+ const log = options.log ?? console.log;
211
+ const error = options.error ?? console.error;
212
+ // Open the config store lazily so --help / unknown subcommands don't touch
213
+ // the DB, and always close an owned handle.
214
+ // Annotated as a possibly-undefined holder so TS doesn't narrow it to `never`
215
+ // in the finally block (the assignment happens inside resolveStore's closure,
216
+ // which control-flow analysis can't see executing).
217
+ const owned = {};
218
+ const resolveStore = () => {
219
+ if (options.config)
220
+ return options.config;
221
+ const opened = openConfigStore();
222
+ owned.close = opened.close;
223
+ return opened.store;
224
+ };
225
+ const resolveDeviceStore = () => {
226
+ if (options.deviceStore)
227
+ return options.deviceStore;
228
+ const opened = openDeviceStore();
229
+ owned.close = opened.close;
230
+ return opened.store;
231
+ };
232
+ try {
233
+ switch (subcommand) {
234
+ case 'login':
235
+ return await runLogin(rest, resolveStore(), client, now, sleep, log);
236
+ case 'status':
237
+ return runStatus(resolveStore(), log);
238
+ case 'logout':
239
+ return runLogout(resolveStore(), log);
240
+ case 'devices':
241
+ return runDevices(resolveDeviceStore(), log);
242
+ case 'revoke':
243
+ return runRevoke(rest[0], resolveDeviceStore(), log, error);
244
+ default:
245
+ error(`Unknown remote subcommand: ${subcommand}`);
246
+ error(HIVE_REMOTE_USAGE);
247
+ return 1;
248
+ }
249
+ }
250
+ catch (err) {
251
+ error(err instanceof Error ? err.message : String(err));
252
+ return 1;
253
+ }
254
+ finally {
255
+ owned.close?.();
256
+ }
257
+ };
@@ -173,7 +173,12 @@ export const resolveHiveUpdateInstallArgs = (moduleUrl = import.meta.url) => {
173
173
  return [...INSTALL_COMMAND_ARGS];
174
174
  return [...INSTALL_COMMAND_ARGS, '--prefix', prefix];
175
175
  };
176
- const formatInstallCommand = (args) => `npm ${args.map(shellQuote).join(' ')}`;
176
+ const windowsQuote = (value) => {
177
+ if (/^[-A-Za-z0-9_/:=.,@+\\]+$/.test(value))
178
+ return value;
179
+ return `"${value.replace(/"/g, '""')}"`;
180
+ };
181
+ const formatInstallCommand = (args, platform = process.platform) => `npm ${args.map(platform === 'win32' ? windowsQuote : shellQuote).join(' ')}`;
177
182
  export const runHiveUpdateCommand = async (argv, options = {}) => {
178
183
  if (argv.includes('--help') || argv.includes('-h')) {
179
184
  console.log(HIVE_UPDATE_USAGE);
@@ -190,7 +195,7 @@ export const runHiveUpdateCommand = async (argv, options = {}) => {
190
195
  const run = options.runUpdate ?? defaultRunUpdate;
191
196
  const command = getNpmCommand(options.platform);
192
197
  const args = resolveHiveUpdateInstallArgs(options.moduleUrl);
193
- const displayCommand = formatInstallCommand(args);
198
+ const displayCommand = formatInstallCommand(args, options.platform);
194
199
  console.log(`Running: ${displayCommand}`);
195
200
  const result = await run(command, args);
196
201
  if (result.spawnError) {