@huynle/hub 0.9.0 → 0.9.2
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 +36 -0
- package/README.md +7 -4
- package/package.json +1 -1
- package/packages/claude-code/package.json +1 -1
- package/packages/claude-code/src/wrapper.ts +2 -2
- package/packages/cli/dist/hub-cli.js +1126 -479
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/bootstrap/PHASE3-CONTRACT.md +112 -0
- package/packages/cli/src/bootstrap/adapters/node-services/control.ts +164 -21
- package/packages/cli/src/bootstrap/adapters/node-services/plan.ts +24 -7
- package/packages/cli/src/bootstrap/adapters/node-services/render.ts +116 -9
- package/packages/cli/src/bootstrap/adapters/node-services/validate.ts +8 -2
- package/packages/cli/src/bootstrap/contracts/actions.ts +8 -6
- package/packages/cli/src/bootstrap/contracts/discovery.ts +4 -3
- package/packages/cli/src/bootstrap/contracts/exec.ts +4 -2
- package/packages/cli/src/bootstrap/contracts/paths.ts +2 -1
- package/packages/cli/src/bootstrap/contracts/platform.ts +5 -5
- package/packages/cli/src/bootstrap/discovery/discover.ts +7 -2
- package/packages/cli/src/bootstrap/discovery/host.ts +2 -0
- package/packages/cli/src/bootstrap/preview/plan.ts +5 -1
- package/packages/cli/src/bootstrap/profiles/desired.ts +16 -1
- package/packages/cli/src/bootstrap/profiles/history.ts +2 -1
- package/packages/cli/src/bootstrap/profiles/upgrade.ts +2 -2
- package/packages/cli/src/bootstrap/release/assets.ts +4 -1
- package/packages/cli/src/node.ts +94 -12
- package/packages/cli/src/setup/commands.ts +27 -7
- package/packages/cli/src/setup/runtime.ts +31 -4
- package/packages/codex/package.json +1 -1
- package/packages/codex/src/wrapper.ts +2 -2
- package/packages/node/package.json +1 -1
- package/packages/node/src/config.ts +49 -17
- package/packages/node/src/git.ts +16 -2
- package/packages/node/src/harnesses.ts +54 -9
- package/packages/node/src/host.ts +61 -15
- package/packages/node/src/opencode-service.ts +111 -0
- package/packages/node/src/opencode-warm.ts +11 -5
- package/packages/node/src/run.ts +50 -5
- package/packages/preset/package.json +1 -1
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/src/index.ts +3 -1
- package/packages/protocol/src/launch.ts +39 -4
- package/packages/runtime-openshell/package.json +1 -1
- package/packages/runtime-sdk/package.json +1 -1
- package/packages/sdk/package.json +1 -1
- package/packages/spoke-sdk/package.json +1 -1
- package/src/central/agent/launch-spec.ts +4 -2
- package/src/central/agent/webhooks.ts +5 -2
- package/src/central/config.ts +24 -2
- package/src/central/http.ts +1 -0
- package/src/central/install/CONTRACT.md +4 -4
- package/src/central/install/install.ps1 +37 -5
- package/src/central/install/render.ts +13 -8
- package/src/central/push-target.ts +11 -2
- package/web/dist/assets/{ArtifactPage-4GoBqSpU.js → ArtifactPage-BKISN-Qj.js} +1 -1
- package/web/dist/assets/{ArtifactPane-Dx_0iWwH.js → ArtifactPane-CKOiAUNH.js} +1 -1
- package/web/dist/assets/{ArtifactWorkbench-CuHgARMk.js → ArtifactWorkbench-d7R1o-rs.js} +1 -1
- package/web/dist/assets/{Diagram-CZM_R7MG.js → Diagram-azw2B_QH.js} +1 -1
- package/web/dist/assets/{Library-TwvrwqSk.js → Library-CcjZXsfF.js} +2 -2
- package/web/dist/assets/{ProfilesDestination-rKNDpLjR.js → ProfilesDestination-DdzbzmeK.js} +1 -1
- package/web/dist/assets/{TeamsPage-DtJylLrt.js → TeamsPage-CDyjrK-I.js} +1 -1
- package/web/dist/assets/{Watchtower-Bmgdyfjb.js → Watchtower-DYwoUWME.js} +2 -2
- package/web/dist/assets/{index-D-xG9nrc.js → index-LNMZCqgE.js} +15 -15
- package/web/dist/assets/{live-7q72Lyj2.js → live-ycZ_aQZO.js} +1 -1
- package/web/dist/assets/{renderer2d-hfZxM6Xl.js → renderer2d-BIwbgRoX.js} +1 -1
- package/web/dist/assets/{renderer3d-Km9vipTM.js → renderer3d-C1a7eYGQ.js} +1 -1
- package/web/dist/assets/{safe-area-BAbgBiFk.js → safe-area-DHhPy61Q.js} +1 -1
- package/web/dist/index.html +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.2
|
|
4
|
+
|
|
5
|
+
Webhooks can reach a named receiver on your own network without opening the hub to every private address. No
|
|
6
|
+
migration is needed.
|
|
7
|
+
|
|
8
|
+
### For operators
|
|
9
|
+
- **`agents.webhooks.allowPrivateHosts`** in `hub.json`: a list of exact hostnames whose `https://` webhook URLs may
|
|
10
|
+
resolve to private addresses (a LAN-hosted app behind split DNS, such as a Brain on the same cluster). Everything
|
|
11
|
+
else keeps the public-host rule: no `http://`, no IPs, no other hosts or subdomains, and the check still runs before
|
|
12
|
+
every send, and webhooks to a listed host must use port 443. Use it instead of `allowPrivate`, which opens private
|
|
13
|
+
targets for every webhook on the hub. In Kubernetes, also allow egress to the receiver's private address.
|
|
14
|
+
[docs/launches.md → Where webhooks may go](docs/launches.md#where-webhooks-may-go)
|
|
15
|
+
|
|
16
|
+
## 0.9.1
|
|
17
|
+
|
|
18
|
+
**+ launch node on Windows.** `hubctl` installs `hub node` as a per-user logon task (Task Scheduler: no admin, no
|
|
19
|
+
stored password, no window), and on Windows the node starts OpenCode's background service, so a Windows machine stays
|
|
20
|
+
online and takes launches without OpenCode left open. Choose it in the console's Set up dialog or with
|
|
21
|
+
`install.ps1?profile=launch-node`. All harnesses (Claude Code, Codex) stays coming soon on Windows. No migration is
|
|
22
|
+
needed.
|
|
23
|
+
|
|
24
|
+
### Machine setup
|
|
25
|
+
- **+ launch node on Windows**: `install.ps1` takes `profile=launch-node` with a `~/…` or `C:/…` workspace root and
|
|
26
|
+
`activate=1` (passed to hubctl as `--workspace-root` and `--confirm-activation`), and the console's Set up dialog
|
|
27
|
+
offers **+ launch node** on Windows (workspace folder as `C:\Users\you\projects`, `C:/…` or `~/…`; network
|
|
28
|
+
folders refused; Start services now). **All harnesses** stays coming soon on Windows.
|
|
29
|
+
- **hubctl: the `task-scheduler` service manager** (windows-x64): `hub node` runs as task `hub-node-<user>` at logon
|
|
30
|
+
(`conhost --headless hubctl.exe node run`, InteractiveToken, LeastPrivilege; the Task XML is UTF-16 in
|
|
31
|
+
`~/.local/state/hub/tasks`), restarted within a minute if it exits, controlled through a fixed `schtasks`/`taskkill`
|
|
32
|
+
allowlist with a locale-independent running check; `hub node install/uninstall` writes the XML and prints the
|
|
33
|
+
`schtasks` commands. `launch-node` plans on Windows; `full-harness` stays refused there.
|
|
34
|
+
- **The node on Windows**: canonical `C:/…` paths in the launch protocol, node.json (`C:\…`, `C:/…`, `~/…`) and
|
|
35
|
+
worktrees; it starts OpenCode's background service when none runs, then keeps it warm; a node with no workspace
|
|
36
|
+
roots waits for node.json instead of exiting; its log goes to `~/.local/state/hub/node.log`. git commands that hang
|
|
37
|
+
are killed with their children; every spawn starts hidden.
|
|
38
|
+
|
|
3
39
|
## 0.9.0
|
|
4
40
|
|
|
5
41
|
Three things in one release: **media in sessions** (screenshots, images, Mermaid diagrams, safe HTML previews, and
|
package/README.md
CHANGED
|
@@ -198,8 +198,9 @@ curl -fsSL 'https://hub.example.com/install.sh?profile=launch-node&root=~/projec
|
|
|
198
198
|
```
|
|
199
199
|
|
|
200
200
|
```powershell
|
|
201
|
-
# Windows x64 (PowerShell 5.1 or 7): the same steps with hubctl-windows-x64.exe
|
|
201
|
+
# Windows x64 (PowerShell 5.1 or 7): the same steps with hubctl-windows-x64.exe
|
|
202
202
|
irm 'https://hub.example.com/install.ps1' | iex
|
|
203
|
+
irm 'https://hub.example.com/install.ps1?profile=launch-node&root=C:/Users/me/projects&activate=1' | iex
|
|
203
204
|
```
|
|
204
205
|
|
|
205
206
|
Query options (each optional, at most once; anything else answers 400 with the reason):
|
|
@@ -207,11 +208,12 @@ Query options (each optional, at most once; anything else answers 400 with the r
|
|
|
207
208
|
| Key | Values | Default |
|
|
208
209
|
|---|---|---|
|
|
209
210
|
| `profile` | `session-only` (OpenCode only), `launch-node` (+ a launch node), `full-harness` (all harnesses) | `session-only` |
|
|
210
|
-
| `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
|
|
211
|
+
| `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 `~/` (`install.ps1`: `~/` or a drive path such as `C:/`, forward slashes), no `..` or `//` | `~/projects` |
|
|
211
212
|
| `activate` | `1` starts the services now (`--confirm-activation`), `0` leaves them stopped | `0` |
|
|
212
213
|
|
|
213
|
-
`install.ps1` takes
|
|
214
|
-
|
|
214
|
+
`install.ps1` takes `session-only` and `launch-node` (the node runs as a per-user logon task); `full-harness` answers
|
|
215
|
+
400 for now (Claude Code and Codex need user services hubctl does not install on Windows yet). It runs on x64
|
|
216
|
+
Windows only (no arm64 build yet). It never closes your PowerShell window: a failure is
|
|
215
217
|
one red `hub setup:` line. After a successful apply it adds `%USERPROFILE%\.local\bin` to your user PATH (once; open a
|
|
216
218
|
new terminal for other windows). The scripts carry
|
|
217
219
|
the hub's public URL, version and the validated choices; never a token. They download hubctl from this version's
|
|
@@ -1993,6 +1995,7 @@ in the file).
|
|
|
1993
1995
|
| `agents.never` | permission patterns (`action[:glob]`) no agent may ever approve, for every user, checked before any grant; see [Agent actions and grants](#agent-actions-and-grants) |
|
|
1994
1996
|
| `agents.launches` | per-user launch caps `{maxQueued?, maxActive?, perHour?}` (defaults 50, 4, 60) and `lostAfterMinutes?` (0–1440 or false, default 5: a running launch the same node instance stops reporting, with its session gone, ends lost; 0/false: never); see [docs/launches.md](docs/launches.md#placement-and-caps) |
|
|
1995
1997
|
| `agents.webhooks.allowPrivate` | `true` lets webhooks target `http://`, loopback and private hosts (self-hosted receivers); see [docs/launches.md](docs/launches.md#where-webhooks-may-go) |
|
|
1998
|
+
| `agents.webhooks.allowPrivateHosts` | exact hostnames (at most 50) whose `https://` webhook URLs may resolve to private addresses, e.g. a LAN-hosted app behind split DNS; nothing else is opened; see [docs/launches.md](docs/launches.md#where-webhooks-may-go) |
|
|
1996
1999
|
|
|
1997
2000
|
Server fields: env vars (`HUB_HOST`, `HUB_PORT`, `HUB_PUBLIC_URL`, `HUB_STATE_DIR`) > hub.json >
|
|
1998
2001
|
defaults. Speech: phone settings > hub.json > env vars. Values are checked like the phone's speech
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huynle/hub",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
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.9.
|
|
3
|
+
"version": "0.9.2",
|
|
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",
|
|
@@ -57,7 +57,7 @@ function spawnDaemon(io: ClaudeIo): void {
|
|
|
57
57
|
ensurePrivateDir(dir)
|
|
58
58
|
const log = openSync(path.join(dir, "daemon.log"), "a", 0o600)
|
|
59
59
|
try {
|
|
60
|
-
const child = spawn(io.program.execPath, [io.program.entry, "claude-code", "daemon"], { detached: true, stdio: ["ignore", log, log], env: { ...io.env, BUN_BE_BUN: "1" } })
|
|
60
|
+
const child = spawn(io.program.execPath, [io.program.entry, "claude-code", "daemon"], { detached: true, windowsHide: true, stdio: ["ignore", log, log], env: { ...io.env, BUN_BE_BUN: "1" } })
|
|
61
61
|
child.on("error", () => {})
|
|
62
62
|
child.unref()
|
|
63
63
|
} finally {
|
|
@@ -100,7 +100,7 @@ async function prepare(io: ClaudeIo, socket: string): Promise<string | undefined
|
|
|
100
100
|
/** Runs `bin` with the terminal; resolves with its exit code (128 + signal number when a signal ended it). */
|
|
101
101
|
function spawnClaude(bin: string, args: readonly string[], env: Env, stderr: (s: string) => void): Promise<number> {
|
|
102
102
|
return new Promise((resolve) => {
|
|
103
|
-
const child = spawn(bin, args, { stdio: "inherit", env: env as NodeJS.ProcessEnv })
|
|
103
|
+
const child = spawn(bin, args, { stdio: "inherit", windowsHide: true, env: env as NodeJS.ProcessEnv })
|
|
104
104
|
// The terminal sends Ctrl-C to Claude Code too: it decides what that means; this process keeps waiting.
|
|
105
105
|
const ignore = () => {}
|
|
106
106
|
const forward = () => child.kill("SIGTERM")
|