@shanesaravia/hive 0.1.0 → 0.1.1
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 +5 -0
- package/README.md +11 -0
- package/dist/bin/hive.js +157 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Hive will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.1.1 — 2026-08-23
|
|
6
|
+
|
|
7
|
+
- Add `hive update`, with read-only checks, interactive or unattended installation, setup refresh, and automatic restart of an active local server.
|
|
8
|
+
|
|
5
9
|
## 0.1.0 — 2026-08-23
|
|
6
10
|
|
|
7
11
|
Initial public preview of Hive, a provider-neutral local mission-control interface for Claude Code, Codex, and agent fleets.
|
|
@@ -14,4 +18,5 @@ Initial public preview of Hive, a provider-neutral local mission-control interfa
|
|
|
14
18
|
- Mission health, lifecycle, recovery, policies, budgets, templates, notifications, and searchable history
|
|
15
19
|
- Repository-aware working directories, skills, MCP configuration, and Git worktrees where supported
|
|
16
20
|
- Installable `hive` CLI with diagnostics, optional setup, persistent local state, and graceful lifecycle commands
|
|
21
|
+
- Browser-origin enforcement protecting the loopback control API and WebSocket from foreign websites
|
|
17
22
|
- Verified npm artifact across macOS and Ubuntu on Node.js 20 and 22
|
package/README.md
CHANGED
|
@@ -120,12 +120,23 @@ Useful commands:
|
|
|
120
120
|
| `hive status` | Report whether Hive is running and its local address. |
|
|
121
121
|
| `hive open` | Open an already-running dashboard. |
|
|
122
122
|
| `hive stop` | Gracefully stop Hive. |
|
|
123
|
+
| `hive update --check` | Check npm for a newer Hive release without changing anything. |
|
|
124
|
+
| `hive update` | Confirm and install the latest release, refreshing setup and restarting Hive when needed. |
|
|
125
|
+
| `hive update --yes` | Install the latest release without an interactive confirmation. |
|
|
123
126
|
| `hive --version` | Show the installed version. |
|
|
124
127
|
|
|
125
128
|
## Update or uninstall
|
|
126
129
|
|
|
127
130
|
Update to the newest release:
|
|
128
131
|
|
|
132
|
+
```bash
|
|
133
|
+
hive update
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
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.
|
|
137
|
+
|
|
138
|
+
You can still update directly through npm if the installed Hive command is unavailable:
|
|
139
|
+
|
|
129
140
|
```bash
|
|
130
141
|
npm install --global @shanesaravia/hive@latest
|
|
131
142
|
```
|
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());
|
package/package.json
CHANGED