@tt-a1i/hive 1.7.0 → 2.0.2
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/CHANGELOG.md +60 -0
- package/README.en.md +73 -11
- package/README.md +41 -8
- package/dist/src/cli/hive-remote.d.ts +46 -0
- package/dist/src/cli/hive-remote.js +257 -0
- package/dist/src/cli/hive-update.js +7 -2
- package/dist/src/cli/hive.d.ts +6 -0
- package/dist/src/cli/hive.js +64 -0
- package/dist/src/cli/team.d.ts +22 -0
- package/dist/src/cli/team.js +255 -5
- package/dist/src/server/agent-command-resolver.js +10 -3
- package/dist/src/server/agent-exit-classification.d.ts +6 -0
- package/dist/src/server/agent-exit-classification.js +6 -0
- package/dist/src/server/agent-manager-support.d.ts +2 -1
- package/dist/src/server/agent-manager-support.js +59 -15
- package/dist/src/server/agent-manager.d.ts +3 -0
- package/dist/src/server/agent-manager.js +22 -7
- package/dist/src/server/agent-run-bootstrap.d.ts +14 -0
- package/dist/src/server/agent-run-bootstrap.js +11 -4
- package/dist/src/server/agent-run-exit-handler.js +14 -8
- package/dist/src/server/agent-run-starter.d.ts +3 -1
- package/dist/src/server/agent-run-starter.js +22 -5
- package/dist/src/server/agent-run-sync.js +13 -5
- package/dist/src/server/agent-runtime-types.d.ts +1 -0
- package/dist/src/server/agent-runtime.d.ts +2 -1
- package/dist/src/server/agent-runtime.js +9 -2
- package/dist/src/server/agent-startup-instructions.d.ts +2 -1
- package/dist/src/server/agent-startup-instructions.js +8 -4
- package/dist/src/server/agent-stdin-dispatcher.d.ts +4 -2
- package/dist/src/server/agent-stdin-dispatcher.js +35 -3
- package/dist/src/server/command-preset-defaults.d.ts +6 -1
- package/dist/src/server/command-preset-defaults.js +56 -0
- package/dist/src/server/fs-browse.d.ts +2 -0
- package/dist/src/server/fs-browse.js +165 -31
- package/dist/src/server/fs-pick-folder.js +6 -69
- package/dist/src/server/fs-sandbox.d.ts +5 -3
- package/dist/src/server/fs-sandbox.js +5 -3
- package/dist/src/server/hive-team-guidance.js +18 -6
- package/dist/src/server/machine-name.d.ts +2 -0
- package/dist/src/server/machine-name.js +13 -0
- package/dist/src/server/open-target-commands.d.ts +1 -0
- package/dist/src/server/open-target-commands.js +4 -1
- package/dist/src/server/orchestrator-autostart.js +1 -1
- package/dist/src/server/platform-path.d.ts +1 -0
- package/dist/src/server/platform-path.js +14 -1
- package/dist/src/server/post-start-input-writer.js +50 -13
- package/dist/src/server/preset-launch-support.js +1 -0
- package/dist/src/server/recovery-summary.d.ts +2 -1
- package/dist/src/server/recovery-summary.js +2 -1
- package/dist/src/server/remote-audit-store.d.ts +51 -0
- package/dist/src/server/remote-audit-store.js +108 -0
- package/dist/src/server/remote-config-keys.d.ts +17 -0
- package/dist/src/server/remote-config-keys.js +27 -0
- package/dist/src/server/remote-control-constants.d.ts +30 -0
- package/dist/src/server/remote-control-constants.js +29 -0
- package/dist/src/server/remote-device-session.d.ts +40 -0
- package/dist/src/server/remote-device-session.js +22 -0
- package/dist/src/server/remote-device-store.d.ts +36 -0
- package/dist/src/server/remote-device-store.js +67 -0
- package/dist/src/server/remote-frame-bridge.d.ts +102 -0
- package/dist/src/server/remote-frame-bridge.js +791 -0
- package/dist/src/server/remote-gateway-client.d.ts +14 -0
- package/dist/src/server/remote-gateway-client.js +36 -0
- package/dist/src/server/remote-loopback-auth.d.ts +6 -0
- package/dist/src/server/remote-loopback-auth.js +112 -0
- package/dist/src/server/remote-pairing-tunnel.d.ts +59 -0
- package/dist/src/server/remote-pairing-tunnel.js +146 -0
- package/dist/src/server/remote-pairing.d.ts +58 -0
- package/dist/src/server/remote-pairing.js +237 -0
- package/dist/src/server/remote-tunnel.d.ts +113 -0
- package/dist/src/server/remote-tunnel.js +514 -0
- package/dist/src/server/restart-policy-support.d.ts +4 -1
- package/dist/src/server/restart-policy-support.js +3 -1
- package/dist/src/server/restart-policy.d.ts +1 -1
- package/dist/src/server/restart-policy.js +19 -3
- package/dist/src/server/route-types.d.ts +1 -1
- package/dist/src/server/routes-dispatches.js +1 -1
- package/dist/src/server/routes-fs.js +3 -3
- package/dist/src/server/routes-marketplace.js +2 -2
- package/dist/src/server/routes-open-workspace.js +1 -1
- package/dist/src/server/routes-remote.d.ts +2 -0
- package/dist/src/server/routes-remote.js +166 -0
- package/dist/src/server/routes-runtime.js +6 -6
- package/dist/src/server/routes-settings.js +16 -16
- package/dist/src/server/routes-tasks.js +2 -2
- package/dist/src/server/routes-team-memory.d.ts +2 -0
- package/dist/src/server/routes-team-memory.js +154 -0
- package/dist/src/server/routes-team-recall.d.ts +2 -0
- package/dist/src/server/routes-team-recall.js +119 -0
- package/dist/src/server/routes-team.js +31 -9
- package/dist/src/server/routes-ui.js +11 -1
- package/dist/src/server/routes-workflow-schedules.js +3 -3
- package/dist/src/server/routes-workflows.js +5 -5
- package/dist/src/server/routes-workspace-memory-dreams.d.ts +2 -0
- package/dist/src/server/routes-workspace-memory-dreams.js +105 -0
- package/dist/src/server/routes-workspace-memory.d.ts +2 -0
- package/dist/src/server/routes-workspace-memory.js +215 -0
- package/dist/src/server/routes-workspaces.js +9 -9
- package/dist/src/server/routes.js +10 -0
- package/dist/src/server/runtime-database.d.ts +1 -0
- package/dist/src/server/runtime-database.js +27 -2
- package/dist/src/server/runtime-restart-policy.d.ts +3 -1
- package/dist/src/server/runtime-restart-policy.js +2 -1
- package/dist/src/server/runtime-store-contract.d.ts +37 -0
- package/dist/src/server/runtime-store-dream.d.ts +23 -0
- package/dist/src/server/runtime-store-dream.js +16 -0
- package/dist/src/server/runtime-store-helpers.d.ts +20 -0
- package/dist/src/server/runtime-store-helpers.js +81 -7
- package/dist/src/server/runtime-store-memory.d.ts +33 -0
- package/dist/src/server/runtime-store-memory.js +37 -0
- package/dist/src/server/runtime-store-remote.d.ts +5 -0
- package/dist/src/server/runtime-store-remote.js +45 -0
- package/dist/src/server/runtime-store-workflows.js +2 -0
- package/dist/src/server/runtime-store.js +14 -3
- package/dist/src/server/session-capture-claude.d.ts +1 -1
- package/dist/src/server/session-capture-claude.js +7 -4
- package/dist/src/server/session-capture-codex.js +4 -5
- package/dist/src/server/session-capture-gemini.js +4 -5
- package/dist/src/server/session-capture-opencode.d.ts +4 -4
- package/dist/src/server/session-capture-opencode.js +20 -12
- package/dist/src/server/session-capture-qwen.d.ts +5 -0
- package/dist/src/server/session-capture-qwen.js +104 -0
- package/dist/src/server/session-capture.d.ts +17 -0
- package/dist/src/server/session-capture.js +16 -0
- package/dist/src/server/sqlite-schema-v23.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v23.js +43 -0
- package/dist/src/server/sqlite-schema-v24.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v24.js +34 -0
- package/dist/src/server/sqlite-schema-v25.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v25.js +127 -0
- package/dist/src/server/sqlite-schema-v26.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v26.js +56 -0
- package/dist/src/server/sqlite-schema-v27.d.ts +6 -0
- package/dist/src/server/sqlite-schema-v27.js +92 -0
- package/dist/src/server/sqlite-schema-v28.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v28.js +19 -0
- package/dist/src/server/sqlite-schema-v29.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v29.js +27 -0
- package/dist/src/server/sqlite-schema-v30.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v30.js +27 -0
- package/dist/src/server/sqlite-schema-v31.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v31.js +30 -0
- package/dist/src/server/sqlite-schema.d.ts +1 -1
- package/dist/src/server/sqlite-schema.js +49 -1
- package/dist/src/server/startup-command-parser.js +5 -1
- package/dist/src/server/tasks-file-watcher.d.ts +2 -0
- package/dist/src/server/tasks-file-watcher.js +15 -6
- package/dist/src/server/tasks-file.js +30 -5
- package/dist/src/server/tasks-websocket-server.js +4 -0
- package/dist/src/server/team-authz.d.ts +1 -1
- package/dist/src/server/team-authz.js +13 -1
- package/dist/src/server/team-list-enrichment.js +3 -1
- package/dist/src/server/team-memory-digest.d.ts +52 -0
- package/dist/src/server/team-memory-digest.js +200 -0
- package/dist/src/server/team-memory-dream-applier.d.ts +5 -0
- package/dist/src/server/team-memory-dream-applier.js +234 -0
- package/dist/src/server/team-memory-dream-http-serializers.d.ts +13 -0
- package/dist/src/server/team-memory-dream-http-serializers.js +12 -0
- package/dist/src/server/team-memory-dream-ops.d.ts +40 -0
- package/dist/src/server/team-memory-dream-ops.js +153 -0
- package/dist/src/server/team-memory-dream-reverter.d.ts +22 -0
- package/dist/src/server/team-memory-dream-reverter.js +221 -0
- package/dist/src/server/team-memory-dream-run-store.d.ts +23 -0
- package/dist/src/server/team-memory-dream-run-store.js +211 -0
- package/dist/src/server/team-memory-dream-runner.d.ts +37 -0
- package/dist/src/server/team-memory-dream-runner.js +178 -0
- package/dist/src/server/team-memory-dream-scheduler.d.ts +32 -0
- package/dist/src/server/team-memory-dream-scheduler.js +115 -0
- package/dist/src/server/team-memory-dream-store.d.ts +19 -0
- package/dist/src/server/team-memory-dream-store.js +16 -0
- package/dist/src/server/team-memory-dream-types.d.ts +104 -0
- package/dist/src/server/team-memory-dream-types.js +23 -0
- package/dist/src/server/team-memory-export.d.ts +22 -0
- package/dist/src/server/team-memory-export.js +220 -0
- package/dist/src/server/team-memory-feature.d.ts +12 -0
- package/dist/src/server/team-memory-feature.js +12 -0
- package/dist/src/server/team-memory-http-serializers.d.ts +102 -0
- package/dist/src/server/team-memory-http-serializers.js +46 -0
- package/dist/src/server/team-memory-injection.d.ts +31 -0
- package/dist/src/server/team-memory-injection.js +49 -0
- package/dist/src/server/team-memory-store.d.ts +116 -0
- package/dist/src/server/team-memory-store.js +513 -0
- package/dist/src/server/team-operations.d.ts +5 -1
- package/dist/src/server/team-operations.js +46 -16
- package/dist/src/server/team-recall-store.d.ts +38 -0
- package/dist/src/server/team-recall-store.js +205 -0
- package/dist/src/server/terminal-input-profile.d.ts +1 -1
- package/dist/src/server/terminal-input-profile.js +18 -0
- package/dist/src/server/terminal-ws-server.js +6 -0
- package/dist/src/server/ui-auth-helpers.d.ts +1 -1
- package/dist/src/server/ui-auth-helpers.js +7 -1
- package/dist/src/server/ui-auth.d.ts +3 -0
- package/dist/src/server/ui-auth.js +21 -1
- package/dist/src/server/workflow-cli-policy.d.ts +2 -3
- package/dist/src/server/workflow-cli-policy.js +3 -3
- package/dist/src/server/workflow-runner.d.ts +1 -0
- package/dist/src/server/workflow-runner.js +9 -4
- package/dist/src/server/workspace-path-validation.js +6 -2
- package/dist/src/server/workspace-store.d.ts +1 -1
- package/dist/src/server/workspace-store.js +35 -9
- package/dist/src/shared/fs-browse.d.ts +1 -0
- package/dist/src/shared/fs-browse.js +1 -0
- package/dist/src/shared/path-input.d.ts +12 -0
- package/dist/src/shared/path-input.js +22 -0
- package/dist/src/shared/remote-bridge-routing.d.ts +19 -0
- package/dist/src/shared/remote-bridge-routing.js +141 -0
- package/dist/src/shared/remote-crypto.d.ts +138 -0
- package/dist/src/shared/remote-crypto.js +427 -0
- package/dist/src/shared/remote-pairing-code.d.ts +7 -0
- package/dist/src/shared/remote-pairing-code.js +47 -0
- package/dist/src/shared/remote-protocol.d.ts +160 -0
- package/dist/src/shared/remote-protocol.js +526 -0
- package/dist/src/shared/team-memory.d.ts +11 -0
- package/dist/src/shared/team-memory.js +10 -0
- package/dist/src/shared/team-recall.d.ts +1 -0
- package/dist/src/shared/team-recall.js +1 -0
- package/dist/src/shared/types.d.ts +4 -5
- package/package.json +12 -5
- package/scripts/postinstall-native-artifacts.mjs +113 -0
- package/web/dist/assets/AddWorkerDialog-CbV75qUX.js +2 -0
- package/web/dist/assets/AddWorkspaceFlow-CwV-7wPx.js +1 -0
- package/web/dist/assets/FirstRunWizard-a6PWIK3x.js +1 -0
- package/web/dist/assets/MarketplaceDrawer-Dd8WIA8T.js +67 -0
- package/web/dist/assets/TaskGraphDrawer-Bk5WFIk_.js +1 -0
- package/web/dist/assets/{WhatsNewDialog-CHkZeINH.js → WhatsNewDialog-C2VZaip0.js} +1 -1
- package/web/dist/assets/WorkerModal-DucW-9YT.js +1 -0
- package/web/dist/assets/WorkflowsDrawer-Bjf4olbR.js +1 -0
- package/web/dist/assets/WorkspaceMemoryDrawer-DglCy_5f.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-BIWwISvA.js +1 -0
- package/web/dist/assets/index-BAiLYajK.css +1 -0
- package/web/dist/assets/index-BV2k9Dts.js +73 -0
- package/web/dist/assets/search-Bk2HQvO7.js +1 -0
- package/web/dist/assets/square-terminal-D93m9hfY.js +1 -0
- package/web/dist/cli-icons/agy.png +0 -0
- package/web/dist/cli-icons/cursor.ico +0 -0
- package/web/dist/cli-icons/grok.ico +0 -0
- package/web/dist/cli-icons/qwen.png +0 -0
- package/web/dist/index.html +8 -3
- package/web/dist/sw.js +1 -1
- package/scripts/fix-runtime-artifacts.mjs +0 -33
- package/web/dist/assets/AddWorkerDialog-BRUxpa3f.js +0 -2
- package/web/dist/assets/AddWorkspaceDialog-D56x5JCb.js +0 -1
- package/web/dist/assets/FirstRunWizard-BFVaMIsE.js +0 -1
- package/web/dist/assets/MarketplaceDrawer-DeEZ35dN.js +0 -76
- package/web/dist/assets/WorkerModal-BBCuMLIa.js +0 -1
- package/web/dist/assets/WorkspaceTaskDrawer-CpZHAcj1.js +0 -1
- package/web/dist/assets/WorkspaceTerminalPanels-7If2mDyp.js +0 -1
- package/web/dist/assets/WorkspaceTerminalPanels-DDGTF8rc.css +0 -1
- package/web/dist/assets/index-5zh61jMg.css +0 -1
- package/web/dist/assets/index-CxNL0O-C.js +0 -73
- package/web/dist/assets/path-join-7MR1s7b1.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
All notable user-facing changes will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 2.0.2 - 2026-06-10
|
|
6
|
+
|
|
7
|
+
Windows Codex terminal scrolling fix.
|
|
8
|
+
|
|
9
|
+
- Fixes Codex terminal scrolling for Windows installs whose saved launch
|
|
10
|
+
command still points at `node.exe ...\@openai\codex\bin\codex.js`, so Hive
|
|
11
|
+
now applies the Codex-specific wheel/PageUp/PageDown input profile instead of
|
|
12
|
+
treating the session like a plain shell.
|
|
13
|
+
|
|
14
|
+
## 2.0.1 - 2026-06-09
|
|
15
|
+
|
|
16
|
+
Team memory, worker-card polish, and release-channel cleanup.
|
|
17
|
+
|
|
18
|
+
- Adds ambient team memory so Hive can retain useful workspace context and
|
|
19
|
+
surface it again when you need the team to remember prior decisions,
|
|
20
|
+
constraints, or project notes.
|
|
21
|
+
- Refines the Memory and Workflows drawers with better desktop/mobile layouts,
|
|
22
|
+
clearer tabs, and a search field that stays out of the way on wide screens.
|
|
23
|
+
- Redesigns worker cards for stronger scanability: clearer status treatment,
|
|
24
|
+
higher contrast, cleaner role text, and an in-place rename flow instead of a
|
|
25
|
+
separate edit dialog.
|
|
26
|
+
- Clarifies pending dispatch status so queued or waiting worker activity is
|
|
27
|
+
easier to understand while the Orchestrator is coordinating work.
|
|
28
|
+
- Publishes the current remote/mobile build under the original official
|
|
29
|
+
`@tt-a1i/hive` package name.
|
|
30
|
+
|
|
31
|
+
## 2.0.0 - 2026-06-07
|
|
32
|
+
|
|
33
|
+
Remote access, mobile control, and the production gateway.
|
|
34
|
+
|
|
35
|
+
- Adds optional Remote access so you can open your running Hive from a phone
|
|
36
|
+
browser. Remote is off by default; when enabled, the phone connects through
|
|
37
|
+
an end-to-end encrypted tunnel and gets the same authority as the local
|
|
38
|
+
desktop browser.
|
|
39
|
+
- Ships the Cloudflare Workers gateway stack for identity and routing: GitHub
|
|
40
|
+
and Google sign-in, Durable Object relay, D1-backed daemon/device records,
|
|
41
|
+
rate limiting, version-pinned mobile bundles, and deployment runbooks for
|
|
42
|
+
self-hosting or pointing Hive at an existing gateway.
|
|
43
|
+
- Adds the desktop trust-root pairing flow. The desktop creates a short-lived
|
|
44
|
+
pairing code, the phone enters it after selecting the machine, both sides
|
|
45
|
+
show a 6-digit SAS code, and the device is stored only after desktop
|
|
46
|
+
confirmation.
|
|
47
|
+
- Adds remote device management: list paired devices, revoke them from
|
|
48
|
+
Settings or the CLI, drop live sessions immediately from the Settings panel,
|
|
49
|
+
and review an audit trail of remote requests and denials.
|
|
50
|
+
- Adds `hive remote login`, `status`, `logout`, `devices`, and `revoke` for
|
|
51
|
+
linking the machine to a gateway account and managing paired devices from
|
|
52
|
+
the host itself.
|
|
53
|
+
- Adds the mobile Hive shell: sign-in/connect screens, machine list, bottom
|
|
54
|
+
navigation, workspace switching, full-screen team/task panels, and
|
|
55
|
+
remote-aware reconnect and update prompts.
|
|
56
|
+
- Makes phone terminals writable through the terminal itself. Worker terminals
|
|
57
|
+
can be opened full-screen, mobile focus mode hides surrounding chrome while
|
|
58
|
+
you work, and terminal touch scrolling now tracks the finger more closely
|
|
59
|
+
with smoother normal-buffer glide and faster alternate-screen movement.
|
|
60
|
+
- Preserves local-first behavior: local `127.0.0.1` Hive keeps working without
|
|
61
|
+
a gateway, remote access is path-whitelisted to Hive's own `/api/*` and
|
|
62
|
+
`/ws/*`, and paired phones cannot approve new devices or turn Remote access
|
|
63
|
+
back on after it has been disabled.
|
|
64
|
+
|
|
5
65
|
## 1.7.0 - 2026-06-05
|
|
6
66
|
|
|
7
67
|
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
|
|
203
|
-
when set.
|
|
204
|
-
|
|
205
|
-
Hive does not provide sandboxing, multi-user auth,
|
|
206
|
-
|
|
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.
|
|
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
|
|
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
|
|
337
|
+
**Folder picker on Windows**
|
|
280
338
|
|
|
281
|
-
|
|
282
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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) {
|