@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 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
  [![Release verification](https://github.com/shanesaravia/hive/actions/workflows/release-verification.yml/badge.svg)](https://github.com/shanesaravia/hive/actions/workflows/release-verification.yml)
9
9
 
10
- ![Hive fleet dashboard showing provider-tagged missions, live status, worker counts, token usage, health alerts, search, and filters](docs/assets/hive-fleet-dashboard.png)
10
+ ### Cards dashboard
11
+
12
+ ![Hive Cards dashboard showing provider-tagged missions, direct mission controls, live status, worker counts, token usage, search, and filters](docs/assets/hive-cards-dashboard.png)
13
+
14
+ ### Visual office
15
+
16
+ ![Hive Visual Office showing the shared direct studio, orchestration rooms, managers, workers, review hall, elevator, and live room state](docs/assets/hive-visual-office.png)
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. For Claude missions, choose whether to work in a new Git worktree. Codex missions currently use Codex's workspace-write sandbox in the selected repository; Hive-created Codex worktrees are not yet available.
149
- 7. Start the mission and open its card to follow progress or continue the conversation.
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
- For Claude missions, type `/` in either the new-mission prompt or an existing conversation to search registered project, user, plugin, and built-in skills. Recognized skills are highlighted and sent as ordinary prompt text, leaving Claude Code responsible for skill execution and permissions. Hive discovers skill metadata only; it does not preload entire skill bodies into mission context.
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 four primary views:
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 & workers | Goal, current work, next work, blockers, phased plan, dependencies, gates, evidence, budgets, skills, workers, and outputs |
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
- An optional plan checkpoint appears only before execution begins. It lets you approve the proposed approach or request changes, but autonomous missions do not require that checkpoint. Once any work starts, stale plan-approval controls disappear. This is separate from accepting the completed mission.
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
- REST + WebSocket
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
- The product roadmap and completion checklist live in [`docs/IMPROVEMENTS.md`](docs/IMPROVEMENTS.md).
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 & workers** 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.
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
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./types.js";
2
2
  export * from "./status.js";
3
+ export * from "./directStudio.js";
@@ -1,2 +1,3 @@
1
1
  export * from "./types.js";
2
2
  export * from "./status.js";
3
+ export * from "./directStudio.js";
@@ -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
- if (job?.state === "blocked") {
33
- return { status: "waiting_on_you", stale: false };
34
- }
35
- // Mid-turn park: a permission prompt keeps state "working" but the daemon
36
- // flips tempo to blocked and puts the ask in needs ("approve Bash: …").
37
- if (job?.tempo === "blocked" && job.needs) {
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;
@@ -10,9 +10,12 @@
10
10
  ],
11
11
  "scripts": {
12
12
  "build": "tsc -p tsconfig.json",
13
+ "test": "tsx --test src/*.test.ts",
13
14
  "typecheck": "tsc --noEmit"
14
15
  },
15
16
  "devDependencies": {
17
+ "@types/node": "^22.0.0",
18
+ "tsx": "^4.19.0",
16
19
  "typescript": "^5.6.0"
17
20
  }
18
21
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shanesaravia/hive",
3
3
  "private": false,
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "description": "Provider-neutral local mission control for Claude Code, Codex, and agent fleets.",
7
7
  "license": "MIT",