@huynle/hub 0.11.0 → 0.11.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 +26 -0
- package/README.md +19 -5
- package/package.json +1 -1
- package/packages/claude-code/package.json +1 -1
- package/packages/claude-code/src/sessions.ts +4 -1
- package/packages/cli/dist/hub-cli.js +240 -83
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/cli.ts +12 -7
- package/packages/cli/src/decisions.ts +52 -4
- package/packages/cli/src/format.ts +9 -0
- package/packages/cli/src/mcp.ts +20 -4
- package/packages/cli/src/team-intake-mcp.ts +2 -1
- package/packages/cli/src/teams-mcp.ts +7 -3
- package/packages/codex/package.json +1 -1
- package/packages/codex/src/sessions.ts +14 -3
- package/packages/node/package.json +1 -1
- package/packages/preset/package.json +1 -1
- package/packages/protocol/package.json +1 -1
- package/packages/protocol/schema/api/v1/_root.json +119 -0
- package/packages/protocol/schema/api/v1/account.json +419 -0
- package/packages/protocol/schema/api/v1/decisions.json +635 -0
- package/packages/protocol/schema/api/v1/discovery.json +110 -0
- package/packages/protocol/schema/api/v1/events.json +679 -0
- package/packages/protocol/schema/api/v1/session-actions.json +660 -0
- package/packages/protocol/schema/api/v1/sessions.json +2055 -0
- package/packages/protocol/schema/api/v1/speech.json +492 -0
- package/packages/protocol/schema/api/v1/unspecified.json +282 -0
- package/packages/protocol/schema/app-delivery/v1.schema.json +67 -5
- package/packages/protocol/schema/app-front/v1.schema.json +7 -3
- package/packages/protocol/src/api-v1.ts +8 -0
- package/packages/protocol/src/index.ts +2 -0
- package/packages/protocol/src/teams.ts +13 -1
- 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/app-front.ts +2 -2
- package/packages/sdk/src/ask-fields.ts +76 -0
- package/packages/sdk/src/client.ts +11 -2
- package/packages/sdk/src/envelope.ts +3 -2
- package/packages/sdk/src/index.ts +1 -0
- package/packages/sdk/src/team-intake.ts +6 -0
- package/packages/sdk/src/teams.ts +2 -0
- package/packages/sdk/src/types.ts +36 -4
- package/packages/sdk/src/wake.ts +9 -4
- package/packages/spoke-sdk/package.json +1 -1
- package/src/central/agent/agent-limits.ts +185 -0
- package/src/central/agent/app-decisions.ts +6 -5
- package/src/central/agent/decisions.ts +130 -9
- package/src/central/agent/delivery.ts +134 -22
- package/src/central/agent/errors.ts +2 -1
- package/src/central/agent/events.ts +20 -2
- package/src/central/agent/launch-engine.ts +6 -3
- package/src/central/agent/message-limits.ts +5 -2
- package/src/central/agent/message-routes.ts +33 -6
- package/src/central/agent/messages.ts +7 -0
- package/src/central/agent/placement.ts +4 -2
- package/src/central/agent/read-routes.ts +5 -0
- package/src/central/agent/routes.ts +2 -0
- package/src/central/agent/subscriptions.ts +13 -4
- package/src/central/api-v1.ts +115 -0
- package/src/central/artifacts/store.ts +4 -2
- package/src/central/concierge/board-results.ts +2 -1
- package/src/central/concierge/notifier.ts +4 -2
- package/src/central/config.ts +20 -6
- package/src/central/health/classify.ts +209 -0
- package/src/central/http.ts +285 -23
- package/src/central/recording/index.ts +2 -1
- package/src/central/recording/schema.ts +2 -1
- package/src/central/registry.ts +34 -3
- package/src/central/teams/budgets.ts +144 -0
- package/src/central/teams/hop-stalls.ts +14 -6
- package/src/central/teams/intake.ts +38 -6
- package/src/central/teams/involvement.ts +95 -0
- package/src/central/teams/item-decisions.ts +60 -0
- package/src/central/teams/item-eligibility.ts +35 -0
- package/src/central/teams/item-stalls.ts +87 -0
- package/src/central/teams/loops.ts +40 -0
- package/src/central/teams/progress.ts +154 -0
- package/src/central/teams/routes.ts +2 -2
- package/src/central/teams/store.ts +21 -5
- package/src/central/teams/validation.ts +17 -6
- package/src/central/workspaces/coordinator.ts +3 -1
- package/src/spoke/hub-tool.ts +26 -11
- package/web/dist/assets/{ArtifactPage-C5MMqXLN.js → ArtifactPage-TbFJi59n.js} +1 -1
- package/web/dist/assets/{ArtifactPane-CXSCmhyJ.js → ArtifactPane-7D-M-Ich.js} +1 -1
- package/web/dist/assets/{ArtifactWorkbench-S0RxNGWy.js → ArtifactWorkbench-DlCLEjut.js} +1 -1
- package/web/dist/assets/{Diagram-BGmyRb-R.js → Diagram-PvOPetOI.js} +1 -1
- package/web/dist/assets/{Library-CFmMbXEa.js → Library-Cdi83pOV.js} +2 -2
- package/web/dist/assets/{ProfilesDestination-7jpOc2HM.js → ProfilesDestination-cryC7P6j.js} +1 -1
- package/web/dist/assets/TeamsPage-B4xrlGhp.js +1 -0
- package/web/dist/assets/Watchtower-60B1JX_J.js +2 -0
- package/web/dist/assets/index-DA0gKIzv.js +33 -0
- package/web/dist/assets/live-B2IfKm37.js +5 -0
- package/web/dist/assets/{live-BUofsQpz.css → live-De-kd3eW.css} +1 -1
- package/web/dist/assets/{renderer2d-B2Nh39UN.js → renderer2d-CsZnF3_o.js} +1 -1
- package/web/dist/assets/{renderer3d-CTYbljHH.js → renderer3d-BIMA0wFn.js} +2 -2
- package/web/dist/assets/{safe-area-CkhEclGo.js → safe-area-dtrnw9NF.js} +1 -1
- package/web/dist/index.html +1 -1
- package/web/dist/assets/TeamsPage-C1NGrUR-.js +0 -1
- package/web/dist/assets/Watchtower-DnvlJaU0.js +0 -2
- package/web/dist/assets/index-Da8SKXMw.js +0 -33
- package/web/dist/assets/live-BmqLASSo.js +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.1
|
|
4
|
+
|
|
5
|
+
Agents can send structured asks to `@me` (choices, kind, recommendation) from the OpenCode `hub` tool, MCP, the SDK
|
|
6
|
+
and the CLI, and teams tag work items. Also since 0.11.0: team autonomy phase 2 (per-item wake budgets with an
|
|
7
|
+
Extend/Stop Decision, loop detection, progress resets), session health on session reads, a configurable hub hop
|
|
8
|
+
ceiling, the team Renew button, live agent-limit pins and a startup retry, and typed wake-skip limits. Update the
|
|
9
|
+
plugin (npm `@huynle/hub`) and restart OpenCode to get the new hub tool.
|
|
10
|
+
|
|
11
|
+
- Teams: each team card and team page shows `hops N/limit`, a `stalled: hop cap` badge and a **Renew** button that
|
|
12
|
+
resets every current seat's hop depth and closes an open Renew Decision (console cookie only, audited as
|
|
13
|
+
`team.hops.reset` kind `manual`); `GET /api/teams/:id/hops` reads the depths.
|
|
14
|
+
- Agents can send structured asks to `@me`: the OpenCode `hub` tool and the MCP `ask` tool take `options`,
|
|
15
|
+
`recommendation`, `urgency`, `tier`, `kind` and `choices`; the SDK's `AskOptions` take `choices` and `kind` (and
|
|
16
|
+
`answerDecision` takes `picks`); the CLI adds `hub ask @me --choice "D1=Label:a=Option*,b=Option" --kind plan`.
|
|
17
|
+
- Decisions: an ask to `@me` may carry structured `choices` (1–12 groups of 2–6 options, at most one recommended
|
|
18
|
+
per group; not with `options`) and a `kind` (question, plan, merge, release). The user answers with `picks`, one
|
|
19
|
+
option per group, or with text alone; the asker reads one `D1: label [a]` line per group. The API schemas and the
|
|
20
|
+
recording events `decision.answered` and `decision.voice` carry the picks.
|
|
21
|
+
- Hub text sanitising (message text, labels, Decision questions and choices) now also removes every Unicode format
|
|
22
|
+
character (`\p{Cf}`), including TAG characters (U+E0000–E007F) and the soft hyphen. Side effect: emoji built
|
|
23
|
+
from tag sequences, such as the England and Scotland flags, show as a plain black flag. Zero-width joiners and
|
|
24
|
+
directional marks (U+200B–200F) were already removed, so compound emoji split up and RTL marks are dropped in
|
|
25
|
+
labels as before.
|
|
26
|
+
- Wake-skip replies now carry `wakeLimit` for the effective team/hub hop cap or recipient wake budget. The CLI, MCP
|
|
27
|
+
tools and OpenCode hub tool show that number instead of a fixed default; older hubs show a number-free reason.
|
|
28
|
+
|
|
3
29
|
## 0.11.0
|
|
4
30
|
|
|
5
31
|
Voice recording's Developer mode and the richer `capture.v2` recording events (below), plus the fixes and team
|
package/README.md
CHANGED
|
@@ -88,6 +88,9 @@ Formerly **opencode-voice** and, briefly, **opencode-hub**
|
|
|
88
88
|
mode), staffed with sessions from any machine. The console's **Teams** page lists them and shows each team's
|
|
89
89
|
members, work (live intake status) and communication ([docs/teams.md](docs/teams.md),
|
|
90
90
|
[intake](docs/teams-intake.md)).
|
|
91
|
+
Team members can attach an open intake item to a message with `hub msg|ask --item itk_…`, MCP `msg`/`ask`'s `item`,
|
|
92
|
+
or the OpenCode hub tool's `item`. Both endpoints must hold current seats in that item's team; replies inherit it
|
|
93
|
+
while the item stays open.
|
|
91
94
|
- **Watchtower** (formerly Bird's-eye view): a 3D, 2D or list picture of machines, sessions, teams and live
|
|
92
95
|
message flow, with a team editor ([docs/watchtower.md](docs/watchtower.md)).
|
|
93
96
|
- **Media in sessions**: tool screenshots, attachments and image files a reply names show in the transcript (with a
|
|
@@ -611,6 +614,13 @@ hand-made token: `GET /connect/authorize` (PKCE S256) → the hub's consent page
|
|
|
611
614
|
`POST /connect/token` → a 1-hour `hca_` access token and a rotating `hcr_` refresh token; `POST /connect/revoke` ends
|
|
612
615
|
it. Clients are registered in Settings → Agents & access. See [docs/app-front.md](docs/app-front.md#connect-an-app).
|
|
613
616
|
|
|
617
|
+
An administrator can adjust the hub-wide hop cap, its ceiling (`agents.hopCeiling`, default 100, at most 10,000; a
|
|
618
|
+
raise asks for confirmation), launch limits, per-item wake/time budgets and no-progress loop threshold under
|
|
619
|
+
**Settings → Admin → Agent limits** without restarting the hub. `hub.json` remains each limit group's default until a console value changes it; the UI shows each source separately. Agents may read the effective
|
|
620
|
+
limits with `hub mcp` tool `agent_limits` but cannot change them; see [team hop limits](docs/teams-intake.md#team-message-hop-cap-and-renew)
|
|
621
|
+
and [per-item budgets and progress](docs/teams-intake.md#per-item-budgets-attribution-and-progress), plus
|
|
622
|
+
[launch caps](docs/launches.md#how-the-caps-count).
|
|
623
|
+
|
|
614
624
|
**Hub as an app's AI layer (app front).** A web app can use Hub as its AI layer for its users: connect (above), launch
|
|
615
625
|
helper sessions, follow and talk to them (a conversation stream, voice turns through the voice front), speak and
|
|
616
626
|
transcribe with the user's own speech provider, and answer the everyday confirm-tier Decisions its own sessions ask.
|
|
@@ -705,16 +715,19 @@ sessions or apps; see [Decisions and `@me`](#agent-identity-agent-api) for the r
|
|
|
705
715
|
|
|
706
716
|
**Limits.** Per 10 minutes: 20 messages per sender→recipient pair and 300 per user (`rate_limited`, exit 6, with
|
|
707
717
|
`retryAfter`), and 30 turns started per recipient (more messages are still delivered, without waking it). A chain of
|
|
708
|
-
messages between sessions may run
|
|
718
|
+
messages between sessions may run up to the hub's configured hop limit (`agents.hopLimit` in Settings → Admin,
|
|
719
|
+
default 8, at most the hop ceiling; a team's
|
|
720
|
+
limit may be lower) without a human turn; past that, messages are delivered without waking and
|
|
709
721
|
you are notified once. Typing into a session (console, Voice, the harness) starts its chain over. Apps (an app
|
|
710
722
|
token, and the hub's own Concierge, workspace coordinator and team intake) count hops per conversation: a new `msg`
|
|
711
723
|
or `ask` from an app starts at hop 1 and replies to an app do not count against it, so an app's 5th (or 50th) ask
|
|
712
724
|
still wakes the session it talks to. Two guards keep apps from restarting chains: a reply or decline counts up from
|
|
713
725
|
the message it answers (reply ping-pong through an app is capped like any other chain), and for 5 minutes after a
|
|
714
726
|
session sends an app something, the app's new messages to *other* sessions continue from that hop (a relay A → app →
|
|
715
|
-
B → app → A reaches the cap
|
|
727
|
+
B → app → A reaches the configured cap; spaced-out work starts at hop 1 again). An app answering one session
|
|
716
728
|
with new messages forever is held by the pair limit and the wake budget. A team intake submitted by a session
|
|
717
|
-
continues that session's chain. A send's answer says when and why it did not wake (`woke`, `wakeSkipped
|
|
729
|
+
continues that session's chain. A send's answer says when and why it did not wake (`woke`, `wakeSkipped`, and
|
|
730
|
+
`wakeLimit` for the effective hop or wake budget); the CLI,
|
|
718
731
|
`hub mcp` and the OpenCode `hub` tool print it.
|
|
719
732
|
|
|
720
733
|
**Never give agents an app token.** A session that holds one (in its environment, an MCP config, a gateway) can send
|
|
@@ -932,12 +945,13 @@ hub name <@name> [--session <addr>]
|
|
|
932
945
|
hub intent <addr> [text… | --clear] what the session is for (one line, ≤ 280 characters)
|
|
933
946
|
hub role claim <role[.project]> [--exclusive] [--session <addr>]
|
|
934
947
|
hub role release <role[.project]> [--session <addr>]
|
|
935
|
-
hub msg <addr> "text" [--all] [--no-wake] [--urgent] [--key K] tell: fire and forget
|
|
936
|
-
hub ask <addr> "text" [--wait [secs]] [--expires 2h] [--all] [--no-wake] [--urgent] [--key K]
|
|
948
|
+
hub msg <addr> "text" [--all] [--no-wake] [--urgent] [--item itk_…] [--key K] tell: fire and forget
|
|
949
|
+
hub ask <addr> "text" [--wait [secs]] [--expires 2h] [--all] [--no-wake] [--urgent] [--item itk_…] [--key K]
|
|
937
950
|
hub reply <msgID> "text" [--no-wake] to the message's real sender, never via the role
|
|
938
951
|
hub decline <msgID> --why "reason"
|
|
939
952
|
hub ask @me "question" [--option id=label[:safe]]... [--recommend id [--why "…"]] [--urgency low|normal|high]
|
|
940
953
|
[--deadline 2h [--on-timeout <safe id>]] [--tier confirm|tap] [--about <addr>]... a Decision for the user
|
|
954
|
+
[--choice "D1=Label:a=Option*,b=Option"]... [--kind question|plan|merge|release] several points (* recommended)
|
|
941
955
|
hub decisions list [--state open|answered|expired|closed] the Decisions you asked
|
|
942
956
|
hub inbox asks to answer, your open asks, recent messages, mutes
|
|
943
957
|
hub mute <addr> · hub unmute <addr> refuse (or accept again) messages from a session
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huynle/hub",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
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.11.
|
|
3
|
+
"version": "0.11.1",
|
|
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",
|
|
@@ -470,9 +470,12 @@ export class ClaudeSessions {
|
|
|
470
470
|
this.#settle(s, undefined, true)
|
|
471
471
|
s.stopRequested = false
|
|
472
472
|
const detail = [input.error_details, input.error].find((v): v is string => typeof v === "string" && v.length > 0) ?? "the turn failed"
|
|
473
|
+
// (SS-9) The StopFailure error type (rate_limit, billing_error, authentication_failed, …) as error.type
|
|
474
|
+
// "claude.<token>", so the hub classifies a typed error instead of guessing from the text. Only a token-shaped value.
|
|
475
|
+
const token = typeof input.error === "string" && /^[a-z][a-z0-9_]{0,40}$/.test(input.error) ? input.error : undefined
|
|
473
476
|
const turnID = s.turnID
|
|
474
477
|
s.busy = false
|
|
475
|
-
this.#emit({ type: "session.execution.failed", data: { sessionID: s.hubID, ...(turnID ? { turnID } : {}), error: { message: cut(detail, HARNESS_ERROR_MAX) } } })
|
|
478
|
+
this.#emit({ type: "session.execution.failed", data: { sessionID: s.hubID, ...(turnID ? { turnID } : {}), error: { message: cut(detail, HARNESS_ERROR_MAX), ...(token ? { type: `claude.${token}` } : {}) } } })
|
|
476
479
|
return {}
|
|
477
480
|
}
|
|
478
481
|
|