@huynle/hub 0.8.4 → 0.8.5

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +40 -3
  3. package/package.json +1 -1
  4. package/packages/claude-code/package.json +1 -1
  5. package/packages/cli/dist/hub-cli.js +5288 -4415
  6. package/packages/cli/package.json +1 -1
  7. package/packages/cli/src/bootstrap/PHASE2-CONTRACT.md +87 -0
  8. package/packages/cli/src/bootstrap/adapters/claude/node.ts +11 -43
  9. package/packages/cli/src/bootstrap/adapters/codex/verify.ts +19 -12
  10. package/packages/cli/src/bootstrap/adapters/opencode/README.md +42 -6
  11. package/packages/cli/src/bootstrap/adapters/opencode/apply.ts +18 -7
  12. package/packages/cli/src/bootstrap/adapters/opencode/archive.ts +36 -19
  13. package/packages/cli/src/bootstrap/adapters/opencode/config.ts +19 -3
  14. package/packages/cli/src/bootstrap/adapters/opencode/index.ts +2 -5
  15. package/packages/cli/src/bootstrap/adapters/opencode/plan.ts +37 -6
  16. package/packages/cli/src/bootstrap/adapters/opencode/verify.ts +49 -26
  17. package/packages/cli/src/bootstrap/adapters/process-tree.ts +263 -0
  18. package/packages/cli/src/bootstrap/contracts/paths.ts +7 -4
  19. package/packages/cli/src/bootstrap/contracts/platform.ts +9 -5
  20. package/packages/cli/src/bootstrap/contracts/validate.ts +20 -4
  21. package/packages/cli/src/bootstrap/discovery/discover.ts +3 -1
  22. package/packages/cli/src/bootstrap/discovery/executables.ts +49 -14
  23. package/packages/cli/src/bootstrap/discovery/host.ts +16 -8
  24. package/packages/cli/src/bootstrap/discovery/node-probe.ts +41 -5
  25. package/packages/cli/src/bootstrap/discovery/probe.ts +7 -3
  26. package/packages/cli/src/bootstrap/discovery/util.ts +42 -5
  27. package/packages/cli/src/bootstrap/enrollment/store.ts +13 -6
  28. package/packages/cli/src/bootstrap/preview/plan.ts +3 -0
  29. package/packages/cli/src/bootstrap/profiles/desired.ts +10 -3
  30. package/packages/cli/src/bootstrap/release/README.md +63 -9
  31. package/packages/cli/src/bootstrap/release/cli.ts +94 -16
  32. package/packages/cli/src/bootstrap/release/harness-pins.pending.json +24 -0
  33. package/packages/cli/src/bootstrap/release/manifest.ts +3 -0
  34. package/packages/cli/src/bootstrap/release/pins.ts +60 -9
  35. package/packages/cli/src/bootstrap/transaction/builtin.ts +18 -6
  36. package/packages/cli/src/bootstrap/transaction/engine.ts +166 -12
  37. package/packages/cli/src/bootstrap/transaction/executor.ts +5 -0
  38. package/packages/cli/src/bootstrap/transaction/fs.ts +142 -3
  39. package/packages/cli/src/bootstrap/transaction/shim.ts +31 -0
  40. package/packages/cli/src/bootstrap/transaction/state.ts +11 -6
  41. package/packages/cli/src/credentials.ts +5 -2
  42. package/packages/cli/src/main.ts +3 -2
  43. package/packages/cli/src/setup/commands.ts +96 -18
  44. package/packages/cli/src/setup/contributors.ts +45 -10
  45. package/packages/cli/src/setup/runtime.ts +25 -6
  46. package/packages/cli/src/setup/self-aside.ts +130 -0
  47. package/packages/codex/package.json +1 -1
  48. package/packages/node/package.json +1 -1
  49. package/packages/node/src/opencode-warm.ts +12 -4
  50. package/packages/preset/package.json +1 -1
  51. package/packages/protocol/package.json +1 -1
  52. package/packages/runtime-openshell/package.json +1 -1
  53. package/packages/runtime-sdk/package.json +1 -1
  54. package/packages/sdk/package.json +1 -1
  55. package/packages/spoke-sdk/package.json +1 -1
  56. package/src/central/config.ts +12 -0
  57. package/src/central/http.ts +10 -0
  58. package/src/central/install/CONTRACT.md +66 -0
  59. package/src/central/install/install.ps1 +349 -0
  60. package/src/central/install/install.sh +266 -0
  61. package/src/central/install/render.ts +146 -0
  62. package/src/central/install/templates.ts +6 -0
  63. package/src/central/install/text-assets.d.ts +9 -0
  64. package/src/config.ts +12 -7
  65. package/src/spoke/env-inject.ts +17 -2
  66. package/src/spoke/launchers.ts +145 -9
  67. package/src/win-acl.ts +154 -0
  68. package/web/dist/assets/ArtifactPage-Dq7VW-bU.js +1 -0
  69. package/web/dist/assets/{ArtifactPane-XTnwXl-Y.js → ArtifactPane-DKwbMTX9.js} +1 -1
  70. package/web/dist/assets/ArtifactWorkbench-vrgIfncX.js +6 -0
  71. package/web/dist/assets/Library-D6-Go6Cu.js +2 -0
  72. package/web/dist/assets/{ProfilesDestination-dZa3vioh.js → ProfilesDestination-BOML2Dgf.js} +1 -1
  73. package/web/dist/assets/{TeamsPage-DJt-Kk84.js → TeamsPage-CNBTE8gB.js} +1 -1
  74. package/web/dist/assets/Watchtower-Dor1Ubjy.js +2 -0
  75. package/web/dist/assets/Watchtower-RphjcL0_.css +1 -0
  76. package/web/dist/assets/hub-CrbItiwP.js +13 -0
  77. package/web/dist/assets/index-82Ce0IAf.css +1 -0
  78. package/web/dist/assets/index-D9SP3_0z.js +22 -0
  79. package/web/dist/assets/{live-D-RZbeUi.js → live-BNJgy0vg.js} +3 -3
  80. package/web/dist/assets/{pane-layout-Csk-vPNe.js → pane-layout-EdR1kRrG.js} +1 -1
  81. package/web/dist/assets/preload-helper-DqrJTq0t.js +1 -0
  82. package/web/dist/assets/{renderer2d-DILxLFEq.js → renderer2d-CYag1CnR.js} +1 -1
  83. package/web/dist/assets/{renderer3d-PvN9Qbt2.js → renderer3d-BRB6rgDJ.js} +1 -1
  84. package/web/dist/assets/{safe-area-BS6ii3M7.js → safe-area-fOy0AOuG.js} +1 -1
  85. package/web/dist/assets/{source-BFLJQ43_.js → source-Wbq35qGp.js} +1 -1
  86. package/web/dist/assets/{ui-Qo2Pd9-O.js → ui-j5FFk90B.js} +1 -1
  87. package/web/dist/index.html +6 -4
  88. package/web/dist/assets/ArtifactPage-Cb1DcrQf.js +0 -1
  89. package/web/dist/assets/ArtifactWorkbench-C37tZZ3e.js +0 -6
  90. package/web/dist/assets/Library-CZSSHvOJ.js +0 -2
  91. package/web/dist/assets/Watchtower-BXaUaXO1.js +0 -2
  92. package/web/dist/assets/Watchtower-CTgqHk5g.css +0 -1
  93. package/web/dist/assets/index-DVSkeAvn.css +0 -1
  94. package/web/dist/assets/index-DifgVuKS.js +0 -34
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.5
4
+
5
+ Set up Hub on a machine in one line. The console's new **Set up Hub on a machine** (avatar menu, Settings → Machines
6
+ & devices, Watchtower) builds a `curl … | sh` (macOS, Linux) or `irm … | iex` (Windows) command that the hub serves
7
+ with its own URL and version: it installs and checks hubctl, enrolls the machine (you approve it in the console) and
8
+ sets it up. hubctl now runs natively on Windows x64 for the OpenCode-only profile. No migration is needed.
9
+
10
+ ### Machine setup
11
+ - **The hub serves one-line install scripts**: public `GET /install.sh` (macOS, Linux: `curl -fsSL '<hub>/install.sh?…' | sh`)
12
+ and `GET /install.ps1` (Windows: `irm '<hub>/install.ps1?…' | iex`), rendered from fixed templates with only the
13
+ hub's public URL, its version and the validated choices (`profile`, `root`, `activate`; anything else answers 400
14
+ with the reason; never a token). They pin this hub's hubctl release; the new `HUB_RELEASE_BASE` points them
15
+ elsewhere (https, or http on loopback or a private-network IP), and a development version without it answers 503.
16
+ A plain-http hub is served only on loopback or a private-network IP (with `--allow-insecure-http`), else 400.
17
+ Leave both paths reachable behind an authenticating proxy, like `/.well-known/hub`.
18
+ - **`install.ps1` installs hubctl on Windows** (x64; arm64 and 32-bit are refused with the reason): it downloads
19
+ `hubctl-windows-x64.exe`, checks its sha256 against `HUBCTL_SHA256SUMS` (`Get-FileHash`), then runs the same
20
+ `machine status` / `machine enroll` / `setup preview` / `setup apply` / `setup verify` sequence as `install.sh`
21
+ (session-only), and adds `%USERPROFILE%\.local\bin` to the user PATH once (`%VARS%` in it are kept). It no longer adds
22
+ the OpenCode plugin or writes the spoke config itself; it still never closes the PowerShell window.
23
+ - Console: **Set up Hub on a machine**, one dialog opened from the avatar's new menu, Settings → Machines & devices
24
+ (**Set up a machine**, also in the settings search) and Watchtower's **Connect a machine**: pick the OS (detected),
25
+ the profile (OpenCode only, + launch node with its workspace folder, All harnesses; Windows: OpenCode only for
26
+ now) and Start services now, then copy the `curl … | sh` or `irm … | iex` one-liner built from the hub's public URL.
27
+
28
+ ### hubctl on Windows (x64, OpenCode only)
29
+ - **`hubctl-windows-x64.exe`** is built, signed into the release manifest and smoke-tested on Windows. Windows paths
30
+ (`C:/…`) are first-class in plans and journals; discovery reads `%USERPROFILE%`, PATHEXT, `.cmd` shims and the
31
+ machine's `MachineGuid`. `hub` and `opencode` on PATH are `.cmd` shims, the harness's current version is a junction,
32
+ files in use are replaced rename-aside, and the machine credential gets an owner-only ACL. `+ launch node` and
33
+ `All harnesses` need user services and are refused on Windows for now. This release pins no OpenCode for Windows
34
+ yet: a Windows machine without OpenCode is asked to install it first.
35
+ - **The OpenCode plugin writes `.cmd` launchers on Windows** instead of `#!/bin/sh` scripts and a symlink, and never
36
+ overwrites hubctl's `hub.cmd`.
37
+ - **Rollback**: a rollback that removes the running `hubctl.exe` deletes it once it exits and lists what it undid; a
38
+ path in use undoes everything else, names the path and is finished by `hubctl setup recover`.
39
+ - **Verify probes leave nothing running** (all harnesses, every OS): `opencode models --standalone`, and the probe's
40
+ whole process tree ends with it.
41
+
42
+ ### Fixes
43
+ - `HEAD /install.sh` and `/install.ps1` answer like GET without a body.
44
+
3
45
  ## 0.8.4
4
46
 
5
47
  A fix release. A question or permission a session is waiting on no longer disappears from the console while
package/README.md CHANGED
@@ -179,6 +179,41 @@ Optional: put the voice agent on a fast model in `~/.config/hub/config.json`:
179
179
  `"voiceModel": "anthropic/claude-haiku-4-5"` (any `provider/model` you have). Subagents keep the
180
180
  session's model.
181
181
 
182
+ ## Set up a machine (one line)
183
+
184
+ The hub serves an install script for its own version, so a machine needs only one command. In the console use
185
+ **Set up Hub on a machine** (avatar menu, Settings → Machines, or Watchtower's **Connect a machine**) and copy the
186
+ line it shows, or write it yourself:
187
+
188
+ ```sh
189
+ # macOS / Linux (POSIX sh): downloads and checks hubctl, enrolls (approve the code in the console), previews, applies
190
+ curl -fsSL 'https://hub.example.com/install.sh' | sh
191
+ curl -fsSL 'https://hub.example.com/install.sh?profile=launch-node&root=~/projects&activate=1' | sh
192
+ ```
193
+
194
+ ```powershell
195
+ # Windows x64 (PowerShell 5.1 or 7): the same steps with hubctl-windows-x64.exe; OpenCode only for now
196
+ irm 'https://hub.example.com/install.ps1' | iex
197
+ ```
198
+
199
+ Query options (each optional, at most once; anything else answers 400 with the reason):
200
+
201
+ | Key | Values | Default |
202
+ |---|---|---|
203
+ | `profile` | `session-only` (OpenCode only), `launch-node` (+ a launch node), `full-harness` (all harnesses) | `session-only` |
204
+ | `root` | the launch node's workspace root, only with `launch-node`: up to 200 characters of `A-Z a-z 0-9 . _ / ~ -`, starting with `/` or `~/`, no `..` or `//` | `~/projects` |
205
+ | `activate` | `1` starts the services now (`--confirm-activation`), `0` leaves them stopped | `0` |
206
+
207
+ `install.ps1` takes only `profile=session-only` and `activate=0` for now (hubctl does not install user services on
208
+ Windows yet) and runs on x64 Windows only (no arm64 build yet). It never closes your PowerShell window: a failure is
209
+ one red `hub setup:` line. After a successful apply it adds `%USERPROFILE%\.local\bin` to your user PATH (once; open a
210
+ new terminal for other windows). The scripts carry
211
+ the hub's public URL, version and the validated choices; never a token. They download hubctl from this version's
212
+ release on [hub-releases](https://github.com/huynle/hub-releases/releases) (`v<version>`); `HUB_RELEASE_BASE` on
213
+ the hub points them at another location (a mirror, or a development build, which otherwise answers 503). A
214
+ plain-`http` hub is served only on loopback or a private-network IP address (the script then passes
215
+ `--allow-insecure-http`); on a host name or a public address the routes answer 400: use https.
216
+
182
217
  ## Quick start (hubctl, before any harness)
183
218
 
184
219
  `hubctl` is a standalone, signed program (Bun and the CLI compiled into one file; no bun, node or harness needed)
@@ -317,8 +352,9 @@ foreground with `hub.json`; `scripts/io.github.huynle.hub.plist` is a launchd te
317
352
  **Security:** the hub can drive your OpenCode sessions, which can run tools. Every API call needs a
318
353
  paired device or a signed-in user; spokes need machine tokens; nothing trusts the client IP. For a public
319
354
  hostname, consider [sign-in with Google](#multi-user-sign-in-with-google) or an authenticating proxy in
320
- front of the web app, and leave `/spoke/*`, `/auth/*`, `/healthz`, `/.well-known/hub`, the manifest and
321
- icons reachable for spokes, sign-in, app discovery and the PWA (and `/mcp`, bearer-authenticated, if MCP clients
355
+ front of the web app, and leave `/spoke/*`, `/auth/*`, `/healthz`, `/.well-known/hub`, `/install.sh`,
356
+ `/install.ps1`, the manifest and icons reachable for spokes, sign-in, app discovery, [machine
357
+ setup](#set-up-a-machine-one-line) and the PWA (and `/mcp`, bearer-authenticated, if MCP clients
322
358
  or gateways use [MCP over HTTP](#over-http-mcp)).
323
359
 
324
360
  **Behind a reverse proxy**, set a request-body limit of about 26 MiB (artifact blobs are up to 25 MiB) and keep
@@ -328,7 +364,7 @@ including `blobs/` (artifact bytes).
328
364
 
329
365
  ## Configuration
330
366
 
331
- - **Hub**: env vars (`HUB_HOST`, `HUB_PORT`, `HUB_PUBLIC_URL`, `HUB_STATE_DIR`, `OPENROUTER_API_KEY`, …)
367
+ - **Hub**: env vars (`HUB_HOST`, `HUB_PORT`, `HUB_PUBLIC_URL`, `HUB_STATE_DIR`, `HUB_RELEASE_BASE`, `OPENROUTER_API_KEY`, …)
332
368
  over `~/.config/hub/hub.json` (`$HUB_CONFIG`); see [Central server](#central-server) and
333
369
  [hub.json](#hubjson). Speech providers and keys are easiest to set in the app (Settings → Speech).
334
370
  - **Plugin** (OpenCode spoke): `~/.config/hub/config.json` (`$HUB_SPOKE_CONFIG`; server, mode, machine
@@ -1218,6 +1254,7 @@ holds the startup (`bin/hub.ts` serves `web/` from disk; the compiled binaries e
1218
1254
  | `HUB_DATABASE_STATEMENT_TIMEOUT_MS` | `30000` | cluster mode: Postgres `statement_timeout` of the hub's pools (`0` turns it off) |
1219
1255
  | `HUB_TURN_TIMEOUT_MS` | `600000` | the hub waits this + 15 s so the spoke's own timeout result arrives first |
1220
1256
  | `HUB_VAPID_SUBJECT` | the https public URL, else `mailto:hub@localhost` | contact sent to push services |
1257
+ | `HUB_RELEASE_BASE` | `https://github.com/huynle/hub-releases/releases/download/v<version>` | where `/install.sh` and `/install.ps1` download hubctl ([Set up a machine](#set-up-a-machine-one-line)): https, or plain http on loopback or a private-network IP address; the hub refuses to start with any other value. Without it a development version (not a plain `x.y.z`) answers 503 |
1221
1258
  | `HUB_CSP` | `enforce` | `report-only` sends the console's Content-Security-Policy as `Content-Security-Policy-Report-Only` (violations are only logged in the browser console); see [Content-Security-Policy](#content-security-policy) |
1222
1259
  | `OPENROUTER_API_KEY` | | default key for the `openrouter` speech provider (never sent to other providers) |
1223
1260
  | `HUB_STT_MODEL`, `HUB_TTS_MODEL`, `HUB_VOICE`, `HUB_MAX_*` | see `src/central/config.ts` | speech defaults; the phone's speech settings override them |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huynle/hub",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "Hub: a harness-agnostic central hub your AI agent harnesses connect to (OpenCode first). Follow, steer and stop sessions from your phone or browser, with notifications, optional hands-free Voice and a self-hostable server.",
5
5
  "license": "MIT",
6
6
  "author": "Huy Le",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huynle/hub-claude-code",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "private": true,
5
5
  "description": "The Claude Code hooks spoke: per-user daemon, hook bridge, plugin dir, `hub claude` wrapper and daemon-backed MCP server (internal; shipped inside @huynle/hub, not published on its own).",
6
6
  "license": "MIT",