@huynle/hub 0.7.3 → 0.8.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 +229 -0
- package/Dockerfile +7 -2
- package/README.md +153 -24
- package/package.json +5 -3
- package/packages/claude-code/package.json +1 -1
- package/packages/claude-code/src/daemon.ts +8 -1
- package/packages/claude-code/src/launcher.ts +29 -9
- package/packages/claude-code/src/profile.ts +173 -0
- package/packages/claude-code/src/sessions.ts +22 -4
- package/packages/cli/dist/hub-cli.js +6474 -3470
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/artifact-jobs-mcp.ts +226 -0
- package/packages/cli/src/artifacts-mcp.ts +160 -0
- package/packages/cli/src/bootstrap/enrollment/enroll.ts +20 -8
- package/packages/cli/src/bootstrap/enrollment/policy.ts +125 -12
- package/packages/cli/src/bootstrap/enrollment/status.ts +3 -2
- package/packages/cli/src/cli.ts +95 -13
- package/packages/cli/src/format.ts +48 -10
- package/packages/cli/src/http.ts +1 -0
- package/packages/cli/src/intents.ts +23 -0
- package/packages/cli/src/login.ts +20 -6
- package/packages/cli/src/mcp.ts +380 -9
- package/packages/cli/src/messaging.ts +3 -1
- package/packages/cli/src/setup/commands.ts +3 -2
- package/packages/cli/src/setup/runtime.ts +3 -2
- package/packages/cli/src/team-intake-mcp.ts +158 -0
- package/packages/cli/src/teams-mcp.ts +403 -0
- package/packages/cli/src/watchlist.ts +135 -0
- package/packages/codex/package.json +1 -1
- package/packages/codex/src/profile.ts +163 -0
- package/packages/codex/src/sessions.ts +12 -0
- package/packages/codex/src/spoke.ts +19 -1
- package/packages/node/package.json +1 -1
- package/packages/node/src/config.ts +96 -2
- package/packages/node/src/opencode-warm.ts +325 -0
- package/packages/node/src/run.ts +27 -1
- package/packages/preset/package.json +1 -1
- package/packages/preset/src/profile.ts +34 -0
- package/packages/preset/src/spoke.ts +4 -0
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/src/artifacts.ts +142 -0
- package/packages/protocol/src/concierge.ts +366 -0
- package/packages/protocol/src/contracts.ts +104 -0
- package/packages/protocol/src/graph.ts +70 -0
- package/packages/protocol/src/hub-workspace.ts +201 -0
- package/packages/protocol/src/index.ts +169 -6
- package/packages/protocol/src/launch.ts +22 -0
- package/packages/protocol/src/profiles.ts +301 -0
- package/packages/protocol/src/teams.ts +204 -0
- 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/sdk/src/address.ts +50 -2
- package/packages/sdk/src/artifact-jobs.ts +194 -0
- package/packages/sdk/src/artifacts.ts +187 -0
- package/packages/sdk/src/client.ts +226 -5
- package/packages/sdk/src/concierge.ts +88 -0
- package/packages/sdk/src/errors.ts +3 -1
- package/packages/sdk/src/index.ts +5 -0
- package/packages/sdk/src/team-intake.ts +122 -0
- package/packages/sdk/src/teams.ts +346 -0
- package/packages/sdk/src/types.ts +548 -1
- package/packages/spoke-sdk/package.json +1 -1
- package/packages/spoke-sdk/src/index.ts +1 -0
- package/packages/spoke-sdk/src/profile-apply.ts +245 -0
- package/src/central/actions.ts +7 -0
- package/src/central/agent/acting-routes.ts +2 -1
- package/src/central/agent/acting-switch.ts +2 -1
- package/src/central/agent/acting.ts +215 -10
- package/src/central/agent/app-tokens.ts +3 -2
- package/src/central/agent/audit.ts +17 -0
- package/src/central/agent/body.ts +163 -0
- package/src/central/agent/decisions.ts +69 -2
- package/src/central/agent/delivery.ts +95 -15
- package/src/central/agent/directory-routes.ts +37 -7
- package/src/central/agent/directory.ts +70 -14
- package/src/central/agent/errors.ts +5 -0
- package/src/central/agent/events-routes.ts +21 -4
- package/src/central/agent/events.ts +11 -3
- package/src/central/agent/form-check.ts +85 -0
- package/src/central/agent/grant-requests.ts +2 -1
- package/src/central/agent/grant-routes.ts +4 -3
- package/src/central/agent/grants.ts +29 -2
- package/src/central/agent/idempotency.ts +133 -0
- package/src/central/agent/intent-routes.ts +116 -0
- package/src/central/agent/intents.ts +505 -0
- package/src/central/agent/interaction-graph-routes.ts +212 -0
- package/src/central/agent/interaction-graph.ts +865 -0
- package/src/central/agent/launch-engine.ts +16 -2
- package/src/central/agent/launch-routes.ts +6 -1
- package/src/central/agent/launch-spec.ts +14 -1
- package/src/central/agent/message-routes.ts +2 -1
- package/src/central/agent/messages.ts +27 -2
- package/src/central/agent/names.ts +12 -2
- package/src/central/agent/read-routes.ts +86 -19
- package/src/central/agent/routes.ts +176 -5
- package/src/central/agent/webhook-routes.ts +2 -1
- package/src/central/agent-data.ts +4 -0
- package/src/central/artifacts/access.ts +44 -0
- package/src/central/artifacts/blob-store.ts +113 -0
- package/src/central/artifacts/blob-support.ts +98 -0
- package/src/central/artifacts/events.ts +27 -0
- package/src/central/artifacts/host-caps.ts +162 -0
- package/src/central/artifacts/host.ts +315 -0
- package/src/central/artifacts/idempotency.ts +109 -0
- package/src/central/artifacts/jobs-routes.ts +773 -0
- package/src/central/artifacts/jobs.ts +344 -0
- package/src/central/artifacts/maintenance.ts +103 -0
- package/src/central/artifacts/routes.ts +360 -0
- package/src/central/artifacts/store.ts +776 -0
- package/src/central/artifacts/workspaces.ts +31 -0
- package/src/central/backend/file-blobs.ts +377 -0
- package/src/central/backend/index.ts +12 -3
- package/src/central/backend/memory-blobs.ts +116 -0
- package/src/central/backend/postgres-blobs.ts +513 -0
- package/src/central/backend/postgres-migrate.ts +33 -0
- package/src/central/backend/postgres-state.ts +19 -0
- package/src/central/backend/types.ts +8 -0
- package/src/central/concierge/activity.ts +142 -0
- package/src/central/concierge/arm.ts +63 -0
- package/src/central/concierge/board-render.ts +190 -0
- package/src/central/concierge/board-results.ts +169 -0
- package/src/central/concierge/board-routes.ts +339 -0
- package/src/central/concierge/board.ts +249 -0
- package/src/central/concierge/context.ts +221 -0
- package/src/central/concierge/entitlements.ts +13 -0
- package/src/central/concierge/guard.ts +120 -0
- package/src/central/concierge/inbound.ts +89 -0
- package/src/central/concierge/index.ts +84 -0
- package/src/central/concierge/notes.ts +41 -0
- package/src/central/concierge/notifier.ts +986 -0
- package/src/central/concierge/prompt.ts +130 -0
- package/src/central/concierge/proposals.ts +262 -0
- package/src/central/concierge/push-remap.ts +49 -0
- package/src/central/concierge/routes.ts +62 -0
- package/src/central/concierge/schedule.ts +113 -0
- package/src/central/concierge/service.ts +243 -0
- package/src/central/concierge/session-routes.ts +69 -0
- package/src/central/concierge/settings.ts +217 -0
- package/src/central/concierge/supervisor.ts +740 -0
- package/src/central/concierge/tiers.ts +260 -0
- package/src/central/concierge/watchlist-routes.ts +277 -0
- package/src/central/concierge/watchlist.ts +273 -0
- package/src/central/config.ts +7 -1
- package/src/central/http.ts +633 -50
- package/src/central/mcp-http.ts +10 -21
- package/src/central/profiles/apply.ts +333 -0
- package/src/central/profiles/content.ts +174 -0
- package/src/central/profiles/events.ts +40 -0
- package/src/central/profiles/idempotency.ts +14 -0
- package/src/central/profiles/import.ts +139 -0
- package/src/central/profiles/routes.ts +356 -0
- package/src/central/profiles/store.ts +597 -0
- package/src/central/profiles/usage-ports.ts +120 -0
- package/src/central/profiles/usage.ts +364 -0
- package/src/central/push.ts +7 -0
- package/src/central/registry.ts +43 -6
- package/src/central/store.ts +4 -0
- package/src/central/teams/collections.ts +34 -0
- package/src/central/teams/discovery.ts +346 -0
- package/src/central/teams/draft-edits.ts +46 -0
- package/src/central/teams/events.ts +46 -0
- package/src/central/teams/intake-routes.ts +100 -0
- package/src/central/teams/intake.ts +772 -0
- package/src/central/teams/policy.ts +231 -0
- package/src/central/teams/routes.ts +516 -0
- package/src/central/teams/seats.ts +272 -0
- package/src/central/teams/staffing.ts +888 -0
- package/src/central/teams/store.ts +667 -0
- package/src/central/teams/validation.ts +256 -0
- package/src/central/workspaces/board.ts +408 -0
- package/src/central/workspaces/checkpoints.ts +316 -0
- package/src/central/workspaces/coordinator.ts +841 -0
- package/src/central/workspaces/events.ts +85 -0
- package/src/central/workspaces/lifecycle.ts +93 -0
- package/src/central/workspaces/master.ts +490 -0
- package/src/central/workspaces/members.ts +632 -0
- package/src/central/workspaces/routes.ts +354 -0
- package/src/central/workspaces/sidechats-routes.ts +410 -0
- package/src/central/workspaces/sidechats.ts +482 -0
- package/src/central/workspaces/store.ts +571 -0
- package/src/central/workspaces/supervision.ts +355 -0
- package/src/index.ts +97 -15
- package/src/spoke/concierge-agent.ts +33 -0
- package/src/spoke/deliver.ts +22 -4
- package/src/spoke/fork-revert.ts +142 -0
- package/src/spoke/hub-rpc.ts +41 -5
- package/src/spoke/hub-tool.ts +383 -18
- package/src/spoke/listing.ts +47 -4
- package/src/spoke/profile-apply.ts +298 -0
- package/src/spoke/session-context.ts +176 -0
- package/src/spoke/spoke.ts +319 -20
- package/src/spoke/timeline.ts +6 -1
- package/src/spoke/tracker.ts +23 -1
- package/src/spoke/who-teams.ts +81 -0
- package/src/tui-messaging.ts +32 -18
- package/web/dist/assets/ArtifactPage-BS0gVkfu.js +1 -0
- package/web/dist/assets/ArtifactPane-PLYHNs6s.js +1 -0
- package/web/dist/assets/ArtifactWorkbench-9eTj1CeW.css +1 -0
- package/web/dist/assets/ArtifactWorkbench-LkDyJ5Dv.js +6 -0
- package/web/dist/assets/Library-CtxRqTjo.js +2 -0
- package/web/dist/assets/Library-DYsFj_5c.css +1 -0
- package/web/dist/assets/ProfilesDestination-BYiHKLmc.js +1 -0
- package/web/dist/assets/TeamsPage-BwjsAAUC.js +1 -0
- package/web/dist/assets/Watchtower-C4swrWVs.js +2 -0
- package/web/dist/assets/Watchtower-CTgqHk5g.css +1 -0
- package/web/dist/assets/index-DaH5GUdV.js +31 -0
- package/web/dist/assets/index-WWuKfWxL.css +1 -0
- package/web/dist/assets/live-BUofsQpz.css +1 -0
- package/web/dist/assets/live-YyTjE47g.js +5 -0
- package/web/dist/assets/pane-layout-CKC4I00k.js +1 -0
- package/web/dist/assets/plural-Bspvoqfq.js +1 -0
- package/web/dist/assets/renderer2d-CX5j3NcD.js +1 -0
- package/web/dist/assets/renderer3d-BXIVOvfi.js +5393 -0
- package/web/dist/assets/safe-area-DfPsOdWR.js +1 -0
- package/web/dist/assets/source-CvUHTc3O.js +1 -0
- package/web/dist/assets/ui-C9Igxzjm.js +1 -0
- package/web/dist/index.html +5 -2
- package/web/dist/sw.js +22 -2
- package/web/dist/assets/index-Dm8OmkaO.css +0 -1
- package/web/dist/assets/index-FUJbj_Du.js +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,235 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.8.0
|
|
6
|
+
|
|
7
|
+
Workspaces, supervision, split panes and side chats, shared agent profiles, persistent AI-powered artifacts, teams,
|
|
8
|
+
and the Watchtower. All new state is additive. Cluster hubs need `hub-server migrate` (schema v2) before the new
|
|
9
|
+
pods start. See [docs/operations.md](docs/operations.md) for the rollout, rollback, backup and front-proxy notes.
|
|
10
|
+
|
|
11
|
+
### Fork and revert a message
|
|
12
|
+
- Hovering (or focusing) one of your messages in the console shows **Copy · Fork · Revert**, like the OpenCode app;
|
|
13
|
+
on a phone, long-press it or tap its ⋯ button. **Fork** opens a new session with the conversation before the
|
|
14
|
+
message and the message in its composer. **Revert** hides the message and everything after it, restores the files
|
|
15
|
+
the session changed since then (confirming first, with the list), and puts the message back in the composer; a
|
|
16
|
+
banner offers **Restore**; sending the next message makes it permanent. Works across devices and in panes.
|
|
17
|
+
- New console routes (user-only, audited): `POST /api/sessions/:id/fork`, `GET …/revert/preview`, `POST …/revert`,
|
|
18
|
+
`POST …/revert/restore`, `POST …/revert/commit`. Spoke features `fork` and `revert` (OpenCode processes that reach
|
|
19
|
+
their own server) with ops `fork`, `revertPreview`, `revert`, `revertRestore`, `revertCommit`; a staged revert is
|
|
20
|
+
reported as `SessionInfo.revert` (additive: older hubs ignore it). Other harnesses show the actions disabled
|
|
21
|
+
("not supported yet"). Contract: [docs/session-view.md](docs/session-view.md#fork-and-revert-a-message).
|
|
22
|
+
|
|
23
|
+
### Workspaces and supervision
|
|
24
|
+
- **Workspaces** ([docs/workspaces.md](docs/workspaces.md)): durable, cross-machine coordination units with host repo
|
|
25
|
+
bindings, members (`master`/`worker`/`observer`, generations), explicit assignments and a supervision graph
|
|
26
|
+
(acyclic, ≤ 6 levels) kept apart from native `parentID`. Membership and supervision grant nothing. New routes under
|
|
27
|
+
`/api/agent/workspaces…`, SDK `hub.workspaces`, 15 `workspace_*` MCP tools, and compact `workspace.*` events.
|
|
28
|
+
- **Drag to supervise**: the sidebar's **Workspaces** tree shows each workspace's members under their supervisors.
|
|
29
|
+
Drag (or use Alt+arrows or the Move menu) to supervise, reorder or detach. "Spawned by" and "supervised by" are
|
|
30
|
+
shown separately.
|
|
31
|
+
- **Situation board** (`GET …/board`): one bounded, text-free snapshot of members, presence, blockers, assignments,
|
|
32
|
+
Decisions and artifacts, with `stale`/`omitted`/`failed` sections instead of guesses.
|
|
33
|
+
- **Supervisor digests and checkpoints**: masters and supervisors get batched, at-least-once digests as hub messages
|
|
34
|
+
from `app:workspace-coordinator`. `POST …/checkpoints` acknowledges them durably (flushed before the answer).
|
|
35
|
+
- **Quieter digests**: routine updates (including snapshots) are delivered without waking an idle supervisor (2 min
|
|
36
|
+
quiet, 15 min max) and repeats of already-known states are dropped; assignment closures wake without interrupting
|
|
37
|
+
(30 s quiet, 5 min max); blockers, errors and urgent snapshots still wake and interrupt. A cleared error is still
|
|
38
|
+
reported, followed by the recovery. A member's session that disappears and comes back within one batch (a spoke
|
|
39
|
+
restart or reconnect) is not reported.
|
|
40
|
+
- **Master replacement** (`POST …/master {sessionID | launchID}`): explicit, fenced, with the next generation. Supervised
|
|
41
|
+
members move to the new master. No grants move.
|
|
42
|
+
|
|
43
|
+
### Panes and side chats
|
|
44
|
+
- **Split panes**: **Open beside** shows up to 4 sessions or artifacts side by side, stacked or in a grid. The focused
|
|
45
|
+
pane owns the composer and Voice. Layouts are per device. On phones the panes are tabs. `/api/events` takes
|
|
46
|
+
`sessions=a,b` for the visible panes.
|
|
47
|
+
- **Drag into panes**: drag a session (sidebar, Workspaces tree, Watchtower detail), an artifact (library) or a pane
|
|
48
|
+
(header grip) onto a pane: edges split side by side or stacked, the centre replaces, the layout reflows to a grid
|
|
49
|
+
when needed, and a fifth pane is refused with a notice. **Open in pane → left/right/top/bottom** in the session
|
|
50
|
+
menu is the keyboard equivalent. The layout switch is now a compact segmented control with icons.
|
|
51
|
+
- **Side chats**: **Start side chat…** copies a bounded snapshot of a session into a new session on the workspace's
|
|
52
|
+
host binding (any machine), in a pane beside it, with **Refresh** and a confirmed **Send to main**. Neither
|
|
53
|
+
interrupts a running turn.
|
|
54
|
+
|
|
55
|
+
### Agent profiles
|
|
56
|
+
- **Shared, versioned profiles** ([docs/profiles.md](docs/profiles.md)): instructions, skills and commands (with
|
|
57
|
+
`{{param}}`, `{{arguments}}` and spoke-side `{{secret:NAME}}`), immutable versions, and import from
|
|
58
|
+
`AGENTS.md`/`CLAUDE.md`, `skills/*/SKILL.md` and `commands/*.md`. You pin an exact version to a session at runtime
|
|
59
|
+
(the profile chip), to a launch (`agentProfile`) or to a team role. The **Agent profiles** page is the library.
|
|
60
|
+
**Ctrl+Alt+P** inserts a rendered command into the composer.
|
|
61
|
+
- **Per-harness application** through the new spoke feature `profileApply`, with honest acknowledgments (`applied`,
|
|
62
|
+
`partial`, `restart_required`, `unsupported`, `rejected`, `pending`): OpenCode (system prompt + `hub_profile`
|
|
63
|
+
tool), Claude Code (hook context, `set_model` in launched sessions), Codex (developer message + skill files);
|
|
64
|
+
presets are always `unsupported`. Local instructions win. No global harness config is written.
|
|
65
|
+
- **Profile metadata and usage**: optional `metadata` and `projects` on a profile, and **Used by**
|
|
66
|
+
(`GET /api/agent/profiles/:id/usage`, SDK `hub.profiles.usage()`, MCP `profile_usage`): pinned sessions with
|
|
67
|
+
requested vs running version and an explicit Upgrade, team roles, launches and workspaces, each shown only under the
|
|
68
|
+
caller's existing read rules (`hidden` names what was left out). The library rows show usage chips, with filters and
|
|
69
|
+
sort.
|
|
70
|
+
|
|
71
|
+
### Artifacts and AI
|
|
72
|
+
- **Persistent artifacts** ([docs/artifacts.md](docs/artifacts.md)): revisions of content-addressed blobs (files
|
|
73
|
+
standalone, chunked Postgres in a cluster), `private` or `workspace` visibility, archive and delete, staged uploads up
|
|
74
|
+
to 25 MiB, and downloads always served as attachments. New routes, SDK `hub.artifacts`, and `artifact_*` MCP tools.
|
|
75
|
+
- **Viewers and dashboards**: markdown, code, images, tables, charts, and declarative dashboards (schema v1, bindings
|
|
76
|
+
to other artifacts only, no URLs or scripts), plus a text editor with conflict-safe drafts.
|
|
77
|
+
- **AI jobs**: ask, propose an edit or run a declared action. The job runs on a handler you choose (a new launch or an
|
|
78
|
+
existing session), always with the requester's authority. Proposals apply only when you **Accept**. Jobs survive hub
|
|
79
|
+
restarts, and each job times out after 2 h.
|
|
80
|
+
- **Viewer redesign**: a header bar with kind icon, version picker (**Back to latest**), Copy, Download, Edit, Open in
|
|
81
|
+
pane and a details popover; content in a framed card (code with file/language header, line numbers, wrap; markdown
|
|
82
|
+
at reading width; dashboards and apps full-bleed); inline editing; and AI as a chat-style side panel (thread,
|
|
83
|
+
composer, Ask / Edit / Action or slash commands, compact handler picker that never preselects), resizable, a
|
|
84
|
+
bottom sheet on phones.
|
|
85
|
+
|
|
86
|
+
### Isolated artifact host
|
|
87
|
+
- Interactive `html`/`app` artifacts run only at `/artifact-host/v1/<capability>/…`: an opaque-origin sandbox with a
|
|
88
|
+
strict CSP, short-lived, viewer-bound and revocable capabilities, and a bridge (`resize`, `askAI`). Every `askAI`
|
|
89
|
+
becomes a consent card in the artifact's AI panel thread ([docs/artifact-host.md](docs/artifact-host.md)).
|
|
90
|
+
|
|
91
|
+
### Teams
|
|
92
|
+
- **Teams** ([docs/teams.md](docs/teams.md)): versioned definitions with roles, one entry role, `open` or `restricted`
|
|
93
|
+
communication paths (`one-way`/`two-way`, `msg`/`ask`), and a draft → publish flow. A session can belong to many
|
|
94
|
+
teams. The hub **enforces** the policy on delivery (`403 forbidden` with `extra.policy`). Team members cannot contact
|
|
95
|
+
sessions outside their teams unless a role has `externalContact`. Sessions in no team are unchanged.
|
|
96
|
+
- **Staffing** with existing or newly launched sessions under your grants (`403 needs_user` lists what is missing).
|
|
97
|
+
**Intake** gives work to the team's entry role and tracks it as an assignment ([docs/teams-intake.md](docs/teams-intake.md)).
|
|
98
|
+
- **Team addresses** `@@role#team` and `@@role.project#team` (quote `#` in shells). `/who`, `status` and `show` are
|
|
99
|
+
team-aware for team members.
|
|
100
|
+
- Malformed addresses answer `Not an address: use ses_…, @name, @@role or @@role#team` with a syntax-only hint (for
|
|
101
|
+
`@engineer#support`: `@@engineer#support` or `@engineer`); the hint never reveals whether a name exists.
|
|
102
|
+
- Entry-role sessions report and close their intake from the harness: OpenCode `hub` tool verbs `intake` and
|
|
103
|
+
`intake_update`, MCP `team_intake_update` (`expectedRevision` now optional). The intake message says how.
|
|
104
|
+
- **Teams page** (`/teams`, in the primary navigation): team cards (mode, entry role, seats, vacant roles, open work),
|
|
105
|
+
**New team** in a dialog, and per team **Members** (one block per role, **+ Add member** with a searchable session
|
|
106
|
+
picker that shows other memberships, **Launch new …**), **Work** (Submit a task, live intake status with links to
|
|
107
|
+
the entry session and its assignment), **Communication** and **Details** (draft → Review and publish, history),
|
|
108
|
+
Pause/Archive and **Edit in Watchtower**. The Watchtower's team panel uses the same components and links back.
|
|
109
|
+
- **Team isolation** (owner setting, default off): Settings → Teams, or `GET/PUT /api/agent/team-settings`
|
|
110
|
+
`{teamIsolation, expectedRevision}` (users only; SDK `hub.teams.settings()` / `setSettings()`). On: team members
|
|
111
|
+
see only their teams' sessions.
|
|
112
|
+
|
|
113
|
+
### Watchtower
|
|
114
|
+
- Renamed from **Bird's-eye view** (new lookout icon). `/birds-eye` links redirect to `/watchtower` with their
|
|
115
|
+
filters, and the browser's saved view and presets (`birdsEye.*`) move to `watchtower.*` once.
|
|
116
|
+
- A full-screen page ([docs/watchtower.md](docs/watchtower.md)) of machines, sessions, you, your apps and teams, with
|
|
117
|
+
live message flow: 3D (lazy `3d-force-graph`), a deterministic 2D canvas, or a list (also used for reduced motion).
|
|
118
|
+
It has URL-state filters and presets, team clusters, drawn vs actual paths and denied attempts, and a **team
|
|
119
|
+
editor** to assemble, staff, publish and submit work. New read API `GET /api/agent/graph` (+ `/edges/:id`,
|
|
120
|
+
`/nodes/:id`).
|
|
121
|
+
- Graph first: the controls are a floating **dock** at the bottom centre (view, Filters with an active count, Legend,
|
|
122
|
+
Teams, Hub details, Reset view, Pause motion, Search) that fades when idle. **Filters** is closed by default and
|
|
123
|
+
shows only the filters you add; active filters are removable chips over the canvas. The **Legend** has a visible
|
|
124
|
+
close and Escape closes it. On phones, filters, legend, details and the team editor are bottom sheets.
|
|
125
|
+
- A look in the style of Brain Graph (MIT, credited in the docs): glowing points in coloured group regions, fibers that
|
|
126
|
+
brighten towards the receiver, depth of field, labels on the most connected nodes, and a stable layout kept per
|
|
127
|
+
device (`watchtower.layout`). Flow pulses fade with message age and stop once nothing on a link is working or
|
|
128
|
+
pending. Rendering is on demand (none while still or hidden), and the 3D view draws in about 25 batched calls.
|
|
129
|
+
- Staffed seats are tied to their role by a tether and vacant roles are drawn hollow; the legend uses the same glyphs;
|
|
130
|
+
**More → Re-layout** clears the saved layout; the empty state sits below the hub core with **Connect a machine**.
|
|
131
|
+
|
|
132
|
+
### Navigation
|
|
133
|
+
- A primary navigation above the session groups: **All sessions**, **Artifacts** (a library across workspaces),
|
|
134
|
+
**Watchtower** and **Agent profiles**.
|
|
135
|
+
- **Settings sections**: General, Notifications, Voice & speech, Machines & devices, Agents & access, Teams and Admin,
|
|
136
|
+
each its own page `/settings/<section>` (deep links, back/forward; old `/settings#speech`-style links still work).
|
|
137
|
+
A section sidebar on desktop, a section list with drill-in on phones, and a **Search settings** box that jumps to a
|
|
138
|
+
setting and highlights it. Notification kinds are collapsed by group with an on/off summary; the device's push
|
|
139
|
+
status is one line with **Details**.
|
|
140
|
+
|
|
141
|
+
### Security hardening
|
|
142
|
+
- **Bounded request bodies** everywhere: agent JSON 1 MiB, profiles 4 MiB, console JSON 4 MiB, `/mcp` 1 MiB, staged
|
|
143
|
+
blobs 25 MiB, all read by a rate-budgeted streaming reader. Oversized bodies are refused with `Connection: close`.
|
|
144
|
+
**Set a front-proxy request-body limit (26 MiB)**: the k8s ingress example now uses `proxy-body-size: 26m` (it was
|
|
145
|
+
`16m`).
|
|
146
|
+
- A session seated in a team no longer sees sessions seated only in *other* teams: they are left out of `who`,
|
|
147
|
+
`status`, `show`, `log`, `/watch` and `/events`, and their addresses answer `404` like unknown ones. Sessions in no
|
|
148
|
+
team stay visible unless the owner turns on `teamIsolation` (Settings → Teams). Users, apps and team-less sessions
|
|
149
|
+
keep the owner-wide view.
|
|
150
|
+
- New app-token scopes `workspaces:*`, `profiles:*`, `artifacts:*` and `teams:*`. **Existing tokens gain nothing**,
|
|
151
|
+
and session tokens are refused on workspace routes.
|
|
152
|
+
- **Plain http only by opt-in**: `hub login` (device code, `--token` or a piped token) and `hub`/`hubctl machine enroll`
|
|
153
|
+
refuse plain http except on loopback, or with `--allow-insecure-http` for a private-network IP address (never a
|
|
154
|
+
host name), with a warning every time; nothing remembers the flag, and later commands using a stored plain-http
|
|
155
|
+
login warn on stderr. A loopback hub's approval link on this machine's LAN address is shown; other origins are
|
|
156
|
+
replaced with a warning.
|
|
157
|
+
|
|
158
|
+
### Fixes
|
|
159
|
+
- Counts pluralise correctly ("2 OpenCode processes", not "processs"); a team role's seat counter reads "1 of 2
|
|
160
|
+
required", "3 members · up to 16" or "full (16)" instead of "1 of 0–16".
|
|
161
|
+
- The artifact AI panel lists handler sessions by `@name` (searchable by name, title or ID) and names a handler picked
|
|
162
|
+
in the console by its `@name` instead of its session ID.
|
|
163
|
+
- The console's live stream opens at once when it resumes (the hub writes a first chunk immediately); before, it waited
|
|
164
|
+
for the 20 s heartbeat and **Reconnecting…** stayed up, across pages. Over plain http, Chrome still allows only 6
|
|
165
|
+
connections per host, so more than about 6 console tabs stall; https avoids this.
|
|
166
|
+
- The sidebar, Details rail and pane resize handles show their resize pointer again (a hidden character had broken
|
|
167
|
+
those CSS rules).
|
|
168
|
+
- `hub node` keeps OpenCode's background service warm (loopback only, every 30 s) so a freshly started service's
|
|
169
|
+
machine comes online without anyone opening a project (OpenCode has no server-start plugin hook).
|
|
170
|
+
- **Routine `wake: false` messages no longer cost an OpenCode session a turn** (routine digests, `--no-wake`
|
|
171
|
+
messages). OpenCode gives every queued inbox item its own model call once a turn ends, resume or not, so a
|
|
172
|
+
supervisor answered each routine digest in a turn of its own. The OpenCode spoke now admits every non-waking
|
|
173
|
+
message steered without resume, and refuses a routine one (a `wake: false` `msg` that is not urgent, to a top-level
|
|
174
|
+
session) while a turn runs: the hub keeps it `pending` and delivers it after the turn, so it reaches the model with
|
|
175
|
+
the next real turn, before its prompt (CLI and MCP say "pending (offline or busy; …)"). A waking message to the
|
|
176
|
+
same session sends the pending ones first (if the session is still busy, the waking one goes first, queued after
|
|
177
|
+
the turn). A flush stops at a session's first failed delivery, so a busy session costs one try per sessions frame.
|
|
178
|
+
Urgent
|
|
179
|
+
ones, asks, replies, primers and anything for a subagent still go into a running turn. Live check:
|
|
180
|
+
`HUB_IT_OPENCODE=1 bun test test/e2e-quiet-delivery.it.test.ts`.
|
|
181
|
+
- **Repeated blocks of one member no longer wake its supervisor each time**: blocked again for the same reason (same
|
|
182
|
+
blocker kind, or the same blocked/error state) within 15 min of a wake about it that the hub carried out, the
|
|
183
|
+
digest line is routine.
|
|
184
|
+
- **A run that fails at once shows as failed** (a model or provider that does not exist, auth, quota). OpenCode ends
|
|
185
|
+
such a run within ~50 ms of `session.created`, before the spoke's debounced sessions snapshot (500 ms), and the hub
|
|
186
|
+
keeps status only for sessions it was told about, so it dropped the failure and listed the session idle: no banner,
|
|
187
|
+
no "!" badge, not under Needs you, no `providerError` push (also in 0.7.3). The spoke now sends the snapshot first
|
|
188
|
+
when a run event is about a session the hub has not been told about yet (creating sessions alone still waits for the
|
|
189
|
+
debounce), and resends a failure once a snapshot lists its session if the session's details were still being
|
|
190
|
+
fetched when it failed. Live check: `HUB_IT_OPENCODE=1 bun test test/spoke-run-failure.it.test.ts`.
|
|
191
|
+
- **A session is never routed to another harness's spoke.** When no process owns a session and none of its
|
|
192
|
+
reporters is a service, the hub falls back to a background service on the reporter's machine; it took any service,
|
|
193
|
+
so an OpenCode session reported by a foreground `opencode serve` on a machine that also runs the Claude Code (or
|
|
194
|
+
Codex) service went to that service: "The claude-code spoke does not serve "timeline"" and `unsupported: summary`
|
|
195
|
+
(also in 0.7.3). The fallback now takes only a service of the session's own harness, else the reporter itself.
|
|
196
|
+
|
|
197
|
+
### Runtime
|
|
198
|
+
- **Bun 1.4.4**, pinned: the image (`oven/bun:1.4.4-slim` by digest, both stages), CI and release workflows, and
|
|
199
|
+
`engines.bun` (`>=1.4.4`). Bun 1.3.x's `Bun.SQL` auto-pipelining could stall a pooled Postgres connection under
|
|
200
|
+
concurrent writes (oven-sh/bun#33985; fixed in Bun 1.4.0 by oven-sh/bun#33627): a cluster pod's state queries then
|
|
201
|
+
never answered (the supervision IT's "many concurrent internal moves" hung or timed out in 3 of 15 runs on 1.3.5,
|
|
202
|
+
0 of 40 on 1.4.4).
|
|
203
|
+
- Cluster: the Postgres pools set `statement_timeout` (30 s by default, `HUB_DATABASE_STATEMENT_TIMEOUT_MS`, `0`
|
|
204
|
+
off), so a query stuck on the database fails with an error instead of holding its caller and connection.
|
|
205
|
+
- Bun 1.4 enforces the server's request ceiling on chunked bodies too; the ceiling now leaves 16 MiB above the
|
|
206
|
+
largest route bound, so an over-limit upload still gets the route's own `400`/`413` with `Connection: close`. Bun
|
|
207
|
+
1.4 then closes the socket instead of reading and discarding whatever the client keeps sending.
|
|
208
|
+
- The image build copies the protocol and SDK sources into the console stage, which imports them (without them
|
|
209
|
+
`docker build` failed in the console's `vite build`).
|
|
210
|
+
|
|
211
|
+
### Behavior notes
|
|
212
|
+
- New agent error code `conflict` (409, with `currentRevision`) for stale `expectedRevision`s and reused
|
|
213
|
+
`Idempotency-Key`s. The SDK `ErrorCode` includes it, and the CLI exits 3.
|
|
214
|
+
- The server's request ceiling rises from about 10 MiB to about 41 MiB (25 MiB blobs plus drain headroom). A JSON body
|
|
215
|
+
that was accepted before can now be refused as too large (by its route's bound).
|
|
216
|
+
- SDK `parseAddress` refuses `#` in a role's project scope (`@@role#team` is only ever team-resolved).
|
|
217
|
+
- Send to main and AI jobs handled by a session use normal delivery: they never interrupt a running turn. The first
|
|
218
|
+
message to an idle session right after the hub's primer may be delivered as steer.
|
|
219
|
+
- Cluster: schema v2 (`artifact-blobs`). Run `hub-server migrate` before rolling pods, and don't create restricted
|
|
220
|
+
teams while old and new pods are mixed.
|
|
221
|
+
|
|
222
|
+
## 0.7.4
|
|
223
|
+
|
|
224
|
+
Release downloads move to a public repository. The source repository is private now, so the standalone `hub`
|
|
225
|
+
binaries, `hubctl`, its signed manifest and the checksums are published to
|
|
226
|
+
[`huynle/hub-releases`](https://github.com/huynle/hub-releases) (the release workflow mirrors every release there,
|
|
227
|
+
byte for byte, so the signed manifest and checksums stay valid). The image `ghcr.io/huynle/hub` and the npm package
|
|
228
|
+
`@huynle/hub` are unchanged.
|
|
229
|
+
|
|
230
|
+
- **Install**: the README, the Ansible role README and the web shell hint use `huynle/hub-releases`; pass
|
|
231
|
+
`--release-url https://github.com/huynle/hub-releases/releases/download/v<version>` to `hubctl setup ansible`.
|
|
232
|
+
- **Plugin rename notice** no longer suggests installing from `github:huynle/hub`.
|
|
233
|
+
|
|
5
234
|
## 0.7.3
|
|
6
235
|
|
|
7
236
|
Session errors are visible: a quota, auth or rate-limit error in an OpenCode session now shows up in the hub.
|
package/Dockerfile
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
# Legacy VOICE_* variables still work, except that the HUB_HOST/HUB_PORT/HUB_STATE_DIR defaults below
|
|
8
8
|
# win over VOICE_HOST/VOICE_PORT/VOICE_STATE_DIR: rename those overrides to HUB_*.
|
|
9
9
|
# The console (web/, Solid + Vite) is built in its own stage; the image ships only web/dist.
|
|
10
|
+
# Bun is pinned (tag and multi-arch index digest) to 1.4.4: it has the Bun.SQL pipelining fix (oven-sh/bun#33627,
|
|
11
|
+
# in since 1.4.0; 1.3.x stalls pooled Postgres connections in cluster mode). Bump both stages together.
|
|
10
12
|
FROM node:22-slim AS web
|
|
11
13
|
WORKDIR /build
|
|
12
14
|
COPY package.json package-lock.json ./
|
|
@@ -24,9 +26,12 @@ COPY packages/preset/package.json ./packages/preset/
|
|
|
24
26
|
COPY packages/codex/package.json ./packages/codex/
|
|
25
27
|
RUN npm ci --no-audit --no-fund --ignore-scripts
|
|
26
28
|
COPY web ./web
|
|
29
|
+
# The console imports the protocol and SDK sources (web/src/… ../packages/{protocol,sdk}/src).
|
|
30
|
+
COPY packages/protocol/src ./packages/protocol/src
|
|
31
|
+
COPY packages/sdk/src ./packages/sdk/src
|
|
27
32
|
RUN npx vite build --config web/vite.config.ts
|
|
28
33
|
|
|
29
|
-
FROM oven/bun:1.
|
|
34
|
+
FROM oven/bun:1.4.4-slim@sha256:1846adf22496bd711036aae8be147e57bdebbaea2e5264e3e0b5af1db187d9a4 AS deps
|
|
30
35
|
WORKDIR /build
|
|
31
36
|
COPY package.json package-lock.json ./
|
|
32
37
|
COPY packages/protocol/package.json ./packages/protocol/
|
|
@@ -47,7 +52,7 @@ COPY docker/hub-deps.ts ./
|
|
|
47
52
|
# Keep only what the hub loads at runtime (the @opencode/* packages are for the plugin).
|
|
48
53
|
RUN bun hub-deps.ts /deps web-push
|
|
49
54
|
|
|
50
|
-
FROM oven/bun:1.
|
|
55
|
+
FROM oven/bun:1.4.4-slim@sha256:1846adf22496bd711036aae8be147e57bdebbaea2e5264e3e0b5af1db187d9a4
|
|
51
56
|
LABEL org.opencontainers.image.title="hub" \
|
|
52
57
|
org.opencontainers.image.description="Hub: a central hub for AI agent harnesses (OpenCode first): remote console, pairing, push and optional Voice" \
|
|
53
58
|
org.opencontainers.image.licenses="MIT" \
|