@tt-a1i/hive 1.3.0 → 1.3.4
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 +42 -14
- package/README.en.md +30 -8
- package/README.md +21 -6
- package/assets/hive-team-view.png +0 -0
- package/dist/src/cli/team.d.ts +6 -0
- package/dist/src/cli/team.js +48 -0
- package/dist/src/server/agent-launch-cache.js +25 -6
- package/dist/src/server/agent-manager.d.ts +2 -2
- package/dist/src/server/agent-runtime-contract.d.ts +3 -0
- package/dist/src/server/agent-runtime.js +3 -0
- package/dist/src/server/agent-startup-instructions.js +1 -1
- package/dist/src/server/agent-stdin-dispatcher.d.ts +4 -0
- package/dist/src/server/agent-stdin-dispatcher.js +12 -0
- package/dist/src/server/app.js +1 -1
- package/dist/src/server/dispatch-ledger-store.d.ts +22 -1
- package/dist/src/server/dispatch-ledger-store.js +34 -3
- package/dist/src/server/hive-team-guidance.js +3 -1
- package/dist/src/server/route-types.d.ts +7 -0
- package/dist/src/server/routes-dispatches.js +4 -2
- package/dist/src/server/routes-runtime.js +1 -0
- package/dist/src/server/routes-team.js +22 -0
- package/dist/src/server/runtime-store-helpers.d.ts +2 -1
- package/dist/src/server/runtime-store-helpers.js +14 -4
- package/dist/src/server/runtime-store.d.ts +5 -8
- package/dist/src/server/runtime-store.js +1 -0
- package/dist/src/server/tasks-websocket-server.d.ts +2 -1
- package/dist/src/server/tasks-websocket-server.js +18 -2
- package/dist/src/server/team-authz.d.ts +1 -1
- package/dist/src/server/team-authz.js +1 -1
- package/dist/src/server/team-operations.d.ts +16 -1
- package/dist/src/server/team-operations.js +28 -1
- package/dist/src/server/terminal-input-profile.d.ts +10 -0
- package/dist/src/server/terminal-input-profile.js +15 -0
- package/dist/src/server/terminal-stream-hub.js +10 -2
- package/dist/src/server/terminal-ws-server.d.ts +2 -1
- package/dist/src/server/terminal-ws-server.js +2 -2
- package/dist/src/server/workspace-shell-runtime.d.ts +2 -1
- package/dist/src/server/workspace-shell-runtime.js +3 -2
- package/dist/src/server/workspace-store-contract.d.ts +1 -0
- package/dist/src/server/workspace-store-mutations.d.ts +1 -0
- package/dist/src/server/workspace-store-mutations.js +1 -0
- package/dist/src/server/workspace-store.js +2 -1
- package/package.json +2 -2
- package/web/dist/assets/AddWorkerDialog-D6-K1wJm.js +1 -0
- package/web/dist/assets/AddWorkspaceDialog-Du0lndJ0.js +1 -0
- package/web/dist/assets/FirstRunWizard-B8k7S5De.js +1 -0
- package/web/dist/assets/WorkerModal-B3XhIvAX.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-CjEoLJvS.js +1 -0
- package/web/dist/assets/chevron-right-BvbSCniy.js +1 -0
- package/web/dist/assets/index-DB5fHAMI.js +81 -0
- package/web/dist/assets/index-Sbdu6Se0.css +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/sw.js +1 -1
- package/web/dist/assets/index-CSEt-Qiy.js +0 -66
- package/web/dist/assets/index-RsXXnrVz.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
All notable user-facing changes will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.3.4 - 2026-05-21
|
|
6
|
+
|
|
7
|
+
Terminal performance and Tasks panel polish.
|
|
8
|
+
|
|
9
|
+
- Improves terminal responsiveness by keeping mounted terminal hosts stable,
|
|
10
|
+
lazy-loading heavier xterm addons, and reducing terminal-run polling churn.
|
|
11
|
+
- Fixes OpenCode TUI wheel and mouse handling by preserving binary input for
|
|
12
|
+
normal terminals while translating OpenCode legacy mouse reports into the
|
|
13
|
+
SGR format it handles correctly.
|
|
14
|
+
- Sends a current `.hive/tasks.md` snapshot when a Tasks websocket connects,
|
|
15
|
+
and guards that initial read so a missing or unreadable file does not break
|
|
16
|
+
the websocket session.
|
|
17
|
+
- Renames the visible Todo entry to **Tasks** and widens the Tasks side panel
|
|
18
|
+
to match the default Team Members pane width.
|
|
19
|
+
- Enlarges the Team Members header and count badge for better readability.
|
|
20
|
+
|
|
21
|
+
## 1.3.3 - 2026-05-21
|
|
22
|
+
|
|
23
|
+
OpenCode terminal scrolling and small UI polish.
|
|
24
|
+
|
|
25
|
+
- Restores the Task Graph topbar entry so the graph view is available again
|
|
26
|
+
from the main shell.
|
|
27
|
+
- Updates generated worker names to use localized, role-scoped historical
|
|
28
|
+
figure name pools, making Chinese and English workspaces feel less generic.
|
|
29
|
+
- Fixes OpenCode TUI mouse-wheel scrolling inside Hive terminal panels. Hive now
|
|
30
|
+
tags each terminal run with an input profile and maps OpenCode wheel events to
|
|
31
|
+
the keys OpenCode's message viewport actually handles (`Ctrl+D` / `Ctrl+U`),
|
|
32
|
+
while leaving other alternate-screen TUIs on the existing arrow-key fallback.
|
|
33
|
+
- Preserves that OpenCode profile when the user selects the OpenCode preset but
|
|
34
|
+
starts it through a custom startup command such as `opencode --continue`.
|
|
35
|
+
- Keeps workspace shell terminals on the default input profile.
|
|
36
|
+
- Enlarges the Team Members header count for better readability.
|
|
37
|
+
- Documents that npm's `prebuild-install@7.1.3` deprecation warning comes from
|
|
38
|
+
the upstream native-binary installer chain and is safe to ignore.
|
|
39
|
+
|
|
5
40
|
## 1.3.0 - 2026-05-20
|
|
6
41
|
|
|
7
42
|
Installable Hive: turns the web shell into a real PWA so Chrome / Edge can
|
|
@@ -135,37 +170,30 @@ Brand polish.
|
|
|
135
170
|
|
|
136
171
|
## 1.1.2 - 2026-05-17
|
|
137
172
|
|
|
138
|
-
|
|
173
|
+
Release workflow fix.
|
|
139
174
|
|
|
140
175
|
- Runs npm publish on Ubuntu instead of macOS. Publishing does not require
|
|
141
|
-
macOS, and the Ubuntu runner
|
|
176
|
+
macOS, and the Ubuntu runner is a better fit for the publish step.
|
|
142
177
|
|
|
143
178
|
## 1.1.1 - 2026-05-17
|
|
144
179
|
|
|
145
|
-
|
|
180
|
+
Release workflow fix.
|
|
146
181
|
|
|
147
|
-
- Publishes
|
|
148
|
-
|
|
149
|
-
The package contents are otherwise the same 1.1.x private-release line:
|
|
150
|
-
Workspace terminal tabs, hidden dormant Blueprint entry, and no production
|
|
151
|
-
source maps in the npm tarball.
|
|
182
|
+
- Publishes without production source maps in the npm tarball while keeping the
|
|
183
|
+
user-facing package contents unchanged.
|
|
152
184
|
|
|
153
185
|
## 1.1.0 - 2026-05-17
|
|
154
186
|
|
|
155
|
-
|
|
187
|
+
Workspace terminal release.
|
|
156
188
|
|
|
157
189
|
- Added a Workspace terminal that opens from the active workspace and runs in
|
|
158
190
|
the workspace directory. It supports multiple shell tabs, full-height terminal
|
|
159
191
|
space, tab switching, and closing individual tabs without closing the whole
|
|
160
192
|
dialog.
|
|
161
193
|
- Kept the external install path unchanged. Users still install with
|
|
162
|
-
`npm install -g @tt-a1i/hive` or run with `npx @tt-a1i/hive
|
|
163
|
-
built from the private product repository and published to the same npm
|
|
164
|
-
package.
|
|
194
|
+
`npm install -g @tt-a1i/hive` or run with `npx @tt-a1i/hive`.
|
|
165
195
|
- Hid the dormant task-graph / Blueprint entry from the main UI while keeping
|
|
166
196
|
the underlying code in place for possible future use.
|
|
167
|
-
- Documented the public/private repository split and release policy in
|
|
168
|
-
`docs/private-release-strategy.md`.
|
|
169
197
|
|
|
170
198
|
## 1.0.0 - 2026-05-17
|
|
171
199
|
|
package/README.en.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/logo.png" width="120" alt="Hive logo" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# Hive
|
|
2
6
|
|
|
3
7
|
<p align="center">
|
|
@@ -15,12 +19,12 @@ Code, research, drafts, translations — if a team can split the work, a hive ca
|
|
|
15
19
|
|
|
16
20
|
[](https://www.npmjs.com/package/@tt-a1i/hive)
|
|
17
21
|
[](https://github.com/tt-a1i/hive/actions/workflows/release.yml)
|
|
18
|
-
[](https://hivehq.dev)
|
|
19
23
|
[](https://nodejs.org/)
|
|
20
24
|
[](./LICENSE.BSL)
|
|
21
25
|
[-lightgrey.svg)](#platform-support)
|
|
22
26
|
|
|
23
|
-
🌐 **Website**: [
|
|
27
|
+
🌐 **Website**: [hivehq.dev/en/](https://hivehq.dev/en/) · [中文](https://hivehq.dev/)
|
|
24
28
|
|
|
25
29
|
English · [简体中文](./README.md)
|
|
26
30
|
|
|
@@ -29,6 +33,10 @@ English · [简体中文](./README.md)
|
|
|
29
33
|
> [npm](https://www.npmjs.com/package/@tt-a1i/hive) and the badge above resolves
|
|
30
34
|
> to it.
|
|
31
35
|
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="./assets/hive-team-view.png" alt="Hive workbench with a 4-agent team — orchestrator dispatching while workers run" />
|
|
38
|
+
</p>
|
|
39
|
+
|
|
32
40
|
## Why Hive
|
|
33
41
|
|
|
34
42
|
CLI agents are powerful, but coordinating several of them manually is
|
|
@@ -236,6 +244,11 @@ Hive depends on `node-pty` and `better-sqlite3`, which use native binaries. Use
|
|
|
236
244
|
Node.js 22+, keep your package manager cache clean, and verify your platform
|
|
237
245
|
build tools are available.
|
|
238
246
|
|
|
247
|
+
If npm prints a deprecated warning for `prebuild-install@7.1.3`, it is safe to
|
|
248
|
+
ignore. The warning comes from `better-sqlite3`'s native binary download chain;
|
|
249
|
+
it is an upstream installer maintenance notice, not a Hive install failure, and
|
|
250
|
+
does not affect runtime behavior.
|
|
251
|
+
|
|
239
252
|
**Folder picker does not open on Linux**
|
|
240
253
|
|
|
241
254
|
Install `zenity`, or paste the workspace path manually.
|
|
@@ -300,12 +313,21 @@ verifies macOS, Ubuntu, and Windows, then publishes to npm with `NPM_TOKEN`.
|
|
|
300
313
|
|
|
301
314
|
## Status
|
|
302
315
|
|
|
303
|
-
Hive is
|
|
304
|
-
multi-agent collaboration workflow, Windows support, and clearer
|
|
305
|
-
observability.
|
|
316
|
+
Hive is in alpha. The core flow is usable today; current work focuses on
|
|
317
|
+
polishing the multi-agent collaboration workflow, Windows support, and clearer
|
|
318
|
+
orchestration observability. Try it out and open issues — feedback shapes what
|
|
319
|
+
gets prioritized next.
|
|
306
320
|
|
|
307
|
-
##
|
|
321
|
+
## A different form factor: squad
|
|
322
|
+
|
|
323
|
+
If you'd rather have **pure CLI, zero background process, and the ability to
|
|
324
|
+
run on a remote SSH box**, [squad](https://github.com/mco-org/squad) takes the
|
|
325
|
+
same idea down a different path — SQLite as the protocol layer, one terminal
|
|
326
|
+
per agent. The two projects don't replace each other; pick by workflow:
|
|
308
327
|
|
|
309
|
-
Hive
|
|
328
|
+
- **Hive** — visual workbench, one-click restart, workspace sidebar, easier to demo to a team
|
|
329
|
+
- **squad** — lives in tmux, SSH remote dev, no extra background process, Windows servers
|
|
330
|
+
|
|
331
|
+
## License
|
|
310
332
|
|
|
311
|
-
|
|
333
|
+
Hive is open source 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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/logo.png" width="120" alt="Hive logo" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# Hive
|
|
2
6
|
|
|
3
7
|
<p align="center">
|
|
@@ -10,17 +14,21 @@
|
|
|
10
14
|
|
|
11
15
|
[](https://www.npmjs.com/package/@tt-a1i/hive)
|
|
12
16
|
[](https://github.com/tt-a1i/hive/actions/workflows/release.yml)
|
|
13
|
-
[](https://hivehq.dev)
|
|
14
18
|
[](https://nodejs.org/)
|
|
15
19
|
[](./LICENSE.BSL)
|
|
16
20
|
[-lightgrey.svg)](#平台支持)
|
|
17
21
|
|
|
18
|
-
🌐 **官网**:[
|
|
22
|
+
🌐 **官网**:[hivehq.dev](https://hivehq.dev/)([English](https://hivehq.dev/en/))
|
|
19
23
|
|
|
20
24
|
[English](./README.en.md) · 简体中文
|
|
21
25
|
|
|
22
26
|
> Hive 是本机优先的工具,只监听 `127.0.0.1`,面向已经在用 CLI Agent 的人。最新稳定版本见 [npm](https://www.npmjs.com/package/@tt-a1i/hive),上面的 badge 会指向它。
|
|
23
27
|
|
|
28
|
+
<p align="center">
|
|
29
|
+
<img src="./assets/hive-team-view.png" alt="Hive 工作台:4 个 CLI Agent 团队,Orchestrator 派单、Worker 各自开工" />
|
|
30
|
+
</p>
|
|
31
|
+
|
|
24
32
|
## 为什么需要 Hive
|
|
25
33
|
|
|
26
34
|
CLI Agent 各自都很强,但同时管几个就有点别扭:
|
|
@@ -173,6 +181,8 @@ hive --port 4020
|
|
|
173
181
|
|
|
174
182
|
Hive 依赖 `node-pty` 和 `better-sqlite3`,它们用原生二进制。确认 Node.js 22+,清干净 package manager 缓存,并准备好你平台的构建工具(macOS Xcode CLI、Linux build-essential + python3、Windows VS Build Tools)。
|
|
175
183
|
|
|
184
|
+
安装时如果看到 `prebuild-install@7.1.3` 的 deprecated warning,可以忽略。它来自 `better-sqlite3` 的原生二进制下载链路,只是上游安装器维护状态提示,不代表 Hive 安装失败,也不会影响运行。
|
|
185
|
+
|
|
176
186
|
**Linux 上目录选择器不弹**
|
|
177
187
|
|
|
178
188
|
装 `zenity`,或者直接在对话框里粘路径。
|
|
@@ -229,10 +239,15 @@ pnpm release:dry
|
|
|
229
239
|
|
|
230
240
|
## 状态
|
|
231
241
|
|
|
232
|
-
Hive
|
|
242
|
+
Hive 目前处于 alpha 阶段,核心流程已可用。当前重点是继续打磨多 Agent 协作体验、Windows 支持和更清晰的调度可观测性。欢迎试用、提 issue——反馈会直接影响后续节奏。
|
|
233
243
|
|
|
234
|
-
##
|
|
244
|
+
## 另一种形态:squad
|
|
245
|
+
|
|
246
|
+
如果你更喜欢 **纯 CLI、零后台进程、能直接在 SSH 进的远端服务器上跑** 的形态,[squad](https://github.com/mco-org/squad) 是同一个想法的另一条路线——SQLite 当通信层,每个 agent 各自开一个终端。两个项目互不替代,按工作流挑就行:
|
|
235
247
|
|
|
236
|
-
|
|
248
|
+
- **Hive** — 想要可视化工作台、一键重启、侧边栏切 workspace、给团队演示
|
|
249
|
+
- **squad** — 活在 tmux 里、SSH 远端开发、不想跑额外后台进程、Windows server
|
|
250
|
+
|
|
251
|
+
## License
|
|
237
252
|
|
|
238
|
-
|
|
253
|
+
Hive 在 Business Source License 1.1 下开源。个人使用、内部部署、嵌入、fork 都可以;详细边界见 [LICENSE.BSL](LICENSE.BSL)。
|
|
Binary file
|
package/dist/src/cli/team.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
interface ParsedCancelArgs {
|
|
2
|
+
dispatchId: string;
|
|
3
|
+
reason: string;
|
|
4
|
+
}
|
|
1
5
|
export interface ParsedReportArgs {
|
|
2
6
|
artifacts: string[];
|
|
3
7
|
dispatchId: string | undefined;
|
|
@@ -5,5 +9,7 @@ export interface ParsedReportArgs {
|
|
|
5
9
|
useStdin: boolean;
|
|
6
10
|
}
|
|
7
11
|
export declare const parseReportArgs: (args: string[], command?: string) => ParsedReportArgs;
|
|
12
|
+
export declare const parseCancelArgs: (args: string[]) => ParsedCancelArgs;
|
|
8
13
|
export declare const readStdinToString: (command?: string) => Promise<string>;
|
|
9
14
|
export declare const runTeamCommand: (argv: string[]) => Promise<void>;
|
|
15
|
+
export {};
|
package/dist/src/cli/team.js
CHANGED
|
@@ -10,6 +10,7 @@ const TEAM_USAGE = [
|
|
|
10
10
|
'Usage:',
|
|
11
11
|
' team list',
|
|
12
12
|
' team send <worker-name> "<task>"',
|
|
13
|
+
' team cancel --dispatch <dispatch-id> "<reason>"',
|
|
13
14
|
' team report "<result>" [--dispatch <dispatch-id>] [--artifact <path>]',
|
|
14
15
|
' team report --stdin [--dispatch <dispatch-id>] [--artifact <path>]',
|
|
15
16
|
' team status "<current status>" [--artifact <path>]',
|
|
@@ -80,6 +81,7 @@ const postJson = async (baseUrl, path, body) => {
|
|
|
80
81
|
};
|
|
81
82
|
const REPORT_USAGE = 'Usage: team report (<result> | --stdin) [--dispatch <dispatch-id>] [--artifact <path>]';
|
|
82
83
|
const STATUS_USAGE = 'Usage: team status (<current status> | --stdin) [--artifact <path>]';
|
|
84
|
+
const CANCEL_USAGE = 'Usage: team cancel --dispatch <dispatch-id> <reason>';
|
|
83
85
|
const usageFor = (command) => (command === 'status' ? STATUS_USAGE : REPORT_USAGE);
|
|
84
86
|
const withUsage = (message, command) => `${message}\n\n${usageFor(command)}`;
|
|
85
87
|
export const parseReportArgs = (args, command = 'report') => {
|
|
@@ -139,6 +141,39 @@ export const parseReportArgs = (args, command = 'report') => {
|
|
|
139
141
|
}
|
|
140
142
|
return { result: useStdin ? null : (positionals[0] ?? null), artifacts, dispatchId, useStdin };
|
|
141
143
|
};
|
|
144
|
+
export const parseCancelArgs = (args) => {
|
|
145
|
+
const positionals = [];
|
|
146
|
+
let dispatchId;
|
|
147
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
148
|
+
const arg = args[index];
|
|
149
|
+
if (arg === undefined)
|
|
150
|
+
continue;
|
|
151
|
+
if (arg === '--dispatch') {
|
|
152
|
+
const next = args[index + 1];
|
|
153
|
+
if (next === undefined || next.startsWith('--')) {
|
|
154
|
+
throw new Error(`--dispatch requires a value\n\n${CANCEL_USAGE}`);
|
|
155
|
+
}
|
|
156
|
+
dispatchId = next;
|
|
157
|
+
index += 1;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (arg.startsWith('--')) {
|
|
161
|
+
throw new Error(`Unknown argument: ${arg}\n\n${CANCEL_USAGE}`);
|
|
162
|
+
}
|
|
163
|
+
positionals.push(arg);
|
|
164
|
+
}
|
|
165
|
+
if (!dispatchId) {
|
|
166
|
+
throw new Error(`Missing --dispatch <dispatch-id>\n\n${CANCEL_USAGE}`);
|
|
167
|
+
}
|
|
168
|
+
if (positionals.length === 0) {
|
|
169
|
+
throw new Error(`Missing <reason>\n\n${CANCEL_USAGE}`);
|
|
170
|
+
}
|
|
171
|
+
const reason = positionals.join(' ').trim();
|
|
172
|
+
if (!reason) {
|
|
173
|
+
throw new Error(`Missing <reason>\n\n${CANCEL_USAGE}`);
|
|
174
|
+
}
|
|
175
|
+
return { dispatchId, reason };
|
|
176
|
+
};
|
|
142
177
|
export const readStdinToString = async (command = 'report') => {
|
|
143
178
|
if (process.stdin.isTTY) {
|
|
144
179
|
throw new Error(withUsage('--stdin requires piped input, but stdin is a TTY. Did you forget to pipe content in?', command));
|
|
@@ -194,6 +229,19 @@ export const runTeamCommand = async (argv) => {
|
|
|
194
229
|
console.log(JSON.stringify(await response.json()));
|
|
195
230
|
return;
|
|
196
231
|
}
|
|
232
|
+
if (command === 'cancel') {
|
|
233
|
+
const cancel = parseCancelArgs(args);
|
|
234
|
+
const env = getHiveEnv();
|
|
235
|
+
const baseUrl = getBaseUrl(env);
|
|
236
|
+
await postJson(baseUrl, '/api/team/cancel', {
|
|
237
|
+
dispatch_id: cancel.dispatchId,
|
|
238
|
+
project_id: env.HIVE_PROJECT_ID,
|
|
239
|
+
from_agent_id: env.HIVE_AGENT_ID,
|
|
240
|
+
token: env.HIVE_AGENT_TOKEN,
|
|
241
|
+
reason: cancel.reason,
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
197
245
|
if (command === 'status') {
|
|
198
246
|
const report = parseReportArgs(args, 'status');
|
|
199
247
|
const body = report.useStdin ? await readStdinToString('status') : (report.result ?? '');
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export const createAgentLaunchCache = (store) => {
|
|
2
2
|
const launchConfigs = new Map();
|
|
3
3
|
const workspaceByAgentId = new Map();
|
|
4
|
+
const missingLaunchConfigs = new Set();
|
|
4
5
|
const cacheKey = (workspaceId, agentId) => `${workspaceId}:${agentId}`;
|
|
5
6
|
const load = () => {
|
|
7
|
+
launchConfigs.clear();
|
|
8
|
+
workspaceByAgentId.clear();
|
|
6
9
|
for (const row of store.listLaunchConfigs()) {
|
|
7
10
|
launchConfigs.set(cacheKey(row.workspaceId, row.agentId), row.config);
|
|
8
11
|
workspaceByAgentId.set(row.agentId, row.workspaceId);
|
|
@@ -11,21 +14,33 @@ export const createAgentLaunchCache = (store) => {
|
|
|
11
14
|
load();
|
|
12
15
|
return {
|
|
13
16
|
get(workspaceId, agentId) {
|
|
14
|
-
const
|
|
17
|
+
const key = cacheKey(workspaceId, agentId);
|
|
18
|
+
const config = launchConfigs.get(key);
|
|
15
19
|
if (config)
|
|
16
20
|
return config;
|
|
21
|
+
if (missingLaunchConfigs.has(key)) {
|
|
22
|
+
throw new Error(`Agent launch config not found: ${agentId}`);
|
|
23
|
+
}
|
|
17
24
|
load();
|
|
18
|
-
const reloadedConfig = launchConfigs.get(
|
|
25
|
+
const reloadedConfig = launchConfigs.get(key);
|
|
19
26
|
if (reloadedConfig)
|
|
20
27
|
return reloadedConfig;
|
|
28
|
+
missingLaunchConfigs.add(key);
|
|
21
29
|
throw new Error(`Agent launch config not found: ${agentId}`);
|
|
22
30
|
},
|
|
23
31
|
peek(workspaceId, agentId) {
|
|
24
|
-
const
|
|
32
|
+
const key = cacheKey(workspaceId, agentId);
|
|
33
|
+
const config = launchConfigs.get(key);
|
|
25
34
|
if (config)
|
|
26
35
|
return config;
|
|
36
|
+
if (missingLaunchConfigs.has(key))
|
|
37
|
+
return undefined;
|
|
27
38
|
load();
|
|
28
|
-
|
|
39
|
+
const reloadedConfig = launchConfigs.get(key);
|
|
40
|
+
if (reloadedConfig)
|
|
41
|
+
return reloadedConfig;
|
|
42
|
+
missingLaunchConfigs.add(key);
|
|
43
|
+
return undefined;
|
|
29
44
|
},
|
|
30
45
|
getWorkspaceId(agentId) {
|
|
31
46
|
return workspaceByAgentId.get(agentId);
|
|
@@ -41,12 +56,16 @@ export const createAgentLaunchCache = (store) => {
|
|
|
41
56
|
sessionIdCapture: input.sessionIdCapture ?? null,
|
|
42
57
|
};
|
|
43
58
|
store.saveLaunchConfig(workspaceId, agentId, normalized);
|
|
44
|
-
|
|
59
|
+
const key = cacheKey(workspaceId, agentId);
|
|
60
|
+
launchConfigs.set(key, normalized);
|
|
61
|
+
missingLaunchConfigs.delete(key);
|
|
45
62
|
workspaceByAgentId.set(agentId, workspaceId);
|
|
46
63
|
},
|
|
47
64
|
remove(workspaceId, agentId) {
|
|
48
65
|
store.deleteLaunchConfig(workspaceId, agentId);
|
|
49
|
-
|
|
66
|
+
const key = cacheKey(workspaceId, agentId);
|
|
67
|
+
launchConfigs.delete(key);
|
|
68
|
+
missingLaunchConfigs.add(key);
|
|
50
69
|
workspaceByAgentId.delete(agentId);
|
|
51
70
|
},
|
|
52
71
|
setWorkspaceId(agentId, workspaceId) {
|
|
@@ -27,7 +27,7 @@ interface AgentRunRecord extends AgentRunSnapshot {
|
|
|
27
27
|
resize: (cols: number, rows: number) => void;
|
|
28
28
|
resume: () => void;
|
|
29
29
|
stop: () => void;
|
|
30
|
-
write: (
|
|
30
|
+
write: (input: Buffer | string) => void;
|
|
31
31
|
};
|
|
32
32
|
onExit?: (event: {
|
|
33
33
|
runId: string;
|
|
@@ -40,7 +40,7 @@ interface AgentManager {
|
|
|
40
40
|
resizeRun: (runId: string, cols: number, rows: number) => void;
|
|
41
41
|
resumeRun: (runId: string) => void;
|
|
42
42
|
startAgent: (input: StartAgentInput) => Promise<AgentRunSnapshot>;
|
|
43
|
-
writeInput: (runId: string,
|
|
43
|
+
writeInput: (runId: string, input: Buffer | string) => void;
|
|
44
44
|
getRun: (runId: string) => AgentRunSnapshot;
|
|
45
45
|
removeRun: (runId: string) => void;
|
|
46
46
|
stopRun: (runId: string) => void;
|
|
@@ -29,6 +29,9 @@ export interface AgentRuntime {
|
|
|
29
29
|
requireActiveRun?: boolean;
|
|
30
30
|
}) => void;
|
|
31
31
|
writeSendPrompt: (workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string) => void;
|
|
32
|
+
writeCancelPrompt: (workspaceId: string, workerId: string, dispatchId: string, reason: string, input?: {
|
|
33
|
+
requireActiveRun?: boolean;
|
|
34
|
+
}) => void;
|
|
32
35
|
writeUserInputPrompt: (workspaceId: string, text: string) => void;
|
|
33
36
|
}
|
|
34
37
|
export type { StartAgentOptions };
|
|
@@ -115,6 +115,9 @@ export const createAgentRuntime = (agentManager, agentRunStore, sessionStore, ge
|
|
|
115
115
|
writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
|
|
116
116
|
stdinDispatcher.writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text);
|
|
117
117
|
},
|
|
118
|
+
writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input = {}) {
|
|
119
|
+
stdinDispatcher.writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input);
|
|
120
|
+
},
|
|
118
121
|
writeUserInputPrompt(workspaceId, text) {
|
|
119
122
|
stdinDispatcher.writeUserInputPrompt(workspaceId, text);
|
|
120
123
|
},
|
|
@@ -15,7 +15,7 @@ export const buildAgentStartupInstructions = ({ agent, workspace, }) => {
|
|
|
15
15
|
'',
|
|
16
16
|
];
|
|
17
17
|
if (agent.role === 'orchestrator') {
|
|
18
|
-
lines.push('你的职责:', '- 直接响应 user,澄清需求并拆解任务', `- 维护 ${TASKS_RELATIVE_PATH}`, '- 按 worker 名称派单,并根据汇报推进下一步', '', '可用 team 命令:', '- team list', '- team send <worker-name> "<task>"', '', '派单时必须使用 worker name,不要使用 worker id。', '', 'Hive worker 派单规则:', ...getHiveTeamRules(agent));
|
|
18
|
+
lines.push('你的职责:', '- 直接响应 user,澄清需求并拆解任务', `- 维护 ${TASKS_RELATIVE_PATH}`, '- 按 worker 名称派单,并根据汇报推进下一步', '', '可用 team 命令:', '- team list', '- team send <worker-name> "<task>"', '- team cancel --dispatch <id> "<reason>"', '', '派单时必须使用 worker name,不要使用 worker id。', '取消未完成派单时必须使用 dispatch id。', '', 'Hive worker 派单规则:', ...getHiveTeamRules(agent));
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
21
21
|
lines.push('可用 team 命令:', '- team report "<完整汇报>" [--dispatch <id>] [--artifact <path>] 完成/失败/阻塞汇报', '- team report --stdin [--dispatch <id>] [--artifact <path>] 同上,从 stdin 读正文(适合多行/含引号/特殊字符)', '- team status "<当前状态>" [--artifact <path>] 中段进度/待命/接入状态', '- team status --stdin [--artifact <path>] 同上,从 stdin 读正文', '- team list 查看 workspace 内的 worker(含状态)', '- team --help 仅查命令用法;**不是**汇报手段', '', '语法要点:', '- 正文是第一个 positional argument,flag 顺序任意:`team report "结论" --dispatch X` 和 `team report --dispatch X "结论"` 都成立。', "- 长正文(多行 / 含引号 / shell 特殊字符 / heredoc)一律走 `--stdin`,并用 *quoted* heredoc(`<<'EOF'`)防止 shell 展开 $vars / 反引号 / 命令替换:", " 例:`team report --stdin --dispatch <id> <<'EOF'`", ' `... 长报告(含 $VAR、`backtick`、"引号" 都按字面量保留)...`', ' `EOF`', '- CLI 报错会同时打印 USAGE,可直接对照修正参数。', '', '完成任务后必须执行 `team report "<结论>"`。', '失败、阻塞或部分完成也用 `team report "<当前状态与原因>"` 汇报。', '没有进行中的任务时,用 `team status "<当前状态>"` 汇报接入、待命或阻塞状态。', '不要调用 team send;worker 之间不能直接派单。', '', 'Hive worker 边界:', ...getHiveTeamRules(agent));
|
|
@@ -13,6 +13,7 @@ export declare const buildOrchestratorReportPayload: (workerName: string, text:
|
|
|
13
13
|
export declare const buildOrchestratorStatusPayload: (workerName: string, text: string, artifacts: string[]) => string;
|
|
14
14
|
export declare const buildOrchestratorUserInputPayload: (text: string) => string;
|
|
15
15
|
export declare const buildWorkerDispatchPayload: (fromAgentName: string, workerDescription: string, dispatchId: string, text: string) => string;
|
|
16
|
+
export declare const buildWorkerCancelPayload: (dispatchId: string, reason: string) => string;
|
|
16
17
|
export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, }: AgentStdinDispatcherInput) => {
|
|
17
18
|
writeReportPrompt(workspaceId: string, workerName: string, text: string, artifacts: string[], input?: {
|
|
18
19
|
requireActiveRun?: boolean;
|
|
@@ -21,6 +22,9 @@ export declare const createAgentStdinDispatcher: ({ agentManager, getLaunchConfi
|
|
|
21
22
|
requireActiveRun?: boolean;
|
|
22
23
|
}): void;
|
|
23
24
|
writeSendPrompt(workspaceId: string, workerId: string, dispatchId: string, fromAgentName: string, workerDescription: string, text: string): void;
|
|
25
|
+
writeCancelPrompt(workspaceId: string, workerId: string, dispatchId: string, reason: string, input?: {
|
|
26
|
+
requireActiveRun?: boolean;
|
|
27
|
+
}): void;
|
|
24
28
|
writeUserInputPrompt(workspaceId: string, text: string): void;
|
|
25
29
|
};
|
|
26
30
|
export {};
|
|
@@ -33,6 +33,15 @@ export const buildWorkerDispatchPayload = (fromAgentName, workerDescription, dis
|
|
|
33
33
|
buildWorkerReminderTail(dispatchId),
|
|
34
34
|
'',
|
|
35
35
|
].join('\n');
|
|
36
|
+
export const buildWorkerCancelPayload = (dispatchId, reason) => [
|
|
37
|
+
`[Hive 系统消息:dispatch ${dispatchId} 已取消]`,
|
|
38
|
+
'',
|
|
39
|
+
'请停止执行这条派单,不要再为它调用 team report。',
|
|
40
|
+
'',
|
|
41
|
+
'取消原因:',
|
|
42
|
+
reason,
|
|
43
|
+
'',
|
|
44
|
+
].join('\n');
|
|
36
45
|
export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getWorkspaceId, registry, syncRun, }) => {
|
|
37
46
|
const writeToActiveAgentRun = (workspaceId, agentId, text, input = {}) => {
|
|
38
47
|
const run = registry
|
|
@@ -72,6 +81,9 @@ export const createAgentStdinDispatcher = ({ agentManager, getLaunchConfig, getW
|
|
|
72
81
|
writeSendPrompt(workspaceId, workerId, dispatchId, fromAgentName, workerDescription, text) {
|
|
73
82
|
writeToActiveAgentRun(workspaceId, workerId, buildWorkerDispatchPayload(fromAgentName, workerDescription, dispatchId, text), { requireActiveRun: true });
|
|
74
83
|
},
|
|
84
|
+
writeCancelPrompt(workspaceId, workerId, dispatchId, reason, input = {}) {
|
|
85
|
+
writeToActiveAgentRun(workspaceId, workerId, buildWorkerCancelPayload(dispatchId, reason), input);
|
|
86
|
+
},
|
|
75
87
|
writeUserInputPrompt(workspaceId, text) {
|
|
76
88
|
writeToActiveAgentRun(workspaceId, `${workspaceId}:orchestrator`, buildOrchestratorUserInputPayload(text));
|
|
77
89
|
},
|
package/dist/src/server/app.js
CHANGED
|
@@ -129,6 +129,6 @@ export const createApp = ({ store, pickFolderService = pickFolder, openWorkspace
|
|
|
129
129
|
sendJson(response, 500, { error: message });
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
-
createTerminalWebSocketServer(server, store);
|
|
132
|
+
createTerminalWebSocketServer(server, store, tasksFileService);
|
|
133
133
|
return { server, store };
|
|
134
134
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Database } from 'better-sqlite3';
|
|
2
|
-
export type DispatchStatus = 'queued' | 'submitted' | 'reported';
|
|
2
|
+
export type DispatchStatus = 'queued' | 'submitted' | 'reported' | 'cancelled';
|
|
3
3
|
export interface DispatchRecord {
|
|
4
4
|
artifacts: string[];
|
|
5
5
|
createdAt: number;
|
|
@@ -28,6 +28,11 @@ interface ReportDispatchInput {
|
|
|
28
28
|
toAgentId: string;
|
|
29
29
|
workspaceId: string;
|
|
30
30
|
}
|
|
31
|
+
interface CancelDispatchInput {
|
|
32
|
+
dispatchId: string;
|
|
33
|
+
reason: string;
|
|
34
|
+
workspaceId: string;
|
|
35
|
+
}
|
|
31
36
|
export interface ListDispatchesOptions {
|
|
32
37
|
limit?: number;
|
|
33
38
|
offset?: number;
|
|
@@ -39,12 +44,28 @@ export declare const createDispatchLedgerStore: (db: Database) => {
|
|
|
39
44
|
deleteWorkerDispatches: (workspaceId: string, workerId: string) => void;
|
|
40
45
|
deleteWorkspaceDispatches: (workspaceId: string) => void;
|
|
41
46
|
findOpenDispatch: (workspaceId: string, toAgentId: string, dispatchId?: string) => DispatchRecord | undefined;
|
|
47
|
+
findOpenDispatchById: (workspaceId: string, dispatchId: string) => DispatchRecord | undefined;
|
|
42
48
|
listOpenDispatchKinds: () => Array<{
|
|
43
49
|
type: "send";
|
|
44
50
|
worker_id: string;
|
|
45
51
|
workspace_id: string;
|
|
46
52
|
}>;
|
|
47
53
|
listWorkspaceDispatches: (workspaceId: string, options?: ListDispatchesOptions) => DispatchRecord[];
|
|
54
|
+
markCancelled: (input: CancelDispatchInput) => {
|
|
55
|
+
reportedAt: number;
|
|
56
|
+
reportText: string;
|
|
57
|
+
status: "cancelled";
|
|
58
|
+
artifacts: string[];
|
|
59
|
+
createdAt: number;
|
|
60
|
+
deliveredAt: number | null;
|
|
61
|
+
fromAgentId: string | null;
|
|
62
|
+
id: string;
|
|
63
|
+
sequence: number | null;
|
|
64
|
+
submittedAt: number | null;
|
|
65
|
+
text: string;
|
|
66
|
+
toAgentId: string;
|
|
67
|
+
workspaceId: string;
|
|
68
|
+
} | undefined;
|
|
48
69
|
markReportedByWorker: (input: ReportDispatchInput) => {
|
|
49
70
|
artifacts: string[];
|
|
50
71
|
reportedAt: number;
|
|
@@ -77,7 +77,7 @@ export const createDispatchLedgerStore = (db) => {
|
|
|
77
77
|
WHERE id = ?
|
|
78
78
|
AND workspace_id = ?
|
|
79
79
|
AND to_agent_id = ?
|
|
80
|
-
AND status
|
|
80
|
+
AND status IN ('queued', 'submitted')
|
|
81
81
|
LIMIT 1`)
|
|
82
82
|
.get(dispatchId, workspaceId, toAgentId);
|
|
83
83
|
return row ? toRecord(row) : undefined;
|
|
@@ -87,12 +87,23 @@ export const createDispatchLedgerStore = (db) => {
|
|
|
87
87
|
FROM dispatches
|
|
88
88
|
WHERE workspace_id = ?
|
|
89
89
|
AND to_agent_id = ?
|
|
90
|
-
AND status
|
|
90
|
+
AND status IN ('queued', 'submitted')
|
|
91
91
|
ORDER BY sequence ASC
|
|
92
92
|
LIMIT 1`)
|
|
93
93
|
.get(workspaceId, toAgentId);
|
|
94
94
|
return row ? toRecord(row) : undefined;
|
|
95
95
|
};
|
|
96
|
+
const findOpenDispatchById = (workspaceId, dispatchId) => {
|
|
97
|
+
const row = db
|
|
98
|
+
.prepare(`SELECT *
|
|
99
|
+
FROM dispatches
|
|
100
|
+
WHERE id = ?
|
|
101
|
+
AND workspace_id = ?
|
|
102
|
+
AND status IN ('queued', 'submitted')
|
|
103
|
+
LIMIT 1`)
|
|
104
|
+
.get(dispatchId, workspaceId);
|
|
105
|
+
return row ? toRecord(row) : undefined;
|
|
106
|
+
};
|
|
96
107
|
const markReportedByWorker = (input) => {
|
|
97
108
|
const dispatch = findOpenDispatch(input.workspaceId, input.toAgentId, input.dispatchId);
|
|
98
109
|
if (!dispatch) {
|
|
@@ -113,6 +124,24 @@ export const createDispatchLedgerStore = (db) => {
|
|
|
113
124
|
status: 'reported',
|
|
114
125
|
};
|
|
115
126
|
};
|
|
127
|
+
const markCancelled = (input) => {
|
|
128
|
+
const dispatch = findOpenDispatchById(input.workspaceId, input.dispatchId);
|
|
129
|
+
if (!dispatch) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
const cancelledAt = Date.now();
|
|
133
|
+
db.prepare(`UPDATE dispatches
|
|
134
|
+
SET status = ?,
|
|
135
|
+
reported_at = ?,
|
|
136
|
+
report_text = ?
|
|
137
|
+
WHERE id = ?`).run('cancelled', cancelledAt, input.reason, dispatch.id);
|
|
138
|
+
return {
|
|
139
|
+
...dispatch,
|
|
140
|
+
reportedAt: cancelledAt,
|
|
141
|
+
reportText: input.reason,
|
|
142
|
+
status: 'cancelled',
|
|
143
|
+
};
|
|
144
|
+
};
|
|
116
145
|
const listWorkspaceDispatches = (workspaceId, options = {}) => {
|
|
117
146
|
const offset = options.offset ?? 0;
|
|
118
147
|
const limit = options.limit ?? 100;
|
|
@@ -138,7 +167,7 @@ export const createDispatchLedgerStore = (db) => {
|
|
|
138
167
|
return db
|
|
139
168
|
.prepare(`SELECT workspace_id, to_agent_id AS worker_id, 'send' AS type
|
|
140
169
|
FROM dispatches
|
|
141
|
-
WHERE status
|
|
170
|
+
WHERE status IN ('queued', 'submitted')
|
|
142
171
|
ORDER BY sequence ASC`)
|
|
143
172
|
.all();
|
|
144
173
|
};
|
|
@@ -154,8 +183,10 @@ export const createDispatchLedgerStore = (db) => {
|
|
|
154
183
|
deleteWorkerDispatches,
|
|
155
184
|
deleteWorkspaceDispatches,
|
|
156
185
|
findOpenDispatch,
|
|
186
|
+
findOpenDispatchById,
|
|
157
187
|
listOpenDispatchKinds,
|
|
158
188
|
listWorkspaceDispatches,
|
|
189
|
+
markCancelled,
|
|
159
190
|
markReportedByWorker,
|
|
160
191
|
markSubmitted,
|
|
161
192
|
};
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* abstract identity restatement.
|
|
15
15
|
*/
|
|
16
16
|
export const ORCHESTRATOR_REMINDER_TAIL = '<hive-system-reminder>\n' +
|
|
17
|
-
'You are the Hive Orchestrator. Reply by either: (a) `team send "<worker-name>" "<task>"` to dispatch follow-up work to a Hive worker, or (
|
|
17
|
+
'You are the Hive Orchestrator. Reply by either: (a) `team send "<worker-name>" "<task>"` to dispatch follow-up work to a Hive worker, (b) `team cancel --dispatch <id> "<reason>"` to cancel an obsolete dispatch, or (c) plain text to the user. Never call your CLI\'s built-in subagent tools (Task / Explore / etc.) — they bypass Hive and will not appear in the UI.\n' +
|
|
18
18
|
'</hive-system-reminder>';
|
|
19
19
|
/**
|
|
20
20
|
* Tail reminder appended to dispatches sent TO a worker. Reinforces the
|
|
@@ -31,6 +31,7 @@ const ORCHESTRATOR_RULES = [
|
|
|
31
31
|
'普通、低风险、几分钟内能直接完成的小任务可以自己做;不要为了形式感派 worker。需要并行、长时间执行、独立 review/test、专门角色,或 user 明确要求 worker/成员处理时,再用 `team send`。',
|
|
32
32
|
'如果只有一个可用 worker,直接用 `team send <worker-name> "<task>"` 派给它;不要把选择题丢回给 user。',
|
|
33
33
|
'当 user 要你“让 worker ...”时,必须用 `team send <worker-name> "<task>"` 派给 Hive worker。',
|
|
34
|
+
'方向变更或 user 明确取消某个未完成派单时,使用 `team cancel --dispatch <id> "<reason>"` 显式关闭旧 dispatch;不要只用自然语言说“取消”。',
|
|
34
35
|
'不要使用你所在 CLI 的内置 subagent / 子代理工具(如 Task / Explore 等)来代替 Hive worker;它们不会出现在 Hive UI,也不会更新 Hive 调度状态。',
|
|
35
36
|
'`team list` 返回的 `last_pty_line` 是该 worker PTY 终端的最后一行原始输出(含任意 stdout / help / 控制序列噪声),**不是** worker 的正式汇报。正式汇报只来自 stdin 注入的 `[Hive 系统消息:来自 @<name> 的汇报]` 或 `[Hive 系统消息:来自 @<name> 的状态更新]`——只把这两种来源当作 reply。',
|
|
36
37
|
];
|
|
@@ -74,6 +75,7 @@ export const buildProtocolDoc = () => [
|
|
|
74
75
|
'',
|
|
75
76
|
'- `team list` — show workspace members and their status',
|
|
76
77
|
'- `team send "<worker-name>" "<task>"` — dispatch to a worker by name (never id)',
|
|
78
|
+
'- `team cancel --dispatch <id> "<reason>"` — cancel an obsolete open dispatch',
|
|
77
79
|
'',
|
|
78
80
|
'## `team` CLI — worker',
|
|
79
81
|
'',
|