@tt-a1i/hive 1.4.3 → 1.5.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.
- package/CHANGELOG.md +44 -0
- package/README.en.md +5 -4
- package/README.md +9 -1
- package/assets/qq-group.jpg +0 -0
- package/dist/bin/team.cmd +1 -0
- package/dist/src/cli/hive-update.d.ts +57 -0
- package/dist/src/cli/hive-update.js +92 -15
- package/dist/src/cli/hive.d.ts +57 -0
- package/dist/src/cli/hive.js +113 -20
- package/dist/src/cli/team.d.ts +1 -0
- package/dist/src/cli/team.js +215 -7
- package/dist/src/server/agent-command-resolver.d.ts +10 -1
- package/dist/src/server/agent-command-resolver.js +32 -4
- package/dist/src/server/agent-launch-resolver.js +9 -3
- package/dist/src/server/agent-manager-support.d.ts +28 -0
- package/dist/src/server/agent-manager-support.js +138 -10
- package/dist/src/server/agent-run-bootstrap.d.ts +17 -1
- package/dist/src/server/agent-run-bootstrap.js +30 -2
- package/dist/src/server/agent-run-starter.d.ts +7 -1
- package/dist/src/server/agent-run-starter.js +9 -2
- package/dist/src/server/agent-run-store.d.ts +1 -1
- package/dist/src/server/agent-runtime-close.d.ts +1 -0
- package/dist/src/server/agent-runtime-close.js +25 -1
- package/dist/src/server/agent-runtime-contract.d.ts +2 -1
- package/dist/src/server/agent-runtime.d.ts +1 -1
- package/dist/src/server/agent-runtime.js +8 -2
- package/dist/src/server/agent-startup-instructions.d.ts +8 -1
- package/dist/src/server/agent-startup-instructions.js +15 -9
- package/dist/src/server/agent-stdin-dispatcher.d.ts +12 -5
- package/dist/src/server/agent-stdin-dispatcher.js +129 -40
- package/dist/src/server/app.d.ts +1 -0
- package/dist/src/server/app.js +12 -2
- package/dist/src/server/cron-util.d.ts +7 -0
- package/dist/src/server/cron-util.js +19 -0
- package/dist/src/server/dispatch-ledger-store.d.ts +22 -0
- package/dist/src/server/dispatch-ledger-store.js +51 -3
- package/dist/src/server/env-sync-message.js +9 -9
- package/dist/src/server/fs-browse.d.ts +14 -1
- package/dist/src/server/fs-browse.js +48 -5
- package/dist/src/server/fs-pick-folder.js +58 -11
- package/dist/src/server/fs-sandbox.js +36 -7
- package/dist/src/server/hive-team-guidance.d.ts +11 -6
- package/dist/src/server/hive-team-guidance.js +252 -70
- package/dist/src/server/live-run-registry.d.ts +1 -0
- package/dist/src/server/live-run-registry.js +1 -1
- package/dist/src/server/open-target-commands.js +29 -4
- package/dist/src/server/orchestrator-autostart.d.ts +12 -0
- package/dist/src/server/orchestrator-autostart.js +15 -13
- package/dist/src/server/path-canonicalization.d.ts +3 -0
- package/dist/src/server/path-canonicalization.js +29 -0
- package/dist/src/server/platform-path.d.ts +3 -0
- package/dist/src/server/platform-path.js +13 -0
- package/dist/src/server/post-start-input-writer.d.ts +1 -1
- package/dist/src/server/post-start-input-writer.js +116 -16
- package/dist/src/server/preset-launch-support.d.ts +1 -1
- package/dist/src/server/preset-launch-support.js +33 -2
- package/dist/src/server/recovery-summary.d.ts +6 -1
- package/dist/src/server/recovery-summary.js +17 -17
- package/dist/src/server/restart-policy-support.d.ts +6 -1
- package/dist/src/server/restart-policy-support.js +9 -1
- package/dist/src/server/restart-policy.d.ts +2 -2
- package/dist/src/server/restart-policy.js +3 -1
- package/dist/src/server/role-template-store.d.ts +1 -0
- package/dist/src/server/role-template-store.js +11 -1
- package/dist/src/server/route-types.d.ts +43 -0
- package/dist/src/server/routes-runtime.js +2 -1
- package/dist/src/server/routes-settings.js +76 -0
- package/dist/src/server/routes-team.js +221 -2
- package/dist/src/server/routes-workflow-schedules.d.ts +2 -0
- package/dist/src/server/routes-workflow-schedules.js +58 -0
- package/dist/src/server/routes-workflows.d.ts +2 -0
- package/dist/src/server/routes-workflows.js +83 -0
- package/dist/src/server/routes.js +4 -0
- package/dist/src/server/runtime-restart-policy.d.ts +3 -1
- package/dist/src/server/runtime-restart-policy.js +3 -1
- package/dist/src/server/runtime-store-contract.d.ts +122 -0
- package/dist/src/server/runtime-store-contract.js +1 -0
- package/dist/src/server/runtime-store-helpers.d.ts +9 -0
- package/dist/src/server/runtime-store-helpers.js +101 -2
- package/dist/src/server/runtime-store-workflows.d.ts +6 -0
- package/dist/src/server/runtime-store-workflows.js +100 -0
- package/dist/src/server/runtime-store.d.ts +3 -70
- package/dist/src/server/runtime-store.js +70 -4
- package/dist/src/server/session-capture-claude.d.ts +23 -0
- package/dist/src/server/session-capture-claude.js +24 -1
- package/dist/src/server/session-capture-codex.d.ts +3 -3
- package/dist/src/server/session-capture-codex.js +9 -7
- package/dist/src/server/session-capture-gemini.d.ts +1 -1
- package/dist/src/server/session-capture-gemini.js +6 -3
- package/dist/src/server/session-capture-opencode.d.ts +18 -0
- package/dist/src/server/session-capture-opencode.js +27 -2
- package/dist/src/server/settings-store.d.ts +3 -0
- package/dist/src/server/settings-store.js +1 -0
- package/dist/src/server/sqlite-schema-v19.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v19.js +17 -0
- package/dist/src/server/sqlite-schema-v20.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v20.js +20 -0
- package/dist/src/server/sqlite-schema-v21.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v21.js +20 -0
- package/dist/src/server/sqlite-schema.d.ts +1 -1
- package/dist/src/server/sqlite-schema.js +97 -1
- package/dist/src/server/startup-command-parser.d.ts +15 -0
- package/dist/src/server/startup-command-parser.js +33 -2
- package/dist/src/server/system-message.d.ts +7 -0
- package/dist/src/server/system-message.js +8 -1
- package/dist/src/server/tasks-file-watcher.d.ts +39 -1
- package/dist/src/server/tasks-file-watcher.js +155 -25
- package/dist/src/server/tasks-file.d.ts +2 -1
- package/dist/src/server/tasks-file.js +32 -9
- package/dist/src/server/tasks-websocket-server.js +13 -14
- package/dist/src/server/team-authz.d.ts +1 -1
- package/dist/src/server/team-authz.js +9 -1
- package/dist/src/server/team-autostaff.d.ts +16 -0
- package/dist/src/server/team-autostaff.js +16 -0
- package/dist/src/server/team-list-serializer.d.ts +1 -1
- package/dist/src/server/team-list-serializer.js +3 -1
- package/dist/src/server/team-operations.d.ts +20 -2
- package/dist/src/server/team-operations.js +160 -14
- package/dist/src/server/terminal-input-profile.js +2 -8
- package/dist/src/server/terminal-protocol.js +9 -3
- package/dist/src/server/terminal-stream-hub.js +16 -10
- package/dist/src/server/terminal-ws-server.js +36 -16
- package/dist/src/server/websocket-upgrade-safety.d.ts +10 -0
- package/dist/src/server/websocket-upgrade-safety.js +35 -0
- package/dist/src/server/windows-command-line.d.ts +3 -0
- package/dist/src/server/windows-command-line.js +9 -0
- package/dist/src/server/windows-filename.d.ts +2 -0
- package/dist/src/server/windows-filename.js +33 -0
- package/dist/src/server/workflow-cli-policy.d.ts +60 -0
- package/dist/src/server/workflow-cli-policy.js +110 -0
- package/dist/src/server/workflow-dispatch-awaiter.d.ts +12 -0
- package/dist/src/server/workflow-dispatch-awaiter.js +80 -0
- package/dist/src/server/workflow-feature.d.ts +15 -0
- package/dist/src/server/workflow-feature.js +15 -0
- package/dist/src/server/workflow-http-serializers.d.ts +64 -0
- package/dist/src/server/workflow-http-serializers.js +58 -0
- package/dist/src/server/workflow-run-log-store.d.ts +19 -0
- package/dist/src/server/workflow-run-log-store.js +45 -0
- package/dist/src/server/workflow-run-store.d.ts +50 -0
- package/dist/src/server/workflow-run-store.js +103 -0
- package/dist/src/server/workflow-runner.d.ts +147 -0
- package/dist/src/server/workflow-runner.js +401 -0
- package/dist/src/server/workflow-schedule-create.d.ts +14 -0
- package/dist/src/server/workflow-schedule-create.js +41 -0
- package/dist/src/server/workflow-schedule-store.d.ts +43 -0
- package/dist/src/server/workflow-schedule-store.js +112 -0
- package/dist/src/server/workflow-scheduler.d.ts +36 -0
- package/dist/src/server/workflow-scheduler.js +97 -0
- package/dist/src/server/workflow-script-loader.d.ts +34 -0
- package/dist/src/server/workflow-script-loader.js +106 -0
- package/dist/src/server/workspace-path-validation.js +16 -4
- package/dist/src/server/workspace-shell-runtime.d.ts +5 -0
- package/dist/src/server/workspace-shell-runtime.js +24 -2
- package/dist/src/server/workspace-store-contract.d.ts +4 -1
- package/dist/src/server/workspace-store-hydration.js +23 -7
- package/dist/src/server/workspace-store-mutations.js +2 -5
- package/dist/src/server/workspace-store-support.d.ts +4 -0
- package/dist/src/server/workspace-store-support.js +13 -1
- package/dist/src/server/workspace-store.js +38 -4
- package/dist/src/shared/types.d.ts +16 -1
- package/package.json +4 -2
- package/web/dist/assets/{AddWorkerDialog-DmkDOdp6.js → AddWorkerDialog-CcC-7kgG.js} +2 -2
- package/web/dist/assets/AddWorkspaceDialog-BDpOTfmt.js +1 -0
- package/web/dist/assets/{FirstRunWizard-SAd1wsH4.js → FirstRunWizard-BYX_ocQn.js} +1 -1
- package/web/dist/assets/{MarketplaceDrawer-B_8aG2uT.js → MarketplaceDrawer-DUxSk7db.js} +1 -1
- package/web/dist/assets/WhatsNewDialog-B_RlCXcV.js +1 -0
- package/web/dist/assets/WorkerModal-D9-7YfZZ.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-BCKoF7qc.js +1 -0
- package/web/dist/assets/{WorkspaceTerminalPanels-BReWh1YL.js → WorkspaceTerminalPanels-Dq8y91t2.js} +1 -1
- package/web/dist/assets/index-BiOvKIVw.css +1 -0
- package/web/dist/assets/index-DMRUklT3.js +73 -0
- package/web/dist/assets/path-join-7MR1s7b1.js +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/sw.js +1 -1
- package/web/dist/assets/AddWorkspaceDialog-BsVnH3Xe.js +0 -1
- package/web/dist/assets/WorkerModal-CQmjiPme.js +0 -1
- package/web/dist/assets/WorkspaceTaskDrawer-B0DmCWcV.js +0 -1
- package/web/dist/assets/chevron-right-CtLjVEl7.js +0 -1
- package/web/dist/assets/index-BEsTmfrO.css +0 -1
- package/web/dist/assets/index-Cn8X3get.js +0 -76
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
All notable user-facing changes will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.5.0 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
Workflow runtime, experimental team automation, and Codex reliability.
|
|
8
|
+
|
|
9
|
+
- Adds the experimental Hive workflow runtime: Orchestrators can author
|
|
10
|
+
multi-agent workflow scripts that fan out across real Hive PTY workers, show
|
|
11
|
+
runs in the Workflows drawer, stop runs, inspect run details, schedule
|
|
12
|
+
recurring workflows, and route workflow reports back into the Orchestrator.
|
|
13
|
+
- Adds workflow agent CLI policy settings so users can choose which CLI
|
|
14
|
+
workflow-created agents use by default and which CLIs are allowed.
|
|
15
|
+
- Adds the experimental auto-staff setting, letting the Orchestrator size the
|
|
16
|
+
worker roster to the task and prefer task-scoped ephemeral workers when it
|
|
17
|
+
needs temporary coders, testers, or reviewers.
|
|
18
|
+
- Adds an in-app What's New dialog so future upgrades can surface curated
|
|
19
|
+
release highlights without requiring users to read the changelog manually.
|
|
20
|
+
- Improves Codex reliability by waiting for pasted-content acknowledgements on
|
|
21
|
+
long dispatches while submitting short report/status injections quickly,
|
|
22
|
+
avoiding the several-second delay before reports reach the Orchestrator.
|
|
23
|
+
- Hardens Windows and runtime edge cases, including malformed WebSocket frames,
|
|
24
|
+
stale nvm4w Codex node entrypoints, workflow worker exits, and additional
|
|
25
|
+
workflow/runtime cleanup paths.
|
|
26
|
+
|
|
27
|
+
## 1.4.4 - 2026-05-29
|
|
28
|
+
|
|
29
|
+
Windows portability and team protocol hardening.
|
|
30
|
+
|
|
31
|
+
- Fixes Windows `.cmd` / `.bat` launch handling for built-in and custom startup
|
|
32
|
+
commands, including quoted paths from nvm4w and `Program Files`.
|
|
33
|
+
- Improves Windows runtime shutdown by tearing down WebSocket connections before
|
|
34
|
+
closing the HTTP server and killing worker process trees with `taskkill /T /F`
|
|
35
|
+
before falling back to PTY termination.
|
|
36
|
+
- Makes `hive update`, open-in-editor commands, folder picking, filesystem
|
|
37
|
+
browsing, and port-in-use recovery friendlier on Windows.
|
|
38
|
+
- Preserves CRLF line endings in `.hive/tasks.md` mutations and makes the tasks
|
|
39
|
+
watcher more tolerant of atomic-save editors.
|
|
40
|
+
- Resolves OpenCode session data under `%LOCALAPPDATA%` on Windows and aligns
|
|
41
|
+
Claude session path encoding with Claude Code's project directory format.
|
|
42
|
+
- Hardens `team send` against stale worker names by returning a 409 with the
|
|
43
|
+
current roster and updates orchestrator guidance to refresh the member list
|
|
44
|
+
before dispatching.
|
|
45
|
+
- Expands Windows-focused unit and integration coverage across startup command
|
|
46
|
+
parsing, CLI shims, stdin protocol help, terminal profiles, filesystem
|
|
47
|
+
browsing, process cleanup, and path rendering.
|
|
48
|
+
|
|
5
49
|
## 1.4.3 - 2026-05-28
|
|
6
50
|
|
|
7
51
|
Update hardening for multi-Node installs.
|
package/README.en.md
CHANGED
|
@@ -107,10 +107,11 @@ a separate app from `hive --port 3000`. To uninstall, visit `chrome://apps`,
|
|
|
107
107
|
right-click the Hive tile, and choose **Remove from Chrome…**.
|
|
108
108
|
|
|
109
109
|
Hive asks the browser to confirm before closing the tab or PWA window so an
|
|
110
|
-
accidental Cmd-W
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
accidental close shortcut (Cmd-W on macOS, Ctrl-W on Windows/Linux) doesn't
|
|
111
|
+
drop your session. Modern browsers gate that prompt on prior page interaction
|
|
112
|
+
— if you open the PWA and immediately press the close shortcut without
|
|
113
|
+
clicking or typing anywhere first, it still closes cleanly. That's a browser
|
|
114
|
+
policy, not a Hive bug.
|
|
114
115
|
|
|
115
116
|
First-run flow:
|
|
116
117
|
|
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ hive update
|
|
|
74
74
|
|
|
75
75
|
PWA 只是 UI 壳,Hive 后端仍需要在终端里跑着。如果启动 PWA 时后端没起,会看到 “Hive 后端未启动” 页面,等你跑起 `hive` 后会自动刷新。PWA 的 install scope 按 origin(含端口)划分,所以 `hive --port 4011` 跟 `hive --port 3000` 在浏览器看来是两个独立应用。卸载方法:浏览器地址栏访问 `chrome://apps`,右键 Hive 图标,选 **从 Chrome 中移除…**。
|
|
76
76
|
|
|
77
|
-
关闭 PWA 窗口或 tab 时 Hive
|
|
77
|
+
关闭 PWA 窗口或 tab 时 Hive 会主动请求浏览器弹原生确认对话框,避免关闭快捷键(macOS 上是 Cmd+W、Windows / Linux 上是 Ctrl+W)误关丢失会话。但现代浏览器要求你跟页面"交互过"(点击 / 滚动 / 输入)才会真的弹这个对话框——刚打开 PWA 立刻按关闭快捷键仍会直接关闭,这是浏览器策略,不是 Hive 的 bug。
|
|
78
78
|
|
|
79
79
|
首次使用流程:
|
|
80
80
|
|
|
@@ -241,6 +241,14 @@ pnpm release:dry
|
|
|
241
241
|
|
|
242
242
|
Hive 目前处于 alpha 阶段,核心流程已可用。当前重点是继续打磨多 Agent 协作体验、Windows 支持和更清晰的调度可观测性。欢迎试用、提 issue——反馈会直接影响后续节奏。
|
|
243
243
|
|
|
244
|
+
## 交流群
|
|
245
|
+
|
|
246
|
+
有问题、想反馈,或者就想聊聊 Agent 协作,欢迎进 QQ 群:**Ai Native 交流群**(群号 `1098836554`)。
|
|
247
|
+
|
|
248
|
+
<p align="center">
|
|
249
|
+
<img src="./assets/qq-group.jpg" width="240" alt="Ai Native 交流群 QQ 群二维码,群号 1098836554" />
|
|
250
|
+
</p>
|
|
251
|
+
|
|
244
252
|
## 在路上:跨 Agent 的长时记忆
|
|
245
253
|
|
|
246
254
|
<p align="center">
|
|
Binary file
|
package/dist/bin/team.cmd
CHANGED
|
@@ -4,6 +4,63 @@ export interface RunUpdateResult {
|
|
|
4
4
|
spawnError?: Error;
|
|
5
5
|
}
|
|
6
6
|
export type RunUpdate = (command: string, args: readonly string[]) => Promise<RunUpdateResult>;
|
|
7
|
+
export interface SpawnInvocationPlan {
|
|
8
|
+
command: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
options: {
|
|
11
|
+
stdio: 'inherit';
|
|
12
|
+
windowsHide?: boolean;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Plan how `defaultRunUpdate` should hand the npm invocation to
|
|
17
|
+
* `child_process.spawn`. Two non-obvious cases collapse here.
|
|
18
|
+
*
|
|
19
|
+
* 1. Node 22+ refuses to spawn `.cmd` / `.bat` files directly after
|
|
20
|
+
* CVE-2024-27980 unless `shell: true` is passed. We do not want
|
|
21
|
+
* `shell: true` though — its arg-stringification path joins argv
|
|
22
|
+
* without quoting, so an install prefix containing spaces (the
|
|
23
|
+
* common Windows case `C:\Program Files\nodejs`) gets word-split
|
|
24
|
+
* by cmd.exe and `--prefix` only sees the first token, so npm
|
|
25
|
+
* silently installs hive to the wrong directory.
|
|
26
|
+
* 2. Wrapping with `cmd.exe /d /s /c <npm.cmd> <args>` solves both:
|
|
27
|
+
* spawning `cmd.exe` (a native exe) avoids the .cmd refusal, and
|
|
28
|
+
* Node's own argv-quoting builds an lpCommandLine where each
|
|
29
|
+
* space-containing arg is wrapped in double quotes that cmd.exe
|
|
30
|
+
* then re-parses correctly. `/d` skips AutoRun, `/s` keeps the
|
|
31
|
+
* quote-handling consistent with `/c`.
|
|
32
|
+
*
|
|
33
|
+
* Detect by filename suffix instead of `process.platform` so unit
|
|
34
|
+
* tests can inject `platform: 'win32'` and exercise the wrap.
|
|
35
|
+
*/
|
|
36
|
+
export declare const planSpawnInvocation: (command: string, args: readonly string[], platform?: NodeJS.Platform) => SpawnInvocationPlan;
|
|
37
|
+
/**
|
|
38
|
+
* Signals the upgrade child should receive when the parent runtime is
|
|
39
|
+
* interrupted. Beyond the POSIX-only SIGTERM/SIGINT, SIGHUP is what
|
|
40
|
+
* libuv synthesises from Windows CTRL_CLOSE_EVENT (window X close),
|
|
41
|
+
* and SIGBREAK comes from Windows Ctrl+Break. Without forwarding
|
|
42
|
+
* those two the npm child outlives the runtime on the most common
|
|
43
|
+
* Windows exit paths.
|
|
44
|
+
*/
|
|
45
|
+
export declare const FORWARDED_UPDATE_SIGNALS: readonly NodeJS.Signals[];
|
|
46
|
+
/**
|
|
47
|
+
* Forward a parent-process signal to the spawned npm child. On POSIX
|
|
48
|
+
* we hand the signal straight to the child; on Windows there are no
|
|
49
|
+
* real signals, so `child.kill(SIGTERM)` resolves to TerminateProcess
|
|
50
|
+
* against cmd.exe (our wrapper) only — npm itself, plus any install
|
|
51
|
+
* scripts it spawned, become orphans. `taskkill /pid <pid> /t /f`
|
|
52
|
+
* walks the wrapper's process tree so the whole branch dies together.
|
|
53
|
+
* If taskkill is unavailable (restricted PATH, locked-down policy)
|
|
54
|
+
* we fall back to `child.kill` so the wrapper at least exits.
|
|
55
|
+
*
|
|
56
|
+
* Exported so the win32 path can be unit-tested by injecting a stub
|
|
57
|
+
* `killTree` runner — the real `taskkillProcessTree` shells out, and
|
|
58
|
+
* we don't want that running during the test suite.
|
|
59
|
+
*/
|
|
60
|
+
export declare const killUpdateChild: (child: {
|
|
61
|
+
pid?: number | undefined;
|
|
62
|
+
kill: (signal: NodeJS.Signals) => boolean;
|
|
63
|
+
}, signal: NodeJS.Signals, platform?: NodeJS.Platform, killTree?: (pid: number, onFailure?: () => void) => boolean) => void;
|
|
7
64
|
export declare const defaultRunUpdate: RunUpdate;
|
|
8
65
|
export declare const resolveHiveUpdateInstallArgs: (moduleUrl?: string) => string[];
|
|
9
66
|
interface RunHiveUpdateOptions {
|
|
@@ -2,7 +2,9 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { basename, dirname, join } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { taskkillProcessTree } from '../server/agent-manager-support.js';
|
|
5
6
|
import { getNpmCommand, INSTALL_COMMAND_ARGS, INSTALL_COMMAND_DISPLAY, PACKAGE_NAME, } from '../server/package-version.js';
|
|
7
|
+
import { buildCmdCallCommand } from '../server/windows-command-line.js';
|
|
6
8
|
export const HIVE_UPDATE_USAGE = [
|
|
7
9
|
'Usage:',
|
|
8
10
|
' hive update',
|
|
@@ -19,27 +21,102 @@ export const HIVE_UPDATE_USAGE = [
|
|
|
19
21
|
'Options:',
|
|
20
22
|
' -h, --help Print this help.',
|
|
21
23
|
].join('\n');
|
|
24
|
+
/**
|
|
25
|
+
* Plan how `defaultRunUpdate` should hand the npm invocation to
|
|
26
|
+
* `child_process.spawn`. Two non-obvious cases collapse here.
|
|
27
|
+
*
|
|
28
|
+
* 1. Node 22+ refuses to spawn `.cmd` / `.bat` files directly after
|
|
29
|
+
* CVE-2024-27980 unless `shell: true` is passed. We do not want
|
|
30
|
+
* `shell: true` though — its arg-stringification path joins argv
|
|
31
|
+
* without quoting, so an install prefix containing spaces (the
|
|
32
|
+
* common Windows case `C:\Program Files\nodejs`) gets word-split
|
|
33
|
+
* by cmd.exe and `--prefix` only sees the first token, so npm
|
|
34
|
+
* silently installs hive to the wrong directory.
|
|
35
|
+
* 2. Wrapping with `cmd.exe /d /s /c <npm.cmd> <args>` solves both:
|
|
36
|
+
* spawning `cmd.exe` (a native exe) avoids the .cmd refusal, and
|
|
37
|
+
* Node's own argv-quoting builds an lpCommandLine where each
|
|
38
|
+
* space-containing arg is wrapped in double quotes that cmd.exe
|
|
39
|
+
* then re-parses correctly. `/d` skips AutoRun, `/s` keeps the
|
|
40
|
+
* quote-handling consistent with `/c`.
|
|
41
|
+
*
|
|
42
|
+
* Detect by filename suffix instead of `process.platform` so unit
|
|
43
|
+
* tests can inject `platform: 'win32'` and exercise the wrap.
|
|
44
|
+
*/
|
|
45
|
+
export const planSpawnInvocation = (command, args, platform = process.platform) => {
|
|
46
|
+
if (platform === 'win32' && /\.(cmd|bat)$/i.test(command)) {
|
|
47
|
+
return {
|
|
48
|
+
command: 'cmd.exe',
|
|
49
|
+
args: ['/d', '/s', '/c', buildCmdCallCommand(command, args)],
|
|
50
|
+
options: { stdio: 'inherit', windowsHide: false },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return { command, args: [...args], options: { stdio: 'inherit' } };
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Signals the upgrade child should receive when the parent runtime is
|
|
57
|
+
* interrupted. Beyond the POSIX-only SIGTERM/SIGINT, SIGHUP is what
|
|
58
|
+
* libuv synthesises from Windows CTRL_CLOSE_EVENT (window X close),
|
|
59
|
+
* and SIGBREAK comes from Windows Ctrl+Break. Without forwarding
|
|
60
|
+
* those two the npm child outlives the runtime on the most common
|
|
61
|
+
* Windows exit paths.
|
|
62
|
+
*/
|
|
63
|
+
export const FORWARDED_UPDATE_SIGNALS = [
|
|
64
|
+
'SIGINT',
|
|
65
|
+
'SIGTERM',
|
|
66
|
+
'SIGHUP',
|
|
67
|
+
'SIGBREAK',
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* Forward a parent-process signal to the spawned npm child. On POSIX
|
|
71
|
+
* we hand the signal straight to the child; on Windows there are no
|
|
72
|
+
* real signals, so `child.kill(SIGTERM)` resolves to TerminateProcess
|
|
73
|
+
* against cmd.exe (our wrapper) only — npm itself, plus any install
|
|
74
|
+
* scripts it spawned, become orphans. `taskkill /pid <pid> /t /f`
|
|
75
|
+
* walks the wrapper's process tree so the whole branch dies together.
|
|
76
|
+
* If taskkill is unavailable (restricted PATH, locked-down policy)
|
|
77
|
+
* we fall back to `child.kill` so the wrapper at least exits.
|
|
78
|
+
*
|
|
79
|
+
* Exported so the win32 path can be unit-tested by injecting a stub
|
|
80
|
+
* `killTree` runner — the real `taskkillProcessTree` shells out, and
|
|
81
|
+
* we don't want that running during the test suite.
|
|
82
|
+
*/
|
|
83
|
+
export const killUpdateChild = (child, signal, platform = process.platform, killTree = (pid, onFailure) => taskkillProcessTree(pid, platform, undefined, onFailure)) => {
|
|
84
|
+
const fallback = () => {
|
|
85
|
+
try {
|
|
86
|
+
child.kill(signal);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// child.kill on Windows throws if the signal name isn't
|
|
90
|
+
// implemented; we forward what we can and ignore the rest.
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
if (platform === 'win32' && typeof child.pid === 'number' && child.pid > 0) {
|
|
94
|
+
if (killTree(child.pid, fallback))
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
fallback();
|
|
98
|
+
};
|
|
22
99
|
export const defaultRunUpdate = (command, args) => new Promise((resolve) => {
|
|
23
|
-
const
|
|
100
|
+
const plan = planSpawnInvocation(command, args);
|
|
101
|
+
const child = spawn(plan.command, plan.args, plan.options);
|
|
24
102
|
let resolved = false;
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
process.once('SIGINT', handleSigint);
|
|
36
|
-
process.once('SIGTERM', handleSigterm);
|
|
103
|
+
// Handlers are registered with `once` so they don't accumulate
|
|
104
|
+
// across invocations and explicitly removed at finalize().
|
|
105
|
+
const handlers = new Map();
|
|
106
|
+
for (const signal of FORWARDED_UPDATE_SIGNALS) {
|
|
107
|
+
const handler = () => {
|
|
108
|
+
killUpdateChild(child, signal);
|
|
109
|
+
};
|
|
110
|
+
handlers.set(signal, handler);
|
|
111
|
+
process.once(signal, handler);
|
|
112
|
+
}
|
|
37
113
|
const finalize = (result) => {
|
|
38
114
|
if (resolved)
|
|
39
115
|
return;
|
|
40
116
|
resolved = true;
|
|
41
|
-
|
|
42
|
-
|
|
117
|
+
for (const [signal, handler] of handlers) {
|
|
118
|
+
process.off(signal, handler);
|
|
119
|
+
}
|
|
43
120
|
resolve(result);
|
|
44
121
|
};
|
|
45
122
|
child.on('error', (error) => {
|
package/dist/src/cli/hive.d.ts
CHANGED
|
@@ -9,7 +9,64 @@ interface RunHiveCommandResult {
|
|
|
9
9
|
type RunHiveCommandOptions = {
|
|
10
10
|
versionService?: VersionService;
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Signals that should drive a graceful shutdown. The interesting ones:
|
|
14
|
+
*
|
|
15
|
+
* SIGINT — Ctrl+C in the runtime terminal (all platforms).
|
|
16
|
+
* SIGTERM — `kill <pid>` on POSIX. Never delivered on Windows.
|
|
17
|
+
* SIGHUP — POSIX: parent shell exits. On Windows libuv synthesises
|
|
18
|
+
* SIGHUP from `CTRL_CLOSE_EVENT`, i.e. the user clicking
|
|
19
|
+
* the X on the runtime's cmd / Terminal window. Without
|
|
20
|
+
* this listener that close path skips the graceful path
|
|
21
|
+
* entirely on Windows.
|
|
22
|
+
* SIGBREAK — Windows: Ctrl+Break. Less common than Ctrl+C but kit
|
|
23
|
+
* scripts and CI hosts still send it.
|
|
24
|
+
*
|
|
25
|
+
* Stale agent_runs from a non-graceful exit are reconciled at next
|
|
26
|
+
* startup via `agentRunStore.markUnfinishedRunsStale()`
|
|
27
|
+
* (runtime-store-helpers.ts), so a dropped signal does not leave the
|
|
28
|
+
* database in an inconsistent state — only the PTY children miss the
|
|
29
|
+
* forwarded SIGTERM. On Windows there's no graceful equivalent for
|
|
30
|
+
* those children anyway (pty.kill is TerminateProcess), so this
|
|
31
|
+
* registration is mostly about giving SQLite a chance to checkpoint.
|
|
32
|
+
*/
|
|
33
|
+
export declare const SHUTDOWN_SIGNALS: readonly ["SIGINT", "SIGTERM", "SIGHUP", "SIGBREAK"];
|
|
12
34
|
export declare const HIVE_USAGE: string;
|
|
13
35
|
export declare const handleHiveInfoCommand: (argv: string[]) => boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the directory where Hive persists its SQLite DB and supporting
|
|
38
|
+
* state. Platform-aware because `~/.config/hive` is a hidden dot-directory
|
|
39
|
+
* convention that Windows Explorer treats as second-class — Windows users
|
|
40
|
+
* can't navigate there from the address bar without typing the full path,
|
|
41
|
+
* and the standard roaming-profile location is `%APPDATA%\<app>` instead.
|
|
42
|
+
*
|
|
43
|
+
* Resolution order:
|
|
44
|
+
* 1. HIVE_DATA_DIR override (any platform, for tests / opinionated users).
|
|
45
|
+
* 2. Windows: %APPDATA%\hive — roaming user state, follows the user
|
|
46
|
+
* across machines on a domain profile. APPDATA, not LOCALAPPDATA,
|
|
47
|
+
* because Hive's DB is user data, not a machine-local cache.
|
|
48
|
+
* Falls back to homedir()\AppData\Roaming\hive when APPDATA is
|
|
49
|
+
* stripped from the env (some Windows Task Scheduler configs do this).
|
|
50
|
+
* 3. POSIX: $XDG_CONFIG_HOME/hive, falling back to ~/.config/hive.
|
|
51
|
+
*
|
|
52
|
+
* Migration: pre-fix Windows installs wrote to ~/.config/hive. When that
|
|
53
|
+
* legacy directory exists but the new %APPDATA%\hive does not, prefer the
|
|
54
|
+
* legacy path so an upgrade does not surface as an empty workspace list.
|
|
55
|
+
* This is a one-way ratchet — once the new location is populated, it wins.
|
|
56
|
+
*
|
|
57
|
+
* Exported so the resolution rules are unit-testable without touching env
|
|
58
|
+
* or the real filesystem.
|
|
59
|
+
*/
|
|
60
|
+
export declare const resolveDataDir: (platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv, pathExists?: (path: string) => boolean) => string;
|
|
61
|
+
/**
|
|
62
|
+
* Recovery hint formatter for the "port already in use" error. Platform-aware
|
|
63
|
+
* because the lsof / xargs / kill pipeline is POSIX-only; on Windows a user
|
|
64
|
+
* pasting that command into cmd or PowerShell gets nothing useful. The
|
|
65
|
+
* Windows path swaps in `netstat -ano | findstr` + `taskkill /F /PID` which
|
|
66
|
+
* is the documented Microsoft workflow for the same problem.
|
|
67
|
+
*
|
|
68
|
+
* Exported for unit testing.
|
|
69
|
+
*/
|
|
70
|
+
export declare const formatPortInUseMessage: (port: number, platform?: NodeJS.Platform) => string;
|
|
14
71
|
export declare const runHiveCommand: (argv: string[], options?: RunHiveCommandOptions) => Promise<RunHiveCommandResult>;
|
|
15
72
|
export type { RunHiveCommandResult };
|
package/dist/src/cli/hive.js
CHANGED
|
@@ -1,15 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { once } from 'node:events';
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { createAgentManager } from '../server/agent-manager.js';
|
|
8
8
|
import { createApp } from '../server/app.js';
|
|
9
9
|
import { readPackageVersion } from '../server/package-version.js';
|
|
10
|
+
import { sameFilesystemPath } from '../server/path-canonicalization.js';
|
|
10
11
|
import { createRuntimeStore } from '../server/runtime-store.js';
|
|
11
12
|
import { createVersionService } from '../server/version-service.js';
|
|
12
13
|
import { runHiveUpdateCommand } from './hive-update.js';
|
|
14
|
+
/**
|
|
15
|
+
* Signals that should drive a graceful shutdown. The interesting ones:
|
|
16
|
+
*
|
|
17
|
+
* SIGINT — Ctrl+C in the runtime terminal (all platforms).
|
|
18
|
+
* SIGTERM — `kill <pid>` on POSIX. Never delivered on Windows.
|
|
19
|
+
* SIGHUP — POSIX: parent shell exits. On Windows libuv synthesises
|
|
20
|
+
* SIGHUP from `CTRL_CLOSE_EVENT`, i.e. the user clicking
|
|
21
|
+
* the X on the runtime's cmd / Terminal window. Without
|
|
22
|
+
* this listener that close path skips the graceful path
|
|
23
|
+
* entirely on Windows.
|
|
24
|
+
* SIGBREAK — Windows: Ctrl+Break. Less common than Ctrl+C but kit
|
|
25
|
+
* scripts and CI hosts still send it.
|
|
26
|
+
*
|
|
27
|
+
* Stale agent_runs from a non-graceful exit are reconciled at next
|
|
28
|
+
* startup via `agentRunStore.markUnfinishedRunsStale()`
|
|
29
|
+
* (runtime-store-helpers.ts), so a dropped signal does not leave the
|
|
30
|
+
* database in an inconsistent state — only the PTY children miss the
|
|
31
|
+
* forwarded SIGTERM. On Windows there's no graceful equivalent for
|
|
32
|
+
* those children anyway (pty.kill is TerminateProcess), so this
|
|
33
|
+
* registration is mostly about giving SQLite a chance to checkpoint.
|
|
34
|
+
*/
|
|
35
|
+
export const SHUTDOWN_SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGBREAK'];
|
|
13
36
|
export const HIVE_USAGE = [
|
|
14
37
|
'Usage:',
|
|
15
38
|
' hive [--port <port>]',
|
|
@@ -58,7 +81,44 @@ const parsePort = (argv) => {
|
|
|
58
81
|
}
|
|
59
82
|
return parsedPort ?? 3000;
|
|
60
83
|
};
|
|
61
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Resolve the directory where Hive persists its SQLite DB and supporting
|
|
86
|
+
* state. Platform-aware because `~/.config/hive` is a hidden dot-directory
|
|
87
|
+
* convention that Windows Explorer treats as second-class — Windows users
|
|
88
|
+
* can't navigate there from the address bar without typing the full path,
|
|
89
|
+
* and the standard roaming-profile location is `%APPDATA%\<app>` instead.
|
|
90
|
+
*
|
|
91
|
+
* Resolution order:
|
|
92
|
+
* 1. HIVE_DATA_DIR override (any platform, for tests / opinionated users).
|
|
93
|
+
* 2. Windows: %APPDATA%\hive — roaming user state, follows the user
|
|
94
|
+
* across machines on a domain profile. APPDATA, not LOCALAPPDATA,
|
|
95
|
+
* because Hive's DB is user data, not a machine-local cache.
|
|
96
|
+
* Falls back to homedir()\AppData\Roaming\hive when APPDATA is
|
|
97
|
+
* stripped from the env (some Windows Task Scheduler configs do this).
|
|
98
|
+
* 3. POSIX: $XDG_CONFIG_HOME/hive, falling back to ~/.config/hive.
|
|
99
|
+
*
|
|
100
|
+
* Migration: pre-fix Windows installs wrote to ~/.config/hive. When that
|
|
101
|
+
* legacy directory exists but the new %APPDATA%\hive does not, prefer the
|
|
102
|
+
* legacy path so an upgrade does not surface as an empty workspace list.
|
|
103
|
+
* This is a one-way ratchet — once the new location is populated, it wins.
|
|
104
|
+
*
|
|
105
|
+
* Exported so the resolution rules are unit-testable without touching env
|
|
106
|
+
* or the real filesystem.
|
|
107
|
+
*/
|
|
108
|
+
export const resolveDataDir = (platform = process.platform, env = process.env, pathExists = existsSync) => {
|
|
109
|
+
const override = env.HIVE_DATA_DIR;
|
|
110
|
+
if (override)
|
|
111
|
+
return override;
|
|
112
|
+
if (platform === 'win32') {
|
|
113
|
+
const appData = env.APPDATA ?? join(homedir(), 'AppData', 'Roaming');
|
|
114
|
+
const target = join(appData, 'hive');
|
|
115
|
+
const legacy = join(homedir(), '.config', 'hive');
|
|
116
|
+
if (!pathExists(target) && pathExists(legacy))
|
|
117
|
+
return legacy;
|
|
118
|
+
return target;
|
|
119
|
+
}
|
|
120
|
+
return join(env.XDG_CONFIG_HOME ?? join(homedir(), '.config'), 'hive');
|
|
121
|
+
};
|
|
62
122
|
const maybePrintUpdateHint = async (versionService) => {
|
|
63
123
|
const info = await versionService.getVersionInfo();
|
|
64
124
|
if (!info.update_available)
|
|
@@ -66,19 +126,39 @@ const maybePrintUpdateHint = async (versionService) => {
|
|
|
66
126
|
console.log(`Hive update available: ${info.current_version} -> ${info.latest_version}. Run: ${info.install_hint}`);
|
|
67
127
|
};
|
|
68
128
|
const isListenError = (error) => error instanceof Error && typeof error.code === 'string';
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Recovery hint formatter for the "port already in use" error. Platform-aware
|
|
131
|
+
* because the lsof / xargs / kill pipeline is POSIX-only; on Windows a user
|
|
132
|
+
* pasting that command into cmd or PowerShell gets nothing useful. The
|
|
133
|
+
* Windows path swaps in `netstat -ano | findstr` + `taskkill /F /PID` which
|
|
134
|
+
* is the documented Microsoft workflow for the same problem.
|
|
135
|
+
*
|
|
136
|
+
* Exported for unit testing.
|
|
137
|
+
*/
|
|
138
|
+
export const formatPortInUseMessage = (port, platform = process.platform) => {
|
|
139
|
+
const stopHint = platform === 'win32'
|
|
140
|
+
? [
|
|
141
|
+
' - Stop the process using that port:',
|
|
142
|
+
` netstat -ano | findstr ":${port}"`,
|
|
143
|
+
' taskkill /PID <pid> /F',
|
|
144
|
+
]
|
|
145
|
+
: [
|
|
146
|
+
' - Stop the process using that port:',
|
|
147
|
+
` lsof -tiTCP:${port} -sTCP:LISTEN | xargs kill`,
|
|
148
|
+
];
|
|
149
|
+
return [
|
|
150
|
+
`Hive could not start because port ${port} is already in use.`,
|
|
151
|
+
'',
|
|
152
|
+
'Another Hive instance may already be running:',
|
|
153
|
+
` http://127.0.0.1:${port}`,
|
|
154
|
+
'',
|
|
155
|
+
'Options:',
|
|
156
|
+
' - Open the existing Hive window.',
|
|
157
|
+
...stopHint,
|
|
158
|
+
' - Start Hive on another port:',
|
|
159
|
+
` hive --port ${port + 1}`,
|
|
160
|
+
].join('\n');
|
|
161
|
+
};
|
|
82
162
|
const formatListenError = (error, requestedPort) => {
|
|
83
163
|
if (isListenError(error) && error.code === 'EADDRINUSE') {
|
|
84
164
|
return new Error(formatPortInUseMessage(error.port ?? requestedPort));
|
|
@@ -119,8 +199,20 @@ export const runHiveCommand = async (argv, options = {}) => {
|
|
|
119
199
|
return closePromise;
|
|
120
200
|
}
|
|
121
201
|
closePromise = (async () => {
|
|
122
|
-
|
|
123
|
-
|
|
202
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
203
|
+
process.off(signal, gracefulShutdown);
|
|
204
|
+
}
|
|
205
|
+
// Tear down the WebSocket layer FIRST. `app.server.close()` waits
|
|
206
|
+
// on every existing socket, including upgraded WebSocket clients
|
|
207
|
+
// that never go idle on their own; `server.closeAllConnections()`
|
|
208
|
+
// alone does NOT terminate already-upgraded WS — only sockets
|
|
209
|
+
// still in the HTTP request/response state machine. The Windows
|
|
210
|
+
// symptom of skipping this step is Ctrl+C in the runtime cmd
|
|
211
|
+
// window hanging the process as long as any browser tab is
|
|
212
|
+
// connected to /ws/terminal/<runId> or /ws/tasks/<workspaceId>.
|
|
213
|
+
app.closeWebSockets();
|
|
214
|
+
// Then force-close any remaining plain-HTTP keep-alive sockets.
|
|
215
|
+
app.server.closeAllConnections();
|
|
124
216
|
await new Promise((resolve, reject) => {
|
|
125
217
|
app.server.close((error) => {
|
|
126
218
|
if (error) {
|
|
@@ -144,8 +236,9 @@ export const runHiveCommand = async (argv, options = {}) => {
|
|
|
144
236
|
process.exit(1);
|
|
145
237
|
});
|
|
146
238
|
};
|
|
147
|
-
|
|
148
|
-
|
|
239
|
+
for (const signal of SHUTDOWN_SIGNALS) {
|
|
240
|
+
process.once(signal, gracefulShutdown);
|
|
241
|
+
}
|
|
149
242
|
console.log(`Hive running at http://127.0.0.1:${address.port}`);
|
|
150
243
|
void maybePrintUpdateHint(versionService).catch(() => { });
|
|
151
244
|
return {
|
|
@@ -155,7 +248,7 @@ export const runHiveCommand = async (argv, options = {}) => {
|
|
|
155
248
|
};
|
|
156
249
|
};
|
|
157
250
|
const isMainModule = process.argv[1]
|
|
158
|
-
? fileURLToPath(import.meta.url)
|
|
251
|
+
? sameFilesystemPath(fileURLToPath(import.meta.url), process.argv[1])
|
|
159
252
|
: false;
|
|
160
253
|
if (isMainModule) {
|
|
161
254
|
const argv = process.argv.slice(2);
|
package/dist/src/cli/team.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface ParsedReportArgs {
|
|
|
10
10
|
}
|
|
11
11
|
export declare const parseReportArgs: (args: string[], command?: string) => ParsedReportArgs;
|
|
12
12
|
export declare const parseCancelArgs: (args: string[]) => ParsedCancelArgs;
|
|
13
|
+
export declare const decodeStdinBuffer: (buffer: Buffer) => string;
|
|
13
14
|
export declare const readStdinToString: (command?: string) => Promise<string>;
|
|
14
15
|
export declare const runTeamCommand: (argv: string[]) => Promise<void>;
|
|
15
16
|
export {};
|