@shanesaravia/hive 0.1.0 → 0.2.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 +28 -0
- package/README.md +67 -10
- package/dist/bin/hive.js +157 -0
- package/node_modules/@hive/shared/dist/directStudio.d.ts +7 -0
- package/node_modules/@hive/shared/dist/directStudio.js +17 -0
- package/node_modules/@hive/shared/dist/index.d.ts +1 -0
- package/node_modules/@hive/shared/dist/index.js +1 -0
- package/node_modules/@hive/shared/dist/status.d.ts +1 -1
- package/node_modules/@hive/shared/dist/status.js +19 -7
- package/node_modules/@hive/shared/dist/types.d.ts +5 -0
- package/node_modules/@hive/shared/package.json +3 -0
- package/package.json +1 -1
- package/packages/server/dist/api/rest.js +165 -14
- package/packages/server/dist/control/codexRuntime.js +24 -4
- package/packages/server/dist/hooks/hookIngest.js +44 -1
- package/packages/server/dist/missions/missionsStore.js +2 -0
- package/packages/server/dist/plans/plansStore.js +35 -4
- package/packages/server/dist/roster/rosterBuilder.js +183 -19
- package/packages/server/dist/skills/skillDiscovery.js +10 -8
- package/packages/server/dist/skills/skillInvocation.js +11 -0
- package/packages/web/dist/assets/index-BrkIk6ny.js +11 -0
- package/packages/web/dist/assets/index-DJFn_ZsI.css +2 -0
- package/packages/web/dist/index.html +2 -2
- package/templates/agents/hive-orchestrator.md +6 -0
- package/packages/web/dist/assets/index-CrKMFCkZ.js +0 -11
- package/packages/web/dist/assets/index-gEGU_lr3.css +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Hive will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.2.0 — 2026-08-25
|
|
6
|
+
|
|
7
|
+
Adds the visual office, a second presentation of the same fleet state alongside the existing cards.
|
|
8
|
+
|
|
9
|
+
### Highlights
|
|
10
|
+
|
|
11
|
+
- Global **Cards | Office** presentation switch, with both views reading one shared fleet snapshot
|
|
12
|
+
- Spatial headquarters with a shared Direct studio, per-mission orchestration rooms, a Review hall, hallways, and an elevator, plus deterministic overflow floors
|
|
13
|
+
- Stable, ID-derived room, desk, and avatar assignment that costs no model tokens
|
|
14
|
+
- Direct manipulation throughout: desks, managers, workers, rooms, and notices open the mission, worker, or tab they represent
|
|
15
|
+
- Mission details available in room view without leaving the office, with Conversation as the default panel
|
|
16
|
+
- Spatial search and filtering, dimming direct and review seats independently while orchestration missions filter by room
|
|
17
|
+
- Living office behavior for working, typing, thinking, idle, waiting, blocked, failed, reviewing, and paused states, with status-aware desks, monitors, and room lighting
|
|
18
|
+
- Manager and worker lifecycle movement — entrances, delegation, worker-to-manager handoffs, review transfers, and exits — ordered by per-identity FIFO transition queues
|
|
19
|
+
- Factual speech, ambient thought, alert, and output dialogue whose cadence scales with floor activity
|
|
20
|
+
- System, Reduced, and Full motion modes with configurable dialogue settings
|
|
21
|
+
- Guided mission launch and plan approval, refined mission controls, and live provider skill discovery
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Fleet and detail room views share transition state, so entering a room no longer replays a completed animation
|
|
26
|
+
- Room lighting, chat continuity, and startup transitions no longer flash stale state on arrival or reload
|
|
27
|
+
|
|
28
|
+
## 0.1.1 — 2026-08-23
|
|
29
|
+
|
|
30
|
+
- Add `hive update`, with read-only checks, interactive or unattended installation, setup refresh, and automatic restart of an active local server.
|
|
31
|
+
|
|
5
32
|
## 0.1.0 — 2026-08-23
|
|
6
33
|
|
|
7
34
|
Initial public preview of Hive, a provider-neutral local mission-control interface for Claude Code, Codex, and agent fleets.
|
|
@@ -14,4 +41,5 @@ Initial public preview of Hive, a provider-neutral local mission-control interfa
|
|
|
14
41
|
- Mission health, lifecycle, recovery, policies, budgets, templates, notifications, and searchable history
|
|
15
42
|
- Repository-aware working directories, skills, MCP configuration, and Git worktrees where supported
|
|
16
43
|
- Installable `hive` CLI with diagnostics, optional setup, persistent local state, and graceful lifecycle commands
|
|
44
|
+
- Browser-origin enforcement protecting the loopback control API and WebSocket from foreign websites
|
|
17
45
|
- Verified npm artifact across macOS and Ubuntu on Node.js 20 and 22
|
package/README.md
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
[](https://github.com/shanesaravia/hive/actions/workflows/release-verification.yml)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
### Cards dashboard
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
### Visual office
|
|
15
|
+
|
|
16
|
+

|
|
11
17
|
|
|
12
18
|
## What Hive is
|
|
13
19
|
|
|
@@ -33,6 +39,10 @@ Hive does not resell model access or replace provider authentication. It gives l
|
|
|
33
39
|
- Direct and orchestrated execution modes for either provider
|
|
34
40
|
- Per-mission Claude Code or Codex provider and model selection
|
|
35
41
|
- Provider model discovery from the locally installed CLIs
|
|
42
|
+
- Switchable **Cards** and deterministic 2.5D **Office** presentations backed by the same live mission state
|
|
43
|
+
- Multi-floor visual capacity with a shared direct studio, orchestration rooms, review hall, and off-floor arrival notices
|
|
44
|
+
- Clickable rooms, managers, workers, and direct desks with spatial mission drill-down
|
|
45
|
+
- Token-free avatar identity, entrances/exits, live posture, monitor state, room lighting, dialogue, and worker handoffs
|
|
36
46
|
- Structured phased plans, weighted progress, dependency graphs, revisions, and evidence
|
|
37
47
|
- Parallel worker visibility, assignments, elapsed time, activity, token usage, changed files, tests, and outputs
|
|
38
48
|
- Separate mission lifecycle and runtime activity states
|
|
@@ -41,6 +51,7 @@ Hive does not resell model access or replace provider authentication. It gives l
|
|
|
41
51
|
- User-controlled Pause, Resume, Complete, Reopen, Archive, manager handoff, task retry, cancellation, reassignment, and reprioritization
|
|
42
52
|
- Orchestrator-proposed **Awaiting acceptance** state
|
|
43
53
|
- Completion gates with verification evidence, explicit waivers, and user acceptance
|
|
54
|
+
- Optional **Plan first** workflow that requires approval before implementation and worker fan-out
|
|
44
55
|
- Reusable built-in, user, and repository mission templates with a visual editor
|
|
45
56
|
- Workspace and mission policies, permissions, worker/token/time budgets, and usage projections
|
|
46
57
|
- Semantic activity feed plus parallel manager/worker timeline
|
|
@@ -120,12 +131,23 @@ Useful commands:
|
|
|
120
131
|
| `hive status` | Report whether Hive is running and its local address. |
|
|
121
132
|
| `hive open` | Open an already-running dashboard. |
|
|
122
133
|
| `hive stop` | Gracefully stop Hive. |
|
|
134
|
+
| `hive update --check` | Check npm for a newer Hive release without changing anything. |
|
|
135
|
+
| `hive update` | Confirm and install the latest release, refreshing setup and restarting Hive when needed. |
|
|
136
|
+
| `hive update --yes` | Install the latest release without an interactive confirmation. |
|
|
123
137
|
| `hive --version` | Show the installed version. |
|
|
124
138
|
|
|
125
139
|
## Update or uninstall
|
|
126
140
|
|
|
127
141
|
Update to the newest release:
|
|
128
142
|
|
|
143
|
+
```bash
|
|
144
|
+
hive update
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Use `hive update --check` for a read-only version check or `hive update --yes` to skip confirmation. If Hive is running, the updater stops it gracefully and restarts it on the same port after installation. It also refreshes Hive's additive provider setup. Mission history and configuration remain in the platform data directory.
|
|
148
|
+
|
|
149
|
+
You can still update directly through npm if the installed Hive command is unavailable:
|
|
150
|
+
|
|
129
151
|
```bash
|
|
130
152
|
npm install --global @shanesaravia/hive@latest
|
|
131
153
|
```
|
|
@@ -140,13 +162,18 @@ Uninstalling the npm package intentionally retains mission history, configuratio
|
|
|
140
162
|
|
|
141
163
|
## Create a mission
|
|
142
164
|
|
|
165
|
+
For a focused direct task, the fleet's quick-start bar provides provider and model selectors and uses worktree isolation when the selected Claude repository supports it. If the task needs parallel workers, switch to orchestrated setup; Hive carries the entered prompt into the full **New mission** flow with the cursor preserved at the end.
|
|
166
|
+
|
|
167
|
+
Use **New mission** when you want the full configuration:
|
|
168
|
+
|
|
143
169
|
1. Select **New mission**.
|
|
144
170
|
2. Enter the intended working directory. Absolute paths and paths beginning with `~` are supported; matching local folders appear as you type.
|
|
145
171
|
3. Choose **Claude** or **Codex**, then optionally select a model. Leaving model blank uses that CLI's configured default.
|
|
146
172
|
4. Choose **Direct** or **Orchestrated** mode.
|
|
147
173
|
5. Describe the task and optionally provide a mission name.
|
|
148
|
-
6.
|
|
149
|
-
7.
|
|
174
|
+
6. Configure launch behavior: Claude worktree isolation, optional **Plan first** approval for orchestrated missions, and any template.
|
|
175
|
+
7. Expand **Advanced settings** when the mission needs policy overrides or worker, concurrency, token, or time budgets.
|
|
176
|
+
8. Start the mission. You can follow it from either the Cards dashboard or visual Office without changing its underlying state.
|
|
150
177
|
|
|
151
178
|
The selected working directory matters. The provider CLI is launched from that directory so it can resolve the same repository instructions, configuration, MCP servers, and skills it would see when launched manually there.
|
|
152
179
|
|
|
@@ -154,7 +181,9 @@ The selected working directory matters. The provider CLI is launched from that d
|
|
|
154
181
|
|
|
155
182
|
Open a mission card and send a follow-up from the Conversation panel. Both providers preserve their native conversation/thread identity while Hive records each turn under the same durable mission.
|
|
156
183
|
|
|
157
|
-
|
|
184
|
+
Type `/` in either the new-mission prompt or an existing conversation to search the skills available to that provider in the selected working directory. Hive reads Claude skills for Claude missions and Codex skills for Codex missions; slash-form Codex selections are translated to the provider's native invocation form behind the scenes. Recognized skills are highlighted and sent as ordinary prompt text, leaving the provider CLI responsible for execution and permissions. Hive discovers skill metadata only; it does not preload entire skill bodies into mission context.
|
|
185
|
+
|
|
186
|
+
If a provider or deliberately interactive skill asks a structured question, Hive surfaces it in **Needs you** and the mission conversation. Answering there resumes the same mission; skill prompts are not silently bypassed.
|
|
158
187
|
|
|
159
188
|
## Navigate the fleet
|
|
160
189
|
|
|
@@ -166,19 +195,38 @@ The fleet is organized around attention rather than process creation time:
|
|
|
166
195
|
|
|
167
196
|
Search covers mission names, conversations, plans, workers, files, errors, decisions, evidence, and outputs. Filters are available for lifecycle/activity status, repository, template, and date. Claude sessions started outside Hive appear separately as discovered local sessions; they can be adopted, stopped, or hidden without pretending they are already durable Hive missions.
|
|
168
197
|
|
|
198
|
+
### Use the visual office
|
|
199
|
+
|
|
200
|
+
Use the global **Cards | Office** control to switch presentation. The choice is remembered locally and follows you into mission details, so the visual workflow does not unexpectedly send you back to the data dashboard.
|
|
201
|
+
|
|
202
|
+
The office is a second presentation of the same mission data, not a simulation or separate runtime:
|
|
203
|
+
|
|
204
|
+
- A desk in the shared **Direct studio** represents one direct mission. Select a desk to open that mission, or select the studio itself for its aggregate worker list and bulk **Clear completed desks** action.
|
|
205
|
+
- An **orchestration room** represents one orchestrated mission. The manager has a distinct position and appearance; each active worker receives a stable desk and can be opened directly.
|
|
206
|
+
- Managers move to the shared **Review hall** when their missions reach **Awaiting acceptance**. Selecting an occupant opens the corresponding mission.
|
|
207
|
+
- Headquarters contains the direct studio, orchestration rooms, and review hall. Additional operations floors are allocated deterministically when orchestration capacity fills; off-floor arrivals are called out without pulling you away from the floor you are viewing.
|
|
208
|
+
- Search and filters dim nonmatching rooms or individual direct/review seats while retaining spatial context.
|
|
209
|
+
|
|
210
|
+
Room plaques and avatar/desk hover states expose mission identity. Room lighting, desk accents, monitor symbols, postures, and bubbles communicate observed activity, waiting, failure, review, and occupancy. Entrances, exits, elevator travel, and worker-to-manager handoffs are driven by a local FIFO presentation queue so backend events remain ordered and do not spend model tokens.
|
|
211
|
+
|
|
212
|
+
Office controls let you follow the operating-system motion preference or explicitly reduce/enable motion, and choose how much work/personality dialogue appears. Dialogue cadence scales with floor occupancy to keep quiet floors alive without covering the workspace in bubbles.
|
|
213
|
+
|
|
169
214
|
## Understand a mission
|
|
170
215
|
|
|
171
|
-
Each mission has
|
|
216
|
+
Each mission has five primary views in the standard details presentation. The spatial room presentation exposes the same controls and panels beside the room, with **Conversation** selected by default:
|
|
172
217
|
|
|
173
218
|
| View | What it shows |
|
|
174
219
|
| --- | --- |
|
|
175
220
|
| Conversation | The durable user/orchestrator thread across all provider turns |
|
|
176
|
-
| Plan
|
|
221
|
+
| Plan | Goal, current work, next work, blockers, phased plan, dependencies, gates, evidence, and weighted progress |
|
|
222
|
+
| Workers | Manager/worker roster, assignments, runtime state, timing, tools, files, outputs, and worker controls |
|
|
177
223
|
| Activity | A semantic event feed or parallel timeline for the manager and workers |
|
|
178
224
|
| Technical | Provider job history, bounded handoff context, policies, and mission-report export |
|
|
179
225
|
|
|
180
226
|
Worker rows open a detail drawer containing the assignment, role, current tool/command, files read or changed, tests, artifacts, timing, tokens, termination state, and task-specific controls. Runtime job IDs remain available for diagnosis without becoming the mission's product identity.
|
|
181
227
|
|
|
228
|
+
Mission names can be edited from either presentation. Renaming changes Hive's durable mission label without pretending to rename an already-running provider job or breaking the underlying conversation.
|
|
229
|
+
|
|
182
230
|
## Plans, progress, and dependencies
|
|
183
231
|
|
|
184
232
|
For non-trivial work, orchestrators publish a structured plan with phases, milestones, tasks, optional subtasks, dependencies, owners, weights, blockers, acceptance criteria, and evidence. Hive then derives progress from completed task weights rather than asking an LLM to estimate a percentage.
|
|
@@ -193,7 +241,7 @@ The plan begins with:
|
|
|
193
241
|
|
|
194
242
|
Use **Plan** for the readable phased workflow and **Dependencies** for the interactive work graph and critical path. Completed and future phases collapse by default, task operational details are expandable, and dependency IDs are translated into task names.
|
|
195
243
|
|
|
196
|
-
|
|
244
|
+
Enable **Plan first** when creating an orchestrated mission to require a pre-implementation checkpoint. The manager publishes the proposal and waits; approving it from the Plan view or global decision inbox records the same decision and resumes implementation. Requesting changes returns feedback to the manager. Missions created without this option remain autonomous, and stale approval controls disappear once implementation starts. Plan approval is separate from accepting a completed mission.
|
|
197
245
|
|
|
198
246
|
## Completion and acceptance
|
|
199
247
|
|
|
@@ -280,7 +328,10 @@ Orchestrated managers cannot directly edit files: Hive launches them with `Edit`
|
|
|
280
328
|
|
|
281
329
|
```text
|
|
282
330
|
Browser UI (React + Vite)
|
|
283
|
-
│
|
|
331
|
+
│
|
|
332
|
+
├── Cards dashboard
|
|
333
|
+
├── deterministic SVG visual office
|
|
334
|
+
└── REST + WebSocket
|
|
284
335
|
Hive server (Fastify)
|
|
285
336
|
│
|
|
286
337
|
├── adapts Claude and Codex runtime state into provider-neutral turns
|
|
@@ -358,7 +409,11 @@ npm run hive -- serve
|
|
|
358
409
|
npm run hive -- orchestrator start "<task>" [--worktree] [--name <name>]
|
|
359
410
|
```
|
|
360
411
|
|
|
361
|
-
|
|
412
|
+
Project planning is split by scope:
|
|
413
|
+
|
|
414
|
+
- [`docs/IMPROVEMENTS.md`](docs/IMPROVEMENTS.md) — core product roadmap and completion checklist
|
|
415
|
+
- [`docs/VISUAL_OFFICE_PLAN.md`](docs/VISUAL_OFFICE_PLAN.md) — completed visual-office foundation
|
|
416
|
+
- [`docs/VISUAL_OFFICE_FEEL_ALIVE_PLAN.md`](docs/VISUAL_OFFICE_FEEL_ALIVE_PLAN.md) — current and upcoming atmosphere, interaction, and polish phases
|
|
362
417
|
|
|
363
418
|
## Troubleshooting
|
|
364
419
|
|
|
@@ -396,7 +451,7 @@ This means the mission remains unfinished while Hive sees no meaningful runtime
|
|
|
396
451
|
|
|
397
452
|
### Accept & complete says completion gates remain
|
|
398
453
|
|
|
399
|
-
Open **Plan
|
|
454
|
+
Open **Plan** and inspect Completion gates. Tests, CI, review, documentation, and other technical gates must be satisfied or waived with a reason. A pending user-approval gate is satisfied automatically by **Accept & complete** and should not block that action.
|
|
400
455
|
|
|
401
456
|
### Data after a restart
|
|
402
457
|
|
|
@@ -408,6 +463,8 @@ Restart Hive with `hive`, then reopen the same mission card. Hive reloads durabl
|
|
|
408
463
|
- Codex uses its workspace-write sandbox in the selected repository; Hive-created Codex worktrees are not yet available.
|
|
409
464
|
- Claude hooks provide richer tool-level evidence than providers or workers that do not emit equivalent structured events.
|
|
410
465
|
- Policies and budgets combine launch-time enforcement with orchestrator guidance; they are not a substitute for operating-system isolation.
|
|
466
|
+
- The visual office is a deterministic status presentation, not a claim that agents are physically active; snapshot state remains authoritative and animation yields to accessibility preferences.
|
|
467
|
+
- Mission artifacts, shared hallway events beyond lifecycle/handoffs, an activity ticker, ambient sound, and celebrations remain planned visual-office polish rather than current functionality.
|
|
411
468
|
- Optional multi-mission initiatives remain intentionally deferred. A mission is the primary durable unit of work.
|
|
412
469
|
|
|
413
470
|
## Project status
|
package/dist/bin/hive.js
CHANGED
|
@@ -3,6 +3,7 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { createInterface } from "node:readline/promises";
|
|
6
7
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
8
|
const currentFile = fileURLToPath(import.meta.url);
|
|
8
9
|
const sourceMode = currentFile.endsWith(".ts");
|
|
@@ -132,6 +133,42 @@ export function parseStartOptions(args) {
|
|
|
132
133
|
}
|
|
133
134
|
return { port, open };
|
|
134
135
|
}
|
|
136
|
+
export function parseUpdateOptions(args) {
|
|
137
|
+
const options = { check: false, assumeYes: false };
|
|
138
|
+
for (const arg of args) {
|
|
139
|
+
if (arg === "--check")
|
|
140
|
+
options.check = true;
|
|
141
|
+
else if (arg === "--yes")
|
|
142
|
+
options.assumeYes = true;
|
|
143
|
+
else
|
|
144
|
+
throw new Error(`Unknown update option: ${arg}`);
|
|
145
|
+
}
|
|
146
|
+
if (options.check && options.assumeYes) {
|
|
147
|
+
throw new Error("Use either `hive update --check` or `hive update --yes`, not both.");
|
|
148
|
+
}
|
|
149
|
+
return options;
|
|
150
|
+
}
|
|
151
|
+
export function compareVersions(left, right) {
|
|
152
|
+
const parse = (value) => {
|
|
153
|
+
const match = value.trim().replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?/);
|
|
154
|
+
if (!match)
|
|
155
|
+
throw new Error(`Invalid package version: ${value}`);
|
|
156
|
+
return { numbers: match.slice(1, 4).map(Number), prerelease: match[4] };
|
|
157
|
+
};
|
|
158
|
+
const a = parse(left);
|
|
159
|
+
const b = parse(right);
|
|
160
|
+
for (let index = 0; index < a.numbers.length; index++) {
|
|
161
|
+
if (a.numbers[index] !== b.numbers[index])
|
|
162
|
+
return a.numbers[index] < b.numbers[index] ? -1 : 1;
|
|
163
|
+
}
|
|
164
|
+
if (a.prerelease === b.prerelease)
|
|
165
|
+
return 0;
|
|
166
|
+
if (!a.prerelease)
|
|
167
|
+
return 1;
|
|
168
|
+
if (!b.prerelease)
|
|
169
|
+
return -1;
|
|
170
|
+
return a.prerelease.localeCompare(b.prerelease);
|
|
171
|
+
}
|
|
135
172
|
function readRuntimeState() {
|
|
136
173
|
try {
|
|
137
174
|
const state = JSON.parse(fs.readFileSync(runtimePath(), "utf8"));
|
|
@@ -352,6 +389,124 @@ async function runStop() {
|
|
|
352
389
|
clearRuntimeState(state.pid);
|
|
353
390
|
console.log("Hive stopped.");
|
|
354
391
|
}
|
|
392
|
+
function npmExecutable() {
|
|
393
|
+
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
394
|
+
}
|
|
395
|
+
function latestPackageVersion() {
|
|
396
|
+
const result = spawnSync(npmExecutable(), ["view", "@shanesaravia/hive@latest", "version", "--json"], {
|
|
397
|
+
encoding: "utf8",
|
|
398
|
+
timeout: 30_000,
|
|
399
|
+
});
|
|
400
|
+
if (result.error || result.status !== 0) {
|
|
401
|
+
const detail = result.error?.message ?? result.stderr.trim() ?? "npm registry request failed";
|
|
402
|
+
throw new Error(`Could not check for Hive updates: ${detail}`);
|
|
403
|
+
}
|
|
404
|
+
const output = result.stdout.trim();
|
|
405
|
+
try {
|
|
406
|
+
const parsed = JSON.parse(output);
|
|
407
|
+
if (typeof parsed === "string")
|
|
408
|
+
return parsed;
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
if (output)
|
|
412
|
+
return output;
|
|
413
|
+
}
|
|
414
|
+
throw new Error("Could not read the latest Hive version from npm.");
|
|
415
|
+
}
|
|
416
|
+
async function confirmUpdate(current, latest) {
|
|
417
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
418
|
+
throw new Error("Confirmation requires an interactive terminal. Re-run with `hive update --yes`.");
|
|
419
|
+
}
|
|
420
|
+
const prompt = createInterface({ input: process.stdin, output: process.stdout });
|
|
421
|
+
try {
|
|
422
|
+
const answer = await prompt.question(`Update Hive ${current} → ${latest}? [y/N] `);
|
|
423
|
+
return /^(y|yes)$/i.test(answer.trim());
|
|
424
|
+
}
|
|
425
|
+
finally {
|
|
426
|
+
prompt.close();
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
async function waitForRuntime(port, timeoutMs = 12_000) {
|
|
430
|
+
const deadline = Date.now() + timeoutMs;
|
|
431
|
+
while (Date.now() < deadline) {
|
|
432
|
+
if (await health(port))
|
|
433
|
+
return;
|
|
434
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
435
|
+
}
|
|
436
|
+
throw new Error(`Hive did not restart on port ${port} within ${timeoutMs / 1000} seconds.`);
|
|
437
|
+
}
|
|
438
|
+
async function relaunchUpdatedHive(port) {
|
|
439
|
+
const child = spawn(process.execPath, [currentFile, "start", "--port", String(port), "--no-open"], {
|
|
440
|
+
detached: true,
|
|
441
|
+
stdio: "ignore",
|
|
442
|
+
});
|
|
443
|
+
child.unref();
|
|
444
|
+
await waitForRuntime(port);
|
|
445
|
+
console.log(`Hive restarted at http://127.0.0.1:${port}`);
|
|
446
|
+
}
|
|
447
|
+
async function runUpdate(args) {
|
|
448
|
+
const options = parseUpdateOptions(args);
|
|
449
|
+
if (sourceMode) {
|
|
450
|
+
throw new Error("`hive update` is only available from the globally installed CLI. Update a source checkout with Git instead.");
|
|
451
|
+
}
|
|
452
|
+
const current = packageVersion();
|
|
453
|
+
const latest = latestPackageVersion();
|
|
454
|
+
const comparison = compareVersions(current, latest);
|
|
455
|
+
if (comparison >= 0) {
|
|
456
|
+
console.log(comparison === 0
|
|
457
|
+
? `Hive ${current} is already the latest version.`
|
|
458
|
+
: `Hive ${current} is newer than the npm latest version (${latest}).`);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
console.log(`Hive ${latest} is available (installed: ${current}).`);
|
|
462
|
+
if (options.check)
|
|
463
|
+
return;
|
|
464
|
+
if (!options.assumeYes && !(await confirmUpdate(current, latest))) {
|
|
465
|
+
console.log("Update cancelled.");
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const state = readRuntimeState();
|
|
469
|
+
const wasRunning = Boolean(state && processExists(state.pid));
|
|
470
|
+
const restartPort = state?.port ?? defaultPort;
|
|
471
|
+
if (wasRunning)
|
|
472
|
+
await runStop();
|
|
473
|
+
let updateError;
|
|
474
|
+
try {
|
|
475
|
+
const install = spawnSync(npmExecutable(), ["install", "--global", "@shanesaravia/hive@latest"], { stdio: "inherit" });
|
|
476
|
+
if (install.error || install.status !== 0) {
|
|
477
|
+
throw new Error(install.error?.message ?? `npm install exited with code ${install.status ?? "unknown"}`);
|
|
478
|
+
}
|
|
479
|
+
const installed = spawnSync(process.execPath, [currentFile, "--version"], { encoding: "utf8" });
|
|
480
|
+
if (installed.error || installed.status !== 0) {
|
|
481
|
+
throw new Error("Hive was installed, but the updated CLI could not be verified.");
|
|
482
|
+
}
|
|
483
|
+
const installedVersion = installed.stdout.trim();
|
|
484
|
+
if (compareVersions(installedVersion, latest) < 0) {
|
|
485
|
+
throw new Error(`npm completed, but Hive ${installedVersion} is still installed; expected ${latest}.`);
|
|
486
|
+
}
|
|
487
|
+
const setup = spawnSync(process.execPath, [currentFile, "setup", "--yes"], { stdio: "inherit" });
|
|
488
|
+
if (setup.error || setup.status !== 0) {
|
|
489
|
+
throw new Error("Hive updated, but provider setup could not be refreshed. Run `hive setup --yes` manually.");
|
|
490
|
+
}
|
|
491
|
+
console.log(`Hive updated successfully: ${current} → ${installedVersion}`);
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
updateError = error;
|
|
495
|
+
}
|
|
496
|
+
if (wasRunning) {
|
|
497
|
+
try {
|
|
498
|
+
await relaunchUpdatedHive(restartPort);
|
|
499
|
+
}
|
|
500
|
+
catch (restartError) {
|
|
501
|
+
if (updateError) {
|
|
502
|
+
throw new Error(`${updateError.message} Hive also failed to restart: ${restartError.message}`);
|
|
503
|
+
}
|
|
504
|
+
throw restartError;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (updateError)
|
|
508
|
+
throw updateError;
|
|
509
|
+
}
|
|
355
510
|
function commandVersion(command) {
|
|
356
511
|
const result = spawnSync(command, ["--version"], { encoding: "utf8", timeout: 3_000 });
|
|
357
512
|
if (result.error || result.status !== 0)
|
|
@@ -453,6 +608,7 @@ Usage:
|
|
|
453
608
|
hive status Show whether Hive is running
|
|
454
609
|
hive open Open the running dashboard
|
|
455
610
|
hive stop Gracefully stop a recorded Hive server
|
|
611
|
+
hive update [--check] [--yes] Check for or install the latest release
|
|
456
612
|
hive --version Print the installed version
|
|
457
613
|
hive --help Show this help
|
|
458
614
|
|
|
@@ -471,6 +627,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
471
627
|
case "status": return runStatus();
|
|
472
628
|
case "open": return runOpen();
|
|
473
629
|
case "stop": return runStop();
|
|
630
|
+
case "update": return runUpdate(args);
|
|
474
631
|
case "--version":
|
|
475
632
|
case "-v":
|
|
476
633
|
console.log(packageVersion());
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { OrchestratorNode } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A deliberately conservative definition of an idle Direct Studio desk.
|
|
4
|
+
* Bulk cleanup must never accept gates or dismiss a mission that still needs
|
|
5
|
+
* work or user attention.
|
|
6
|
+
*/
|
|
7
|
+
export declare function canClearDirectStudioMission(node: OrchestratorNode): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const CLEARABLE_ACTIVITY = new Set(["idle", "done", "offline"]);
|
|
2
|
+
/**
|
|
3
|
+
* A deliberately conservative definition of an idle Direct Studio desk.
|
|
4
|
+
* Bulk cleanup must never accept gates or dismiss a mission that still needs
|
|
5
|
+
* work or user attention.
|
|
6
|
+
*/
|
|
7
|
+
export function canClearDirectStudioMission(node) {
|
|
8
|
+
if (node.mission.mode !== "direct" || node.lifecycleStatus !== "active")
|
|
9
|
+
return false;
|
|
10
|
+
if (!CLEARABLE_ACTIVITY.has(node.activityStatus) || node.inFlight.tasks > 0 || node.inFlight.queued > 0)
|
|
11
|
+
return false;
|
|
12
|
+
if (node.workers.some((worker) => !worker.doneAt && (worker.jobState === "working" || worker.jobState === "busy")))
|
|
13
|
+
return false;
|
|
14
|
+
if (node.alerts.length > 0)
|
|
15
|
+
return false;
|
|
16
|
+
return !(node.plan?.gates ?? []).some((gate) => gate.required && gate.status !== "satisfied" && gate.status !== "waived");
|
|
17
|
+
}
|
|
@@ -6,7 +6,7 @@ import type { ClaudeJob, ClaudeSession, DerivedStatus, HiveEvent } from "./types
|
|
|
6
6
|
* since that's the one case pure file-watching can otherwise miss (the
|
|
7
7
|
* process died without a clean shutdown).
|
|
8
8
|
*/
|
|
9
|
-
export declare function deriveStatus(session: ClaudeSession | undefined, job: ClaudeJob | undefined, recentEvents?: HiveEvent[]): {
|
|
9
|
+
export declare function deriveStatus(session: ClaudeSession | undefined, job: ClaudeJob | undefined, recentEvents?: HiveEvent[], now?: number): {
|
|
10
10
|
status: DerivedStatus;
|
|
11
11
|
stale: boolean;
|
|
12
12
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const STALE_JOB_STATES = new Set(["working", "busy"]);
|
|
2
|
+
const JOB_SESSION_STARTUP_GRACE_MS = 15_000;
|
|
2
3
|
/**
|
|
3
4
|
* Pure status derivation — no network/LLM calls. Joins the raw session/job
|
|
4
5
|
* records already on disk. A job still marked "working" with no matching
|
|
@@ -6,7 +7,7 @@ const STALE_JOB_STATES = new Set(["working", "busy"]);
|
|
|
6
7
|
* since that's the one case pure file-watching can otherwise miss (the
|
|
7
8
|
* process died without a clean shutdown).
|
|
8
9
|
*/
|
|
9
|
-
export function deriveStatus(session, job, recentEvents = []) {
|
|
10
|
+
export function deriveStatus(session, job, recentEvents = [], now = Date.now()) {
|
|
10
11
|
// The daemon's idle notification ("Claude is waiting for your input") fires
|
|
11
12
|
// after every completed turn — it means "session idle", not "the assistant
|
|
12
13
|
// asked you something", so it must not read as waiting_on_you. Permission
|
|
@@ -21,6 +22,14 @@ export function deriveStatus(session, job, recentEvents = []) {
|
|
|
21
22
|
const latestEventTs = recentEvents.at(-1)?.ts ?? 0;
|
|
22
23
|
const blockedEventIsCurrent = blockedEvent !== undefined && blockedEvent.ts >= latestEventTs;
|
|
23
24
|
if (!session && job && STALE_JOB_STATES.has(job.state)) {
|
|
25
|
+
// Claude publishes a resumed background job before its matching live
|
|
26
|
+
// session record. Keep that normal startup gap in "working" instead of
|
|
27
|
+
// briefly presenting a failed mission. Truly orphaned jobs still become
|
|
28
|
+
// stale errors when this short grace period expires.
|
|
29
|
+
const createdAt = job.createdAt ? Date.parse(job.createdAt) : NaN;
|
|
30
|
+
if (Number.isFinite(createdAt) && Math.max(0, now - createdAt) < JOB_SESSION_STARTUP_GRACE_MS) {
|
|
31
|
+
return { status: "working", stale: false };
|
|
32
|
+
}
|
|
24
33
|
return { status: "error", stale: true };
|
|
25
34
|
}
|
|
26
35
|
if (!session) {
|
|
@@ -29,12 +38,15 @@ export function deriveStatus(session, job, recentEvents = []) {
|
|
|
29
38
|
if (session.status === "waiting") {
|
|
30
39
|
return { status: "waiting_on_you", stale: false };
|
|
31
40
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
41
|
+
// Claude also labels conversational closing questions such as "Anything
|
|
42
|
+
// else?" as blocked. Those are completed, optional follow-up turns—not
|
|
43
|
+
// actionable decisions. Treat the provider block as authoritative only
|
|
44
|
+
// when it carries a permission ask, explicit choices, or a current
|
|
45
|
+
// structured blocked_on_user event.
|
|
46
|
+
const actionableProviderBlock = Boolean(job?.needs && (/^approve\s/i.test(job.needs)
|
|
47
|
+
|| (job.promptChoices?.length ?? 0) > 0
|
|
48
|
+
|| blockedEventIsCurrent));
|
|
49
|
+
if ((job?.state === "blocked" || job?.tempo === "blocked") && actionableProviderBlock) {
|
|
38
50
|
return { status: "waiting_on_you", stale: false };
|
|
39
51
|
}
|
|
40
52
|
// A busy session outranks event-inferred waiting: the runtime is provably
|
|
@@ -48,6 +48,8 @@ export interface ClaudeJob {
|
|
|
48
48
|
fan: JobFanEntry[];
|
|
49
49
|
tokens?: number;
|
|
50
50
|
needs?: string;
|
|
51
|
+
/** Structured choices for a provider prompt parked by Hive. */
|
|
52
|
+
promptChoices?: string[];
|
|
51
53
|
output?: unknown;
|
|
52
54
|
/**
|
|
53
55
|
* Hive-augmented (not part of the daemon's state.json): the latest assistant
|
|
@@ -105,6 +107,8 @@ export interface MissionSummary {
|
|
|
105
107
|
policy?: MissionPolicy;
|
|
106
108
|
provider?: MissionProvider;
|
|
107
109
|
model?: string;
|
|
110
|
+
/** Require explicit user approval of the proposed plan before implementation or worker delegation begins. */
|
|
111
|
+
planFirst?: boolean;
|
|
108
112
|
/** Repositories beyond the working directory this mission also touches; each grants --add-dir access on every turn. */
|
|
109
113
|
additionalRepositories?: string[];
|
|
110
114
|
}
|
|
@@ -230,6 +234,7 @@ export interface CompletionGate {
|
|
|
230
234
|
status: CompletionGateStatus;
|
|
231
235
|
required: boolean;
|
|
232
236
|
evidence: string[];
|
|
237
|
+
source?: "orchestrator" | "template" | "user";
|
|
233
238
|
waiver?: {
|
|
234
239
|
reason: string;
|
|
235
240
|
waivedAt: number;
|
package/package.json
CHANGED