@tt-a1i/hive 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.en.md +15 -6
  3. package/README.md +26 -4
  4. package/dist/src/cli/hive.d.ts +4 -0
  5. package/dist/src/cli/hive.js +25 -3
  6. package/dist/src/cli/team.d.ts +8 -1
  7. package/dist/src/cli/team.js +111 -11
  8. package/dist/src/server/action-center-summary.d.ts +193 -0
  9. package/dist/src/server/action-center-summary.js +188 -0
  10. package/dist/src/server/agent-command-resolver.d.ts +6 -0
  11. package/dist/src/server/agent-command-resolver.js +16 -0
  12. package/dist/src/server/agent-manager.js +11 -1
  13. package/dist/src/server/agent-run-starter.js +47 -6
  14. package/dist/src/server/agent-runtime-types.d.ts +4 -0
  15. package/dist/src/server/agent-startup-instructions.d.ts +4 -0
  16. package/dist/src/server/agent-startup-instructions.js +35 -9
  17. package/dist/src/server/agent-stdin-dispatcher.js +17 -9
  18. package/dist/src/server/diagnostics-support-bundle.d.ts +288 -0
  19. package/dist/src/server/diagnostics-support-bundle.js +179 -0
  20. package/dist/src/server/dispatch-ledger-store.d.ts +4 -1
  21. package/dist/src/server/dispatch-ledger-store.js +46 -6
  22. package/dist/src/server/hive-envelope-escape.d.ts +2 -0
  23. package/dist/src/server/hive-envelope-escape.js +2 -0
  24. package/dist/src/server/hive-team-guidance.d.ts +1 -1
  25. package/dist/src/server/hive-team-guidance.js +67 -25
  26. package/dist/src/server/message-log-store.d.ts +1 -1
  27. package/dist/src/server/post-start-input-writer.js +8 -2
  28. package/dist/src/server/preset-launch-support.d.ts +2 -0
  29. package/dist/src/server/preset-launch-support.js +65 -2
  30. package/dist/src/server/protocol-event-stats.d.ts +39 -0
  31. package/dist/src/server/protocol-event-stats.js +84 -0
  32. package/dist/src/server/recovery-summary.js +19 -14
  33. package/dist/src/server/role-template-store.d.ts +1 -1
  34. package/dist/src/server/role-templates.d.ts +1 -0
  35. package/dist/src/server/role-templates.js +43 -29
  36. package/dist/src/server/routes-action-center.d.ts +2 -0
  37. package/dist/src/server/routes-action-center.js +37 -0
  38. package/dist/src/server/routes-diagnostics.d.ts +2 -0
  39. package/dist/src/server/routes-diagnostics.js +17 -0
  40. package/dist/src/server/routes-scenarios.d.ts +25 -0
  41. package/dist/src/server/routes-scenarios.js +89 -0
  42. package/dist/src/server/routes-settings.js +2 -11
  43. package/dist/src/server/routes-team-memory.js +52 -0
  44. package/dist/src/server/routes-team.js +40 -20
  45. package/dist/src/server/routes-workspace-memory-dreams.js +8 -0
  46. package/dist/src/server/routes-workspace-uploads.d.ts +2 -0
  47. package/dist/src/server/routes-workspace-uploads.js +154 -0
  48. package/dist/src/server/routes-workspaces.js +29 -3
  49. package/dist/src/server/routes.js +8 -0
  50. package/dist/src/server/runtime-message-builders.d.ts +0 -1
  51. package/dist/src/server/runtime-message-builders.js +0 -8
  52. package/dist/src/server/runtime-store-contract.d.ts +15 -0
  53. package/dist/src/server/runtime-store-dream.d.ts +14 -1
  54. package/dist/src/server/runtime-store-dream.js +49 -1
  55. package/dist/src/server/runtime-store-helpers.d.ts +7 -0
  56. package/dist/src/server/runtime-store-helpers.js +85 -22
  57. package/dist/src/server/runtime-store-worker-mutations.d.ts +11 -0
  58. package/dist/src/server/runtime-store-worker-mutations.js +46 -0
  59. package/dist/src/server/runtime-store-workflows.js +10 -6
  60. package/dist/src/server/runtime-store.js +34 -42
  61. package/dist/src/server/scenario-presets.d.ts +25 -0
  62. package/dist/src/server/scenario-presets.js +35 -0
  63. package/dist/src/server/sentinel-heartbeat.d.ts +30 -0
  64. package/dist/src/server/sentinel-heartbeat.js +145 -0
  65. package/dist/src/server/spawn-cli-resolver.d.ts +37 -0
  66. package/dist/src/server/spawn-cli-resolver.js +70 -0
  67. package/dist/src/server/spawn-worker-defaults.d.ts +13 -0
  68. package/dist/src/server/spawn-worker-defaults.js +45 -0
  69. package/dist/src/server/sqlite-schema-v32.d.ts +2 -0
  70. package/dist/src/server/sqlite-schema-v32.js +17 -0
  71. package/dist/src/server/sqlite-schema-v33.d.ts +3 -0
  72. package/dist/src/server/sqlite-schema-v33.js +18 -0
  73. package/dist/src/server/sqlite-schema-v34.d.ts +11 -0
  74. package/dist/src/server/sqlite-schema-v34.js +19 -0
  75. package/dist/src/server/sqlite-schema-v35.d.ts +3 -0
  76. package/dist/src/server/sqlite-schema-v35.js +23 -0
  77. package/dist/src/server/sqlite-schema.d.ts +1 -1
  78. package/dist/src/server/sqlite-schema.js +35 -1
  79. package/dist/src/server/system-message.d.ts +5 -2
  80. package/dist/src/server/system-message.js +5 -2
  81. package/dist/src/server/tasks-file-watcher.d.ts +8 -0
  82. package/dist/src/server/tasks-file-watcher.js +31 -2
  83. package/dist/src/server/team-authz.d.ts +9 -1
  84. package/dist/src/server/team-authz.js +24 -0
  85. package/dist/src/server/team-list-serializer.d.ts +2 -2
  86. package/dist/src/server/team-list-serializer.js +2 -1
  87. package/dist/src/server/team-memory-digest.js +4 -4
  88. package/dist/src/server/team-memory-dream-applier.js +24 -3
  89. package/dist/src/server/team-memory-dream-prompt.d.ts +13 -0
  90. package/dist/src/server/team-memory-dream-prompt.js +91 -0
  91. package/dist/src/server/team-memory-dream-run-store.d.ts +2 -0
  92. package/dist/src/server/team-memory-dream-run-store.js +14 -4
  93. package/dist/src/server/team-memory-dream-runner.d.ts +2 -21
  94. package/dist/src/server/team-memory-dream-runner.js +3 -148
  95. package/dist/src/server/team-memory-dream-store.d.ts +1 -1
  96. package/dist/src/server/team-memory-dream-store.js +1 -1
  97. package/dist/src/server/team-operations.d.ts +18 -2
  98. package/dist/src/server/team-operations.js +222 -33
  99. package/dist/src/server/team-recap.d.ts +10 -0
  100. package/dist/src/server/team-recap.js +73 -0
  101. package/dist/src/server/terminal-input-profile.js +88 -9
  102. package/dist/src/server/upload-limits.d.ts +2 -0
  103. package/dist/src/server/upload-limits.js +2 -0
  104. package/dist/src/server/workflow-cli-policy.d.ts +7 -2
  105. package/dist/src/server/workflow-cli-policy.js +15 -3
  106. package/dist/src/server/workflow-run-store.d.ts +1 -0
  107. package/dist/src/server/workflow-run-store.js +11 -1
  108. package/dist/src/server/workflow-runner.d.ts +4 -1
  109. package/dist/src/server/workflow-runner.js +418 -118
  110. package/dist/src/server/workflow-script-loader.d.ts +3 -2
  111. package/dist/src/server/workflow-script-loader.js +161 -0
  112. package/dist/src/server/workspace-store-contract.d.ts +2 -0
  113. package/dist/src/server/workspace-store.d.ts +1 -1
  114. package/dist/src/server/workspace-store.js +40 -30
  115. package/dist/src/server/workspace-upload-store.d.ts +40 -0
  116. package/dist/src/server/workspace-upload-store.js +295 -0
  117. package/dist/src/shared/scenario-presets.d.ts +32 -0
  118. package/dist/src/shared/scenario-presets.js +69 -0
  119. package/dist/src/shared/types.d.ts +12 -1
  120. package/package.json +1 -1
  121. package/web/dist/assets/AddWorkerDialog-DBLhwb91.js +2 -0
  122. package/web/dist/assets/AddWorkspaceFlow-cxvhVAsT.js +1 -0
  123. package/web/dist/assets/FirstRunWizard-DlEPnWWw.js +1 -0
  124. package/web/dist/assets/{MarketplaceDrawer-Dd8WIA8T.js → MarketplaceDrawer-CfSiRi8e.js} +11 -11
  125. package/web/dist/assets/TaskGraphDrawer-C2JufcPs.js +1 -0
  126. package/web/dist/assets/WhatsNewDialog-vP7buLos.js +1 -0
  127. package/web/dist/assets/WorkerModal-CSorwcdP.js +1 -0
  128. package/web/dist/assets/{WorkflowsDrawer-Bjf4olbR.js → WorkflowsDrawer-BXS3w9Uq.js} +1 -1
  129. package/web/dist/assets/WorkspaceMemoryDrawer-D71ivohr.js +1 -0
  130. package/web/dist/assets/{WorkspaceTaskDrawer-BIWwISvA.js → WorkspaceTaskDrawer-CGCTSHKa.js} +1 -1
  131. package/web/dist/assets/index-BcwN8cCw.js +79 -0
  132. package/web/dist/assets/index-StXTPHls.css +1 -0
  133. package/web/dist/assets/{search-Bk2HQvO7.js → search-BZw4T67h.js} +1 -1
  134. package/web/dist/assets/{square-terminal-D93m9hfY.js → square-terminal-B7E57In1.js} +1 -1
  135. package/web/dist/index.html +2 -2
  136. package/web/dist/sw.js +1 -1
  137. package/dist/src/server/env-sync-message.d.ts +0 -9
  138. package/dist/src/server/env-sync-message.js +0 -29
  139. package/web/dist/assets/AddWorkerDialog-CbV75qUX.js +0 -2
  140. package/web/dist/assets/AddWorkspaceFlow-CwV-7wPx.js +0 -1
  141. package/web/dist/assets/FirstRunWizard-a6PWIK3x.js +0 -1
  142. package/web/dist/assets/TaskGraphDrawer-Bk5WFIk_.js +0 -1
  143. package/web/dist/assets/WhatsNewDialog-C2VZaip0.js +0 -1
  144. package/web/dist/assets/WorkerModal-DucW-9YT.js +0 -1
  145. package/web/dist/assets/WorkspaceMemoryDrawer-DglCy_5f.js +0 -1
  146. package/web/dist/assets/index-BAiLYajK.css +0 -1
  147. package/web/dist/assets/index-BV2k9Dts.js +0 -73
package/CHANGELOG.md CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  All notable user-facing changes will be documented in this file.
4
4
 
5
+ ## 2.1.0 - 2026-06-13
6
+
7
+ Sentinel patrol role, one-click team assembly, visible memory consolidation, and remote/dispatch reliability.
8
+
9
+ - Adds a built-in **Sentinel** role: a read-only patrol member that watches the
10
+ team and surfaces stalled or orphaned work via `team status`, without taking
11
+ dispatches or writing memory itself.
12
+ - Adds **one-click scenario team assembly** — start a ready-made team from a
13
+ preset instead of adding members one at a time, with guiding empty-state cards
14
+ when a workspace has no team yet.
15
+ - Reworks team-memory **Dream consolidation** to run through your Orchestrator
16
+ instead of a hidden background CLI pass: maintenance is injected as a visible
17
+ task (`team memory dream show` / `team memory apply`), workers may be asked to
18
+ review proposed changes read-only, and only the Orchestrator commits them.
19
+ Every run keeps a diff report and a one-step revert.
20
+ - Adds a one-click, copyable **team recap** and a diagnostics support bundle to
21
+ the Action Center for faster sharing and troubleshooting.
22
+ - Adds a **dispatch pulse** animation so `team send` visibly flows from the
23
+ Orchestrator to the receiving worker.
24
+ - Guides you to install any missing CLI directly from the add-workspace dialog
25
+ before you start a team.
26
+ - Makes dispatching more reliable: queued tasks replay when a worker starts,
27
+ delivery failures notify the issuer instead of being lost, and `team list`
28
+ now exposes open dispatches.
29
+ - Adds local per-day retention signals (protocol event counters) for workspace
30
+ activity.
31
+ - Fixes remote/mobile reliability: large uploads over the tunnel are chunked
32
+ under the relay message cap, and terminal scrolling is restored for CLIs
33
+ launched through wrapped or legacy commands (for example Codex on Windows).
34
+ - Hardens prompts and the workflow runtime against prompt-injection, and
35
+ polishes protocol error messages, onboarding, and `team spawn` role/CLI
36
+ handling.
37
+
5
38
  ## 2.0.2 - 2026-06-10
6
39
 
7
40
  Windows Codex terminal scrolling fix.
package/README.en.md CHANGED
@@ -56,10 +56,11 @@ them.
56
56
  ## Try the demo first
57
57
 
58
58
  Don't have an agent CLI installed yet? Run `hive`, open the printed URL, and
59
- click **Try Demo** in the first-run wizard. You get a fully client-side
60
- preview fake orchestrator + two workers, prerecorded scrollback, a
61
- prefilled task list without touching the server or any real CLI agent.
62
- Useful for deciding whether to install a real CLI.
59
+ click **Try Demo** in the first-run wizard. The current demo is a walkthrough
60
+ video hosted on Bilibili (network access required to play it) plus a sample
61
+ team in the sidebar, so you can see the orchestrator dispatching and workers
62
+ reporting without installing or signing in to any real CLI agent. Useful for
63
+ deciding whether to install a real CLI.
63
64
 
64
65
  ## Quick Start
65
66
 
@@ -450,6 +451,14 @@ Upstream content is mirrored verbatim, license files are kept under `vendor/mark
450
451
 
451
452
  ## License
452
453
 
453
- Hive source is available under the Business Source License 1.1. Personal use, internal deployment, embedding, and forks are permitted see [LICENSE.BSL](LICENSE.BSL) for the exact boundary.
454
+ Hive is **source-available under the Business Source License 1.1 (BUSL-1.1)**. It is **not** open source as defined by the OSI, and we don't describe it as such.
454
455
 
455
- Forks and redistributions must preserve [NOTICE](NOTICE), [LICENSE.BSL](LICENSE.BSL), and the applicable license files. The Hive name, logo, and visual identity are not licensed by the source license; see [TRADEMARK.md](TRADEMARK.md) for brand usage boundaries.
456
+ ### License FAQ
457
+
458
+ **Why isn't it OSI open source?** BUSL-1.1 places one restriction on production use (next answer), which keeps it outside the Open Source Definition — the BUSL license text itself states it "is not an Open Source license". Rather than blur that line, we say source-available plainly.
459
+
460
+ **Does it affect personal or team use?** No. The Additional Use Grant in [LICENSE.BSL](LICENSE.BSL) explicitly allows production use; the only carve-out is offering Hive to third parties — hosted or embedded, on a paid basis or under any other revenue-generating arrangement (including paid support) — in a way that competes with Hive's multi-CLI-agent orchestration product. Personal use, internal deployment within your organization, embedding into a non-competitive product, and non-commercial forks are all fine.
461
+
462
+ **Will it become open source later?** Yes. Each version converts to the **Apache License 2.0** on the Change Date (2030-05-16) or four years after that version's first public release, whichever comes first.
463
+
464
+ See [LICENSE.BSL](LICENSE.BSL) for the exact terms. Forks and redistributions must preserve [NOTICE](NOTICE), [LICENSE.BSL](LICENSE.BSL), and the applicable license files. The Hive name, logo, and visual identity are not licensed by the source license; see [TRADEMARK.md](TRADEMARK.md) for brand usage boundaries.
package/README.md CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  写代码、做调研、起草文档、做翻译——凡是能拆给一群人协作的脑力活,都可以让一群 Agent 合伙干。
14
14
 
15
+ 全程可以用国产 CLI 组队——Qwen Code 是内置预设,GLM 等国内模型也能通过其支持的 coding CLI 或自定义命令接入——不强制依赖境外 API。Windows 原生支持(非 WSL),详见[平台支持](#平台支持)。
16
+
15
17
  [![npm](https://img.shields.io/npm/v/@tt-a1i/hive.svg)](https://www.npmjs.com/package/@tt-a1i/hive)
16
18
  [![ci](https://img.shields.io/github/actions/workflow/status/tt-a1i/hive/release.yml?branch=main&label=ci)](https://github.com/tt-a1i/hive/actions/workflows/release.yml)
17
19
  [![Website](https://img.shields.io/badge/website-hivehq.dev-5a8a8a.svg)](https://hivehq.dev)
@@ -42,7 +44,7 @@ Hive 加上这一层调度,**不替换**任何 CLI。Agent 还是真实跑在
42
44
 
43
45
  ## 先看看 demo
44
46
 
45
- 还没装任何 agent CLI?运行 `hive`、打开它打印出的本地地址、在 first-run 向导里点 **Try Demo**。你会看到一个完全跑在客户端的预览——假 orchestrator + 两个 worker、预录的终端 scrollback、一份预填的任务清单——既不会连服务器,也不需要任何真实 CLI agent。适合决定要不要继续装真 CLI。
47
+ 还没装任何 agent CLI?运行 `hive`、打开它打印出的本地地址、在 first-run 向导里点 **Try Demo**。当前的 demo 是一段 Bilibili 演示视频(需要联网才能播放),外加侧边栏里的一个示例团队,让你不安装、不登录任何真实 CLI agent 就能看到 Orchestrator 派单、Worker 干活的样子。适合决定要不要继续装真 CLI。
46
48
 
47
49
  ## 快速开始
48
50
 
@@ -58,6 +60,12 @@ npm install -g @tt-a1i/hive
58
60
  hive
59
61
  ```
60
62
 
63
+ 国内网络从 npmmirror 镜像安装更快:
64
+
65
+ ```bash
66
+ npm install -g @tt-a1i/hive --registry=https://registry.npmmirror.com
67
+ ```
68
+
61
69
  安装时如果看到 `npm warn allow-scripts` 或 `prebuild-install@7.1.3 deprecated`,先看最后是否显示 `added ... packages`。这些 warning 多数来自 npm 对安装脚本的安全审查,以及 `node-pty` / `better-sqlite3` / `esbuild` 这类原生依赖的二进制安装链路;不代表 Hive 启动失败。下面的故障排查里有逐项解释。
62
70
 
63
71
  打开终端打印出来的本机地址,通常是 `http://127.0.0.1:3000/`。如果你想指定端口,可以用 `hive --port 4010`。
@@ -168,6 +176,12 @@ Hive **不**提供 sandbox 隔离、多用户认证,也不自带任何 agent
168
176
 
169
177
  ## 平台支持
170
178
 
179
+ | 平台 | 状态 | 说明 |
180
+ | --- | --- | --- |
181
+ | macOS | Tier 1 | 主要开发与发版验证平台。 |
182
+ | Linux | Tier 1 | CI 验证。原生目录选择器依赖 `zenity`,没有也可以手动粘贴路径。 |
183
+ | Windows | Tier 2 | **原生支持,无需 WSL**。CI 跑 Windows 测试子集(`pnpm test:windows`)和打包安装冒烟,包内含 `team.cmd`。按 best-effort 维护:每次发版前的完整 Windows 验证仍是手动步骤。 |
184
+
171
185
  所有平台都需要 Node.js 22+。Hive 依赖 `node-pty` 和 `better-sqlite3` 这类原生包,没有预编译二进制时需要你本机有原生构建工具链。
172
186
 
173
187
  ## 安全模型
@@ -304,7 +318,7 @@ Hive 目前处于 alpha 阶段,核心流程已可用。当前重点是继续
304
318
 
305
319
  但 **这些都是单 agent 内部的记忆**。Hive 是多 agent 协作工作台,正在把它们打通:让整支团队 **共享一座长时记忆库**——Worker A 今天踩的坑,明天 Orchestrator 派给 Worker B 时能自动调来当上下文。
306
320
 
307
- 第一阶段先走本地优先:Hive 用 SQLite 保存协作历史和显式团队记忆,支持 `team recall` / `team memory`、派单和恢复时的自动注入、`<workspace>/.hive/memory.md` 单向导出,以及离线 Dream 整理。Dream 会按 workspace 空闲和增量阈值批处理协议消息,自动应用去重/改写/归档/新增,并保留 diff 报告和整次 run 的回滚入口。
321
+ 第一阶段先走本地优先:Hive 用 SQLite 保存协作历史和显式团队记忆,支持 `team recall` / `team memory`、派单和恢复时的自动注入、`<workspace>/.hive/memory.md` 单向导出,以及 Dream 整理。Dream 会按 workspace 空闲和增量阈值创建维护 run,把有界协议窗口注入 Orchestrator;Orchestrator 可自己整理,或派 worker 只读评审并回报建议,最后由 Orchestrator 用 `team memory apply --run <id> --stdin` 提交去重/改写/归档/新增。每次 run 保留 diff 报告和回滚入口。
308
322
 
309
323
  下一阶段再接 **[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。
310
324
 
@@ -328,6 +342,14 @@ Hive 的"模板市场"内置了两份社区角色 prompt 库的快照,两份
328
342
 
329
343
  ## License
330
344
 
331
- Hive 源码在 Business Source License 1.1 下提供。个人使用、内部部署、嵌入、fork 都可以;详细边界见 [LICENSE.BSL](LICENSE.BSL)。
345
+ Hive **source-available(源码可得)** 项目,以 **Business Source License 1.1(BUSL-1.1)** 提供源码。它**不是** OSI 定义的开源(open source)许可,我们也不自称开源项目。
346
+
347
+ ### License FAQ
348
+
349
+ **为什么不是 OSI 开源?** BUSL-1.1 对生产使用附带一条限制(见下条),不满足开放源代码定义的要求——BUSL 许可文本自己也写明它 "is not an Open Source license"。与其模糊表述,我们选择如实写 source-available。
350
+
351
+ **个人 / 团队日常使用受影响吗?** 不受影响。[LICENSE.BSL](LICENSE.BSL) 的 Additional Use Grant 明确允许生产使用,唯一例外是:以收费或其他营收安排(含付费支持等)向第三方提供托管 / 嵌入的 Hive、且与 Hive 的多 CLI agent 编排产品形成竞争。个人使用、组织内部部署、嵌入非竞争产品、非商业 fork 都不属于"竞争性产品"。
352
+
353
+ **以后会变开源吗?** 会。每个版本在 Change Date(2030-05-16)或该版本首次公开发布满四年(以先到者为准)自动转为 **Apache License 2.0**。
332
354
 
333
- Fork 或再分发版本必须保留 [NOTICE](NOTICE)、[LICENSE.BSL](LICENSE.BSL) 和相关许可证文件。Hive 名称、logo 和视觉识别不随源码许可证授权;品牌使用边界见 [TRADEMARK.md](TRADEMARK.md)。
355
+ 详细条款以 [LICENSE.BSL](LICENSE.BSL) 为准。Fork 或再分发版本必须保留 [NOTICE](NOTICE)、[LICENSE.BSL](LICENSE.BSL) 和相关许可证文件。Hive 名称、logo 和视觉识别不随源码许可证授权;品牌使用边界见 [TRADEMARK.md](TRADEMARK.md)。
@@ -13,6 +13,10 @@ type RunHiveCommandOptions = {
13
13
  versionService?: VersionService;
14
14
  /** Seam: override the tunnel factory in tests. Defaults to the real createRemoteTunnel. */
15
15
  createRemoteTunnel?: (deps: RemoteTunnelDeps) => RemoteTunnel;
16
+ /** Auto-open the UI in the default browser once listening. Only the real
17
+ * CLI entry sets this (with `--no-open` as the opt-out); programmatic
18
+ * callers and tests default to no browser. */
19
+ openBrowser?: boolean;
16
20
  };
17
21
  /**
18
22
  * Signals that should drive a graceful shutdown. The interesting ones:
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
2
3
  import { once } from 'node:events';
3
4
  import { existsSync } from 'node:fs';
4
5
  import { homedir } from 'node:os';
@@ -38,11 +39,12 @@ import { runHiveUpdateCommand } from './hive-update.js';
38
39
  export const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGBREAK'];
39
40
  export const HIVE_USAGE = [
40
41
  'Usage:',
41
- ' hive [--port <port>]',
42
+ ' hive [--port <port>] [--no-open]',
42
43
  ' hive update',
43
44
  '',
44
45
  'Options:',
45
46
  ' --port <port> Bind the local runtime to a specific port (default: 3000).',
47
+ ' --no-open Do not auto-open the browser after start.',
46
48
  ' -h, --help Print this help.',
47
49
  ' -v, --version Print the installed Hive version.',
48
50
  '',
@@ -66,6 +68,8 @@ const parsePort = (argv) => {
66
68
  for (let index = 0; index < argv.length; index += 1) {
67
69
  const arg = argv[index];
68
70
  if (arg !== '--port') {
71
+ if (arg === '--no-open')
72
+ continue; // consumed by the CLI entry's openBrowser gate
69
73
  if (arg?.startsWith('-'))
70
74
  throw new Error(`Unknown option: ${arg}`);
71
75
  if (arg)
@@ -181,6 +185,20 @@ export const formatPortAccessDeniedMessage = (port, platform = process.platform)
181
185
  ' - Or choose another port outside the listed excluded ranges.',
182
186
  ].join('\n');
183
187
  };
188
+ /* Best-effort default-browser launch. Failure must never affect the runtime:
189
+ the URL is already printed, so a missing opener (e.g. no xdg-open on a
190
+ headless box) silently degrades to the manual copy-paste flow. */
191
+ const openUrlInBrowser = (url) => {
192
+ const child = process.platform === 'darwin'
193
+ ? spawn('open', [url], { detached: true, stdio: 'ignore' })
194
+ : process.platform === 'win32'
195
+ ? // `start` is a cmd built-in; the empty '' is its window-title slot so
196
+ // the URL is not mistaken for a title.
197
+ spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore' })
198
+ : spawn('xdg-open', [url], { detached: true, stdio: 'ignore' });
199
+ child.on('error', () => { });
200
+ child.unref();
201
+ };
184
202
  const formatListenError = (error, requestedPort) => {
185
203
  if (isListenError(error) && error.code === 'EADDRINUSE') {
186
204
  return new Error(formatPortInUseMessage(error.port ?? requestedPort));
@@ -294,7 +312,11 @@ export const runHiveCommand = async (argv, options = {}) => {
294
312
  for (const signal of SHUTDOWN_SIGNALS) {
295
313
  process.once(signal, gracefulShutdown);
296
314
  }
297
- console.log(`Hive running at http://127.0.0.1:${address.port}`);
315
+ const url = `http://127.0.0.1:${address.port}`;
316
+ console.log(`Hive running at ${url}`);
317
+ if (options.openBrowser === true && !argv.includes('--no-open')) {
318
+ openUrlInBrowser(url);
319
+ }
298
320
  void maybePrintUpdateHint(versionService).catch(() => { });
299
321
  return {
300
322
  port: address.port,
@@ -328,7 +350,7 @@ if (isMainModule) {
328
350
  process.exit(0);
329
351
  }
330
352
  else {
331
- runHiveCommand(argv).catch((error) => {
353
+ runHiveCommand(argv, { openBrowser: true }).catch((error) => {
332
354
  console.error(error instanceof Error ? error.message : error);
333
355
  process.exit(1);
334
356
  });
@@ -29,10 +29,17 @@ export declare const parseMemorySearchArgs: (args: string[]) => {
29
29
  limit?: number;
30
30
  query: string;
31
31
  };
32
+ export declare const parseMemoryDreamShowArgs: (args: string[]) => {
33
+ runId: string;
34
+ };
35
+ export declare const parseMemoryApplyArgs: (args: string[]) => {
36
+ runId: string;
37
+ };
38
+ export declare const parseMemoryApplyPayload: (value: string) => unknown;
32
39
  export declare const parseMemoryForgetArgs: (args: string[]) => {
33
40
  memoryId: string;
34
41
  };
35
42
  export declare const decodeStdinBuffer: (buffer: Buffer) => string;
36
- export declare const readStdinToString: (command?: string) => Promise<string>;
43
+ export declare const readStdinToString: (command?: string, usage?: string) => Promise<string>;
37
44
  export declare const runTeamCommand: (argv: string[]) => Promise<void>;
38
45
  export {};
@@ -17,15 +17,12 @@ const TEAM_USAGE = [
17
17
  ' team memory add "<body>" [--kind fact|preference|decision|pitfall|procedure_ref] [--tag <tag>]',
18
18
  ' team memory show <memory-id>',
19
19
  ' team memory search "<query>" [--limit <n>]',
20
+ ' team memory dream show <dream-run-id>',
21
+ ' team memory apply --run <dream-run-id> --stdin',
20
22
  ' team memory forget <memory-id>',
21
23
  ' team send <worker-name> "<task>"',
22
24
  ` team spawn <role> [--name <name>] [--cli <${BUILTIN_COMMAND_PRESET_CLI_LIST}>] [--ephemeral]`,
23
25
  ' team dismiss <worker-name>',
24
- " team workflow run --stdin [--args '<JSON>'] (script from stdin — for multi-line scripts)",
25
- ' team workflow run --inline "<source>" [--args \'<JSON>\']',
26
- ' team workflow stop <run-id>',
27
- ' team workflow show <run-id> (full per-agent transcript for one run)',
28
- ' team workflow schedule --cron "<cron>" --name <n> --stdin (register a recurring run)',
29
26
  ' team cancel --dispatch <dispatch-id> "<reason>"',
30
27
  ' team report "<result>" [--dispatch <dispatch-id>] [--artifact <path>]',
31
28
  ' team report --stdin [--dispatch <dispatch-id>] [--artifact <path>]',
@@ -41,7 +38,7 @@ const TEAM_USAGE = [
41
38
  ' PowerShell: Get-Content -Raw -Encoding utf8 body.txt | team report --stdin --dispatch <id>',
42
39
  ' Portable: team report --stdin --dispatch <id> < body.txt',
43
40
  '',
44
- 'For role rules, workflow, and recovery instructions, see .hive/PROTOCOL.md',
41
+ 'For role rules, recovery instructions, and enabled experimental commands, see .hive/PROTOCOL.md',
45
42
  ].join('\n');
46
43
  const getHiveEnv = () => {
47
44
  const values = Object.fromEntries(REQUIRED_ENV_KEYS.map((key) => [key, process.env[key]]));
@@ -113,6 +110,8 @@ const RECALL_USAGE = 'Usage: team recall "<query>" [--limit <n>] [--window <n>]'
113
110
  const MEMORY_ADD_USAGE = 'Usage: team memory add "<body>" [--kind fact|preference|decision|pitfall|procedure_ref] [--tag <tag>]';
114
111
  const MEMORY_SHOW_USAGE = 'Usage: team memory show <memory-id>';
115
112
  const MEMORY_SEARCH_USAGE = 'Usage: team memory search "<query>" [--limit <n>]';
113
+ const MEMORY_DREAM_SHOW_USAGE = 'Usage: team memory dream show <dream-run-id>';
114
+ const MEMORY_APPLY_USAGE = 'Usage: team memory apply --run <dream-run-id> --stdin';
116
115
  const MEMORY_FORGET_USAGE = 'Usage: team memory forget <memory-id>';
117
116
  const usageFor = (command) => (command === 'status' ? STATUS_USAGE : REPORT_USAGE);
118
117
  const withUsage = (message, command) => `${message}\n\n${usageFor(command)}`;
@@ -356,6 +355,66 @@ export const parseMemorySearchArgs = (args) => {
356
355
  ...(limit !== undefined ? { limit } : {}),
357
356
  };
358
357
  };
358
+ export const parseMemoryDreamShowArgs = (args) => {
359
+ if (args.length !== 1 || !args[0] || args[0].startsWith('--')) {
360
+ throw new Error(`Missing <dream-run-id>\n\n${MEMORY_DREAM_SHOW_USAGE}`);
361
+ }
362
+ return { runId: args[0] };
363
+ };
364
+ export const parseMemoryApplyArgs = (args) => {
365
+ const positionals = [];
366
+ let runId;
367
+ let useStdin = false;
368
+ for (let index = 0; index < args.length; index += 1) {
369
+ const arg = args[index];
370
+ if (arg === undefined)
371
+ continue;
372
+ if (arg === '--run') {
373
+ const next = args[index + 1];
374
+ if (next === undefined || next.startsWith('--')) {
375
+ throw new Error(`--run requires a value\n\n${MEMORY_APPLY_USAGE}`);
376
+ }
377
+ runId = next;
378
+ index += 1;
379
+ continue;
380
+ }
381
+ if (arg === '--stdin') {
382
+ useStdin = true;
383
+ continue;
384
+ }
385
+ if (arg.startsWith('--')) {
386
+ throw new Error(`Unknown argument: ${arg}\n\n${MEMORY_APPLY_USAGE}`);
387
+ }
388
+ positionals.push(arg);
389
+ }
390
+ if (positionals.length > 0) {
391
+ throw new Error(`Unexpected positional argument\n\n${MEMORY_APPLY_USAGE}`);
392
+ }
393
+ if (!runId) {
394
+ throw new Error(`Missing --run <dream-run-id>\n\n${MEMORY_APPLY_USAGE}`);
395
+ }
396
+ if (!useStdin) {
397
+ throw new Error(`Missing --stdin\n\n${MEMORY_APPLY_USAGE}`);
398
+ }
399
+ return { runId };
400
+ };
401
+ export const parseMemoryApplyPayload = (value) => {
402
+ let parsed;
403
+ try {
404
+ parsed = JSON.parse(value);
405
+ }
406
+ catch (error) {
407
+ throw new Error(`stdin must be valid JSON; got: ${error instanceof Error ? error.message : String(error)}\n\n${MEMORY_APPLY_USAGE}`);
408
+ }
409
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
410
+ throw new Error(`stdin JSON must be an object with an ops array\n\n${MEMORY_APPLY_USAGE}`);
411
+ }
412
+ const ops = parsed.ops;
413
+ if (!Array.isArray(ops)) {
414
+ throw new Error(`stdin JSON must include an ops array\n\n${MEMORY_APPLY_USAGE}`);
415
+ }
416
+ return ops;
417
+ };
359
418
  export const parseMemoryForgetArgs = (args) => {
360
419
  if (args.length === 0 || !args[0] || args[0].startsWith('--')) {
361
420
  throw new Error(`Missing <memory-id>\n\n${MEMORY_FORGET_USAGE}`);
@@ -379,9 +438,9 @@ export const decodeStdinBuffer = (buffer) => {
379
438
  }
380
439
  return buffer.toString('utf8');
381
440
  };
382
- export const readStdinToString = async (command = 'report') => {
441
+ export const readStdinToString = async (command = 'report', usage = usageFor(command)) => {
383
442
  if (process.stdin.isTTY) {
384
- throw new Error(withUsage('--stdin requires piped input, but stdin is a TTY. Did you forget to pipe content in?', command));
443
+ throw new Error(`--stdin requires piped input, but stdin is a TTY. Did you forget to pipe content in?\n\n${usage}`);
385
444
  }
386
445
  const chunks = [];
387
446
  for await (const chunk of process.stdin) {
@@ -389,7 +448,7 @@ export const readStdinToString = async (command = 'report') => {
389
448
  }
390
449
  const content = decodeStdinBuffer(Buffer.concat(chunks));
391
450
  if (!content.trim()) {
392
- throw new Error(withUsage('--stdin received empty input', command));
451
+ throw new Error(`--stdin received empty input\n\n${usage}`);
393
452
  }
394
453
  return content;
395
454
  };
@@ -486,6 +545,36 @@ export const runTeamCommand = async (argv) => {
486
545
  console.log(JSON.stringify(await response.json()));
487
546
  return;
488
547
  }
548
+ if (subcommand === 'dream') {
549
+ const [dreamSubcommand, ...dreamArgs] = memoryArgs;
550
+ if (dreamSubcommand !== 'show') {
551
+ throw new Error(MEMORY_DREAM_SHOW_USAGE);
552
+ }
553
+ const dream = parseMemoryDreamShowArgs(dreamArgs);
554
+ const env = getHiveEnv();
555
+ const response = await postJson(getBaseUrl(env), '/api/team/memory/dream/show', {
556
+ project_id: env.HIVE_PROJECT_ID,
557
+ from_agent_id: env.HIVE_AGENT_ID,
558
+ token: env.HIVE_AGENT_TOKEN,
559
+ run_id: dream.runId,
560
+ });
561
+ console.log(JSON.stringify(await response.json()));
562
+ return;
563
+ }
564
+ if (subcommand === 'apply') {
565
+ const apply = parseMemoryApplyArgs(memoryArgs);
566
+ const ops = parseMemoryApplyPayload(await readStdinToString('memory apply', MEMORY_APPLY_USAGE));
567
+ const env = getHiveEnv();
568
+ const response = await postJson(getBaseUrl(env), '/api/team/memory/apply', {
569
+ project_id: env.HIVE_PROJECT_ID,
570
+ from_agent_id: env.HIVE_AGENT_ID,
571
+ token: env.HIVE_AGENT_TOKEN,
572
+ run_id: apply.runId,
573
+ ops,
574
+ });
575
+ console.log(JSON.stringify(await response.json()));
576
+ return;
577
+ }
489
578
  if (subcommand === 'forget') {
490
579
  const memory = parseMemoryForgetArgs(memoryArgs);
491
580
  const env = getHiveEnv();
@@ -503,6 +592,8 @@ export const runTeamCommand = async (argv) => {
503
592
  ` ${MEMORY_ADD_USAGE}`,
504
593
  ` ${MEMORY_SHOW_USAGE}`,
505
594
  ` ${MEMORY_SEARCH_USAGE}`,
595
+ ` ${MEMORY_DREAM_SHOW_USAGE}`,
596
+ ` ${MEMORY_APPLY_USAGE}`,
506
597
  ` ${MEMORY_FORGET_USAGE}`,
507
598
  ].join('\n'));
508
599
  }
@@ -531,6 +622,10 @@ export const runTeamCommand = async (argv) => {
531
622
  if (payload.restarted_worker === true) {
532
623
  console.error(`Hive woke up worker "${workerName}" before dispatching.`);
533
624
  }
625
+ if (payload.queued === true) {
626
+ console.error(`Worker "${workerName}" is stopped — the dispatch is queued and will be delivered automatically when the worker is next started. ` +
627
+ 'Tell the user to start it in the Hive UI if this should run now, or `team cancel --dispatch <id>` to reassign.');
628
+ }
534
629
  console.log(JSON.stringify(payload));
535
630
  return;
536
631
  }
@@ -698,19 +793,24 @@ export const runTeamCommand = async (argv) => {
698
793
  ' team workflow run --inline "<source>" [--args ...] (one-arg form)\n' +
699
794
  ' team workflow stop <run-id> (cancel a running workflow)\n' +
700
795
  ' team workflow show <run-id> (full per-agent transcript)\n' +
701
- ' team workflow schedule --cron "<cron>" --name <n> --stdin (register a recurring run)');
796
+ ' team workflow schedule --cron "<cron>" --name <n> --stdin (register a recurring run)\n' +
797
+ ' Note: workflow commands are experimental and may be disabled in this workspace; re-read .hive/PROTOCOL.md for the enabled command set.');
702
798
  }
703
799
  if (command === 'cancel') {
704
800
  const cancel = parseCancelArgs(args);
705
801
  const env = getHiveEnv();
706
802
  const baseUrl = getBaseUrl(env);
707
- await postJson(baseUrl, '/api/team/cancel', {
803
+ const response = await postJson(baseUrl, '/api/team/cancel', {
708
804
  dispatch_id: cancel.dispatchId,
709
805
  project_id: env.HIVE_PROJECT_ID,
710
806
  from_agent_id: env.HIVE_AGENT_ID,
711
807
  token: env.HIVE_AGENT_TOKEN,
712
808
  reason: cancel.reason,
713
809
  });
810
+ const payload = (await response.json());
811
+ if (payload.forwarded === false && payload.forward_error) {
812
+ console.error(`Hive cancelled the dispatch in the ledger, but could not deliver the cancel notice to the worker: ${payload.forward_error}. The worker may still be acting on the task.`);
813
+ }
714
814
  return;
715
815
  }
716
816
  if (command === 'status') {
@@ -0,0 +1,193 @@
1
+ import type { RuntimeStore } from './runtime-store.js';
2
+ export declare const buildActionCenterSummary: (input: {
3
+ includeTextEvidence?: boolean;
4
+ now?: number;
5
+ store: RuntimeStore;
6
+ workspaceId: string;
7
+ }) => {
8
+ attention: Record<string, unknown>[];
9
+ generated_at: number;
10
+ recent_activity: ({
11
+ kind: string;
12
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
13
+ submitted_at: number | null;
14
+ timestamp: number;
15
+ to_agent_id: string;
16
+ to_worker_name: string | null;
17
+ workflow_run_id: string | null;
18
+ label: string | null;
19
+ phase: string | null;
20
+ report_preview: string | null;
21
+ task_preview: string | null;
22
+ has_label?: never;
23
+ has_phase?: never;
24
+ created_at: number;
25
+ id: string;
26
+ } | {
27
+ kind: string;
28
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
29
+ submitted_at: number | null;
30
+ timestamp: number;
31
+ to_agent_id: string;
32
+ to_worker_name: string | null;
33
+ workflow_run_id: string | null;
34
+ has_label: boolean;
35
+ has_phase: boolean;
36
+ label?: never;
37
+ phase?: never;
38
+ report_preview?: never;
39
+ task_preview?: never;
40
+ created_at: number;
41
+ id: string;
42
+ })[];
43
+ summary: {
44
+ idle_workers: number;
45
+ open_dispatches: number;
46
+ recent_reports: number;
47
+ stopped_with_queue: number;
48
+ stopped_workers: number;
49
+ total_workers: number;
50
+ waiting_reports: number;
51
+ working_workers: number;
52
+ };
53
+ workers: ({
54
+ terminal_hint: string | null;
55
+ current_dispatch: {
56
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
57
+ submitted_at: number | null;
58
+ timestamp: number;
59
+ to_agent_id: string;
60
+ to_worker_name: string | null;
61
+ workflow_run_id: string | null;
62
+ label: string | null;
63
+ phase: string | null;
64
+ report_preview: string | null;
65
+ task_preview: string | null;
66
+ has_label?: never;
67
+ has_phase?: never;
68
+ created_at: number;
69
+ id: string;
70
+ } | {
71
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
72
+ submitted_at: number | null;
73
+ timestamp: number;
74
+ to_agent_id: string;
75
+ to_worker_name: string | null;
76
+ workflow_run_id: string | null;
77
+ has_label: boolean;
78
+ has_phase: boolean;
79
+ label?: never;
80
+ phase?: never;
81
+ report_preview?: never;
82
+ task_preview?: never;
83
+ created_at: number;
84
+ id: string;
85
+ } | null;
86
+ id: string;
87
+ latest_report: {
88
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
89
+ submitted_at: number | null;
90
+ timestamp: number;
91
+ to_agent_id: string;
92
+ to_worker_name: string | null;
93
+ workflow_run_id: string | null;
94
+ label: string | null;
95
+ phase: string | null;
96
+ report_preview: string | null;
97
+ task_preview: string | null;
98
+ has_label?: never;
99
+ has_phase?: never;
100
+ created_at: number;
101
+ id: string;
102
+ } | {
103
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
104
+ submitted_at: number | null;
105
+ timestamp: number;
106
+ to_agent_id: string;
107
+ to_worker_name: string | null;
108
+ workflow_run_id: string | null;
109
+ has_label: boolean;
110
+ has_phase: boolean;
111
+ label?: never;
112
+ phase?: never;
113
+ report_preview?: never;
114
+ task_preview?: never;
115
+ created_at: number;
116
+ id: string;
117
+ } | null;
118
+ name: string;
119
+ pending_task_count: number;
120
+ role: import("../shared/types.js").WorkerRole;
121
+ status: "idle" | "working" | "stopped";
122
+ } | {
123
+ terminal_hint?: never;
124
+ current_dispatch: {
125
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
126
+ submitted_at: number | null;
127
+ timestamp: number;
128
+ to_agent_id: string;
129
+ to_worker_name: string | null;
130
+ workflow_run_id: string | null;
131
+ label: string | null;
132
+ phase: string | null;
133
+ report_preview: string | null;
134
+ task_preview: string | null;
135
+ has_label?: never;
136
+ has_phase?: never;
137
+ created_at: number;
138
+ id: string;
139
+ } | {
140
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
141
+ submitted_at: number | null;
142
+ timestamp: number;
143
+ to_agent_id: string;
144
+ to_worker_name: string | null;
145
+ workflow_run_id: string | null;
146
+ has_label: boolean;
147
+ has_phase: boolean;
148
+ label?: never;
149
+ phase?: never;
150
+ report_preview?: never;
151
+ task_preview?: never;
152
+ created_at: number;
153
+ id: string;
154
+ } | null;
155
+ id: string;
156
+ latest_report: {
157
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
158
+ submitted_at: number | null;
159
+ timestamp: number;
160
+ to_agent_id: string;
161
+ to_worker_name: string | null;
162
+ workflow_run_id: string | null;
163
+ label: string | null;
164
+ phase: string | null;
165
+ report_preview: string | null;
166
+ task_preview: string | null;
167
+ has_label?: never;
168
+ has_phase?: never;
169
+ created_at: number;
170
+ id: string;
171
+ } | {
172
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
173
+ submitted_at: number | null;
174
+ timestamp: number;
175
+ to_agent_id: string;
176
+ to_worker_name: string | null;
177
+ workflow_run_id: string | null;
178
+ has_label: boolean;
179
+ has_phase: boolean;
180
+ label?: never;
181
+ phase?: never;
182
+ report_preview?: never;
183
+ task_preview?: never;
184
+ created_at: number;
185
+ id: string;
186
+ } | null;
187
+ name: string;
188
+ pending_task_count: number;
189
+ role: import("../shared/types.js").WorkerRole;
190
+ status: "idle" | "working" | "stopped";
191
+ })[];
192
+ workspace_id: string;
193
+ };