@huynle/hub 0.6.1 → 0.7.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 +870 -0
- package/Dockerfile +33 -0
- package/README.md +1007 -66
- package/package.json +47 -2
- package/packages/claude-code/package.json +12 -0
- package/packages/claude-code/src/bridge.ts +79 -0
- package/packages/claude-code/src/daemon.ts +339 -0
- package/packages/claude-code/src/hook-input.ts +44 -0
- package/packages/claude-code/src/ids.ts +27 -0
- package/packages/claude-code/src/index.ts +18 -0
- package/packages/claude-code/src/launcher.ts +265 -0
- package/packages/claude-code/src/main.ts +127 -0
- package/packages/claude-code/src/mcp.ts +109 -0
- package/packages/claude-code/src/paths.ts +34 -0
- package/packages/claude-code/src/plugin.ts +99 -0
- package/packages/claude-code/src/references.ts +51 -0
- package/packages/claude-code/src/sessions.ts +600 -0
- package/packages/claude-code/src/tools.ts +66 -0
- package/packages/claude-code/src/wire.ts +71 -0
- package/packages/claude-code/src/wrapper.ts +156 -0
- package/packages/cli/dist/hub-cli.js +21647 -0
- package/packages/cli/package.json +11 -0
- package/packages/cli/src/acting.ts +70 -0
- package/packages/cli/src/args.ts +91 -0
- package/packages/cli/src/bootstrap/adapters/archive-stream.ts +276 -0
- package/packages/cli/src/bootstrap/adapters/claude/README.md +63 -0
- package/packages/cli/src/bootstrap/adapters/claude/adapter.ts +250 -0
- package/packages/cli/src/bootstrap/adapters/claude/index.ts +42 -0
- package/packages/cli/src/bootstrap/adapters/claude/node.ts +99 -0
- package/packages/cli/src/bootstrap/adapters/claude/openpgp.ts +221 -0
- package/packages/cli/src/bootstrap/adapters/claude/ports.ts +44 -0
- package/packages/cli/src/bootstrap/adapters/claude/source.ts +160 -0
- package/packages/cli/src/bootstrap/adapters/claude/verify.ts +165 -0
- package/packages/cli/src/bootstrap/adapters/codex/archive.ts +103 -0
- package/packages/cli/src/bootstrap/adapters/codex/index.ts +60 -0
- package/packages/cli/src/bootstrap/adapters/codex/plan.ts +129 -0
- package/packages/cli/src/bootstrap/adapters/codex/sigstore.ts +298 -0
- package/packages/cli/src/bootstrap/adapters/codex/source.ts +102 -0
- package/packages/cli/src/bootstrap/adapters/codex/verify.ts +298 -0
- package/packages/cli/src/bootstrap/adapters/inflate.ts +433 -0
- package/packages/cli/src/bootstrap/adapters/node-services/control.ts +392 -0
- package/packages/cli/src/bootstrap/adapters/node-services/index.ts +23 -0
- package/packages/cli/src/bootstrap/adapters/node-services/launch.ts +223 -0
- package/packages/cli/src/bootstrap/adapters/node-services/plan.ts +222 -0
- package/packages/cli/src/bootstrap/adapters/node-services/render.ts +183 -0
- package/packages/cli/src/bootstrap/adapters/node-services/validate.ts +197 -0
- package/packages/cli/src/bootstrap/adapters/opencode/README.md +204 -0
- package/packages/cli/src/bootstrap/adapters/opencode/apply.ts +205 -0
- package/packages/cli/src/bootstrap/adapters/opencode/archive.ts +91 -0
- package/packages/cli/src/bootstrap/adapters/opencode/config.ts +212 -0
- package/packages/cli/src/bootstrap/adapters/opencode/index.ts +81 -0
- package/packages/cli/src/bootstrap/adapters/opencode/plan.ts +266 -0
- package/packages/cli/src/bootstrap/adapters/opencode/verify.ts +208 -0
- package/packages/cli/src/bootstrap/adapters/readiness.ts +19 -0
- package/packages/cli/src/bootstrap/ansible/index.ts +2 -0
- package/packages/cli/src/bootstrap/ansible/render.ts +279 -0
- package/packages/cli/src/bootstrap/contracts/actions.ts +470 -0
- package/packages/cli/src/bootstrap/contracts/artifact.ts +323 -0
- package/packages/cli/src/bootstrap/contracts/canonical.ts +54 -0
- package/packages/cli/src/bootstrap/contracts/credentials.ts +108 -0
- package/packages/cli/src/bootstrap/contracts/discovery.ts +215 -0
- package/packages/cli/src/bootstrap/contracts/envelope.ts +143 -0
- package/packages/cli/src/bootstrap/contracts/exec.ts +74 -0
- package/packages/cli/src/bootstrap/contracts/harness.ts +202 -0
- package/packages/cli/src/bootstrap/contracts/index.ts +28 -0
- package/packages/cli/src/bootstrap/contracts/journal.ts +198 -0
- package/packages/cli/src/bootstrap/contracts/paths.ts +91 -0
- package/packages/cli/src/bootstrap/contracts/plan.ts +155 -0
- package/packages/cli/src/bootstrap/contracts/platform.ts +62 -0
- package/packages/cli/src/bootstrap/contracts/preview.ts +190 -0
- package/packages/cli/src/bootstrap/contracts/profile.ts +105 -0
- package/packages/cli/src/bootstrap/contracts/secrets.ts +52 -0
- package/packages/cli/src/bootstrap/contracts/validate.ts +212 -0
- package/packages/cli/src/bootstrap/discovery/discover.ts +146 -0
- package/packages/cli/src/bootstrap/discovery/executables.ts +134 -0
- package/packages/cli/src/bootstrap/discovery/host.ts +96 -0
- package/packages/cli/src/bootstrap/discovery/index.ts +6 -0
- package/packages/cli/src/bootstrap/discovery/node-probe.ts +97 -0
- package/packages/cli/src/bootstrap/discovery/probe.ts +41 -0
- package/packages/cli/src/bootstrap/discovery/util.ts +13 -0
- package/packages/cli/src/bootstrap/enrollment/enroll.ts +226 -0
- package/packages/cli/src/bootstrap/enrollment/index.ts +7 -0
- package/packages/cli/src/bootstrap/enrollment/policy.ts +54 -0
- package/packages/cli/src/bootstrap/enrollment/result.ts +63 -0
- package/packages/cli/src/bootstrap/enrollment/status.ts +119 -0
- package/packages/cli/src/bootstrap/enrollment/store.ts +173 -0
- package/packages/cli/src/bootstrap/preview/index.ts +5 -0
- package/packages/cli/src/bootstrap/preview/links.ts +31 -0
- package/packages/cli/src/bootstrap/preview/plan.ts +242 -0
- package/packages/cli/src/bootstrap/preview/preview.ts +104 -0
- package/packages/cli/src/bootstrap/preview/render.ts +30 -0
- package/packages/cli/src/bootstrap/profiles/audit.ts +87 -0
- package/packages/cli/src/bootstrap/profiles/catalog.ts +49 -0
- package/packages/cli/src/bootstrap/profiles/desired.ts +96 -0
- package/packages/cli/src/bootstrap/profiles/drift.ts +286 -0
- package/packages/cli/src/bootstrap/profiles/history.ts +263 -0
- package/packages/cli/src/bootstrap/profiles/index.ts +11 -0
- package/packages/cli/src/bootstrap/profiles/upgrade.ts +276 -0
- package/packages/cli/src/bootstrap/profiles/versions.ts +50 -0
- package/packages/cli/src/bootstrap/release/README.md +115 -0
- package/packages/cli/src/bootstrap/release/assets.ts +39 -0
- package/packages/cli/src/bootstrap/release/cli.ts +332 -0
- package/packages/cli/src/bootstrap/release/harness-pins.json +94 -0
- package/packages/cli/src/bootstrap/release/manifest.ts +118 -0
- package/packages/cli/src/bootstrap/release/pins.ts +192 -0
- package/packages/cli/src/bootstrap/release/text-assets.d.ts +9 -0
- package/packages/cli/src/bootstrap/release/trust-root.json +13 -0
- package/packages/cli/src/bootstrap/release/trust-root.ts +39 -0
- package/packages/cli/src/bootstrap/release/verify.ts +88 -0
- package/packages/cli/src/bootstrap/transaction/builtin.ts +312 -0
- package/packages/cli/src/bootstrap/transaction/engine.ts +994 -0
- package/packages/cli/src/bootstrap/transaction/executor.ts +112 -0
- package/packages/cli/src/bootstrap/transaction/fs.ts +194 -0
- package/packages/cli/src/bootstrap/transaction/index.ts +12 -0
- package/packages/cli/src/bootstrap/transaction/json-merge.ts +403 -0
- package/packages/cli/src/bootstrap/transaction/lock.ts +132 -0
- package/packages/cli/src/bootstrap/transaction/resolve.ts +48 -0
- package/packages/cli/src/bootstrap/transaction/result.ts +60 -0
- package/packages/cli/src/bootstrap/transaction/state.ts +88 -0
- package/packages/cli/src/bootstrap/transaction/store.ts +189 -0
- package/packages/cli/src/bootstrap/transaction/stream.ts +254 -0
- package/packages/cli/src/cli.ts +814 -0
- package/packages/cli/src/credentials.ts +75 -0
- package/packages/cli/src/decisions.ts +106 -0
- package/packages/cli/src/format.ts +185 -0
- package/packages/cli/src/grants.ts +105 -0
- package/packages/cli/src/http.ts +86 -0
- package/packages/cli/src/launches.ts +157 -0
- package/packages/cli/src/login.ts +160 -0
- package/packages/cli/src/main.ts +63 -0
- package/packages/cli/src/mcp.ts +879 -0
- package/packages/cli/src/messaging.ts +108 -0
- package/packages/cli/src/node.ts +279 -0
- package/packages/cli/src/openshell.ts +166 -0
- package/packages/cli/src/setup/commands.ts +809 -0
- package/packages/cli/src/setup/contributors.ts +171 -0
- package/packages/cli/src/setup/dispatch.ts +74 -0
- package/packages/cli/src/setup/launch-driver.ts +109 -0
- package/packages/cli/src/setup/runtime.ts +456 -0
- package/packages/cli/src/setup/spoke-probe.ts +120 -0
- package/packages/cli/src/setup/state.ts +244 -0
- package/packages/cli/src/setup/user-bin.ts +39 -0
- package/packages/cli/src/spoke-services.ts +109 -0
- package/packages/cli/src/watch.ts +28 -0
- package/packages/codex/package.json +12 -0
- package/packages/codex/src/app-server.ts +44 -0
- package/packages/codex/src/ids.ts +28 -0
- package/packages/codex/src/index.ts +11 -0
- package/packages/codex/src/jsonrpc.ts +168 -0
- package/packages/codex/src/main.ts +123 -0
- package/packages/codex/src/paths.ts +65 -0
- package/packages/codex/src/sessions.ts +578 -0
- package/packages/codex/src/spoke.ts +252 -0
- package/packages/codex/src/stdio.ts +101 -0
- package/packages/codex/src/websocket.ts +206 -0
- package/packages/codex/src/wrapper.ts +104 -0
- package/packages/node/package.json +12 -0
- package/packages/node/src/config.ts +184 -0
- package/packages/node/src/connection.ts +283 -0
- package/packages/node/src/daemon.ts +281 -0
- package/packages/node/src/git.ts +107 -0
- package/packages/node/src/harnesses.ts +95 -0
- package/packages/node/src/host.ts +319 -0
- package/packages/node/src/index.ts +17 -0
- package/packages/node/src/main.ts +11 -0
- package/packages/node/src/openshell.ts +73 -0
- package/packages/node/src/run.ts +106 -0
- package/packages/preset/package.json +12 -0
- package/packages/preset/presets/aider.json +8 -0
- package/packages/preset/presets/goose.json +8 -0
- package/packages/preset/src/index.ts +2 -0
- package/packages/preset/src/main.ts +195 -0
- package/packages/preset/src/presets.ts +87 -0
- package/packages/preset/src/spoke.ts +251 -0
- package/packages/preset/src/tmux.ts +160 -0
- package/packages/protocol/package.json +12 -0
- package/packages/protocol/src/harness-events.ts +207 -0
- package/packages/protocol/src/index.ts +1215 -0
- package/packages/protocol/src/launch.ts +172 -0
- package/packages/protocol/src/node.ts +409 -0
- package/packages/protocol/src/preset.ts +144 -0
- package/packages/protocol/src/webhook.ts +62 -0
- package/packages/protocol/src/wire.ts +54 -0
- package/packages/runtime-openshell/image/Dockerfile +36 -0
- package/packages/runtime-openshell/image/README.md +78 -0
- package/packages/runtime-openshell/image/build.ts +203 -0
- package/packages/runtime-openshell/image/entry.sh +163 -0
- package/packages/runtime-openshell/image/image.ts +119 -0
- package/packages/runtime-openshell/image/start.sh +24 -0
- package/packages/runtime-openshell/package.json +12 -0
- package/packages/runtime-openshell/src/cli.ts +584 -0
- package/packages/runtime-openshell/src/index.ts +6 -0
- package/packages/runtime-openshell/src/policy.ts +155 -0
- package/packages/runtime-openshell/src/profiles.ts +181 -0
- package/packages/runtime-openshell/src/runtime.ts +475 -0
- package/packages/runtime-sdk/package.json +12 -0
- package/packages/runtime-sdk/src/index.ts +87 -0
- package/packages/sdk/package.json +12 -0
- package/packages/sdk/src/address.ts +25 -0
- package/packages/sdk/src/client.ts +553 -0
- package/packages/sdk/src/envelope.ts +108 -0
- package/packages/sdk/src/errors.ts +107 -0
- package/packages/sdk/src/index.ts +10 -0
- package/packages/sdk/src/sse.ts +70 -0
- package/packages/sdk/src/types.ts +517 -0
- package/packages/sdk/src/webhook.ts +102 -0
- package/packages/spoke-sdk/package.json +12 -0
- package/packages/spoke-sdk/src/activity.ts +3 -0
- package/packages/spoke-sdk/src/connection.ts +295 -0
- package/packages/spoke-sdk/src/delivery.ts +119 -0
- package/packages/spoke-sdk/src/enroll.ts +101 -0
- package/packages/spoke-sdk/src/harness-hello.ts +79 -0
- package/packages/spoke-sdk/src/harness-spoke.ts +263 -0
- package/packages/spoke-sdk/src/index.ts +12 -0
- package/packages/spoke-sdk/src/prompt-refs.ts +154 -0
- package/packages/spoke-sdk/src/prompt-source.ts +8 -0
- package/packages/spoke-sdk/src/session-ids.ts +49 -0
- package/packages/spoke-sdk/src/session-tokens.ts +78 -0
- package/scripts/hub-claude-code.service +34 -0
- package/scripts/hub-codex-spoke.service +34 -0
- package/scripts/hub-node.service +35 -0
- package/scripts/io.github.huynle.hub-claude-code.plist +53 -0
- package/scripts/io.github.huynle.hub-codex-spoke.plist +53 -0
- package/scripts/io.github.huynle.hub-node.plist +52 -0
- package/src/central/actions.ts +233 -0
- package/src/central/agent/acting-routes.ts +133 -0
- package/src/central/agent/acting-switch.ts +93 -0
- package/src/central/agent/acting.ts +599 -0
- package/src/central/agent/actor.ts +193 -0
- package/src/central/agent/app-tokens.ts +152 -0
- package/src/central/agent/archive-inactive.ts +66 -0
- package/src/central/agent/audit.ts +185 -0
- package/src/central/agent/decisions.ts +530 -0
- package/src/central/agent/delivery.ts +678 -0
- package/src/central/agent/directory-routes.ts +328 -0
- package/src/central/agent/directory.ts +473 -0
- package/src/central/agent/envelope.ts +51 -0
- package/src/central/agent/errors.ts +74 -0
- package/src/central/agent/escalation.ts +219 -0
- package/src/central/agent/event-cursor.ts +49 -0
- package/src/central/agent/event-writers.ts +181 -0
- package/src/central/agent/events-routes.ts +148 -0
- package/src/central/agent/events.ts +277 -0
- package/src/central/agent/grant-requests.ts +221 -0
- package/src/central/agent/grant-routes.ts +70 -0
- package/src/central/agent/grants.ts +235 -0
- package/src/central/agent/launch-engine.ts +1025 -0
- package/src/central/agent/launch-routes.ts +252 -0
- package/src/central/agent/launch-spec.ts +289 -0
- package/src/central/agent/launch-store.ts +264 -0
- package/src/central/agent/launch-tokens.ts +206 -0
- package/src/central/agent/message-limits.ts +123 -0
- package/src/central/agent/message-routes.ts +385 -0
- package/src/central/agent/messages.ts +442 -0
- package/src/central/agent/names.ts +86 -0
- package/src/central/agent/placement.ts +419 -0
- package/src/central/agent/policy.ts +378 -0
- package/src/central/agent/read-routes.ts +385 -0
- package/src/central/agent/routes.ts +281 -0
- package/src/central/agent/session-tokens.ts +227 -0
- package/src/central/agent/versioned.ts +26 -0
- package/src/central/agent/watch.ts +112 -0
- package/src/central/agent/webhook-routes.ts +86 -0
- package/src/central/agent/webhooks.ts +493 -0
- package/src/central/agent-data.ts +177 -0
- package/src/central/auth.ts +350 -121
- package/src/central/backend/file-state.ts +240 -0
- package/src/central/backend/index.ts +116 -0
- package/src/central/backend/memory-bus.ts +93 -0
- package/src/central/backend/memory-catalog.ts +90 -0
- package/src/central/backend/memory-counters.ts +102 -0
- package/src/central/backend/memory-events.ts +45 -0
- package/src/central/backend/memory-kv.ts +38 -0
- package/src/central/backend/memory-state.ts +77 -0
- package/src/central/backend/postgres-migrate.ts +100 -0
- package/src/central/backend/postgres-state.ts +197 -0
- package/src/central/backend/types.ts +246 -0
- package/src/central/backend/valkey-bus.ts +425 -0
- package/src/central/backend/valkey-catalog.ts +190 -0
- package/src/central/backend/valkey-client.ts +36 -0
- package/src/central/backend/valkey-counters.ts +38 -0
- package/src/central/backend/valkey-events.ts +168 -0
- package/src/central/backend/valkey-kv.ts +54 -0
- package/src/central/backend/valkey-locks.ts +92 -0
- package/src/central/cluster/directory.ts +141 -0
- package/src/central/cluster/feed.ts +84 -0
- package/src/central/cluster/leader.ts +232 -0
- package/src/central/cluster/live.ts +151 -0
- package/src/central/cluster/recommend.ts +59 -0
- package/src/central/cluster/rpc.ts +150 -0
- package/src/central/cluster/view.ts +232 -0
- package/src/central/config.ts +197 -3
- package/src/central/done.ts +96 -0
- package/src/central/events-log.ts +100 -0
- package/src/central/http.ts +1149 -170
- package/src/central/import.ts +318 -0
- package/src/central/main.ts +211 -12
- package/src/central/mcp-http.ts +116 -0
- package/src/central/nodes.ts +314 -0
- package/src/central/oidc.ts +34 -14
- package/src/central/push-target.ts +118 -18
- package/src/central/push.ts +256 -82
- package/src/central/registry.ts +902 -92
- package/src/central/say-stream.ts +128 -0
- package/src/central/session-token-push.ts +233 -0
- package/src/central/speech/openai.ts +21 -14
- package/src/central/speech/openrouter.ts +27 -10
- package/src/central/speech/provider.ts +54 -0
- package/src/central/speech/service.ts +22 -7
- package/src/central/spoke-ws.ts +522 -44
- package/src/central/store-shared.ts +518 -0
- package/src/central/store.ts +625 -189
- package/src/central/token-keys.ts +165 -0
- package/src/config.ts +118 -7
- package/src/index.ts +195 -43
- package/src/protocol.ts +3 -650
- package/src/rpc.ts +27 -2
- package/src/spoke/client.ts +3 -272
- package/src/spoke/conversation.ts +16 -12
- package/src/spoke/deliver.ts +75 -0
- package/src/spoke/enroll.ts +2 -79
- package/src/spoke/env-inject.ts +160 -0
- package/src/spoke/hub-rpc.ts +115 -0
- package/src/spoke/hub-tool.ts +409 -0
- package/src/spoke/launch-source.ts +22 -0
- package/src/spoke/launchers.ts +174 -0
- package/src/spoke/locations.ts +3 -2
- package/src/spoke/node-roots.ts +61 -0
- package/src/spoke/prompt-refs.ts +116 -0
- package/src/spoke/session-tokens.ts +2 -0
- package/src/spoke/spoke.ts +465 -28
- package/src/spoke/taskboard.ts +243 -0
- package/src/spoke/timeline.ts +184 -6
- package/src/spoke/tracker.ts +79 -4
- package/src/status.ts +203 -10
- package/src/tui-commands.ts +13 -6
- package/src/tui-messaging.ts +93 -0
- package/src/tui.ts +15 -0
- package/web/dist/apple-touch-icon.png +0 -0
- package/web/dist/assets/highlight-y4rJE6Tt.js +5 -0
- package/web/dist/assets/index-DWnMhXk9.js +20 -0
- package/web/dist/assets/index-DmUXEnw9.css +1 -0
- package/web/dist/assets/ort-wasm-simd-threaded-CxTQ5xH-.wasm +0 -0
- package/web/dist/assets/silero-worker-C8-8vLVS.js +11 -0
- package/web/dist/assets/silero_vad-Dt9-bTDn.onnx +0 -0
- package/web/dist/favicon.ico +0 -0
- package/web/dist/icon-192.png +0 -0
- package/web/dist/icon-512.png +0 -0
- package/web/dist/icon-maskable-512.png +0 -0
- package/web/dist/icon.svg +5 -5
- package/web/dist/index.html +17 -4
- package/web/dist/manifest.webmanifest +2 -2
- package/web/dist/sw.js +79 -15
- package/web/dist/assets/index-DClBvfLL.css +0 -1
- package/web/dist/assets/index-Djo_yF0a.js +0 -12
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// The hub's error envelope (design §8): every /api/agent failure answers {error: {code, message, hint?, ...extra}}.
|
|
2
|
+
// The SDK turns it into a HubError; failures without an envelope (hub unreachable, a proxy's HTML, a body that is not
|
|
3
|
+
// JSON, a broken stream) are HubTransportErrors. Neither ever carries the token.
|
|
4
|
+
import type { Evaluation } from "./types.ts"
|
|
5
|
+
|
|
6
|
+
/** The codes the hub answers with (src/central/agent/errors.ts); later phases may add more, so any string is kept. */
|
|
7
|
+
export type ErrorCode =
|
|
8
|
+
| "invalid"
|
|
9
|
+
| "invalid_cursor"
|
|
10
|
+
| "unauthorized"
|
|
11
|
+
| "token_expired"
|
|
12
|
+
| "needs_user"
|
|
13
|
+
| "forbidden"
|
|
14
|
+
| "not_found"
|
|
15
|
+
| "ambiguous"
|
|
16
|
+
| "name_taken"
|
|
17
|
+
| "gone"
|
|
18
|
+
| "unsupported"
|
|
19
|
+
| "paused"
|
|
20
|
+
| "rate_limited"
|
|
21
|
+
| "internal"
|
|
22
|
+
| "offline"
|
|
23
|
+
| (string & {})
|
|
24
|
+
|
|
25
|
+
export interface Envelope {
|
|
26
|
+
readonly code: ErrorCode
|
|
27
|
+
readonly message: string
|
|
28
|
+
readonly hint?: string
|
|
29
|
+
/**
|
|
30
|
+
* More fields, by code: candidates (ambiguous), retryAfter (rate_limited, seconds), feature/harness (unsupported),
|
|
31
|
+
* evaluation/decisionID (needs_user; see needsUserOf).
|
|
32
|
+
*/
|
|
33
|
+
readonly [extra: string]: unknown
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A failure the hub reported in its envelope. */
|
|
37
|
+
export class HubError extends Error {
|
|
38
|
+
override readonly name = "HubError"
|
|
39
|
+
readonly code: ErrorCode
|
|
40
|
+
readonly hint?: string
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
/** HTTP status of the answer. */
|
|
44
|
+
readonly status: number,
|
|
45
|
+
readonly envelope: Envelope,
|
|
46
|
+
) {
|
|
47
|
+
super(envelope.message)
|
|
48
|
+
this.code = envelope.code
|
|
49
|
+
if (typeof envelope.hint === "string") this.hint = envelope.hint
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Seconds to wait before retrying (rate_limited), when the hub said. */
|
|
53
|
+
get retryAfter(): number | undefined {
|
|
54
|
+
const value = this.envelope.retryAfter
|
|
55
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A failure without the hub's envelope: `unreachable` (no answer), `http` (a non-OK answer without the envelope, or
|
|
61
|
+
* a redirect), `bad_response` (an OK answer that is not what was expected), `stream` (a watch stream that broke).
|
|
62
|
+
*/
|
|
63
|
+
export type TransportKind = "unreachable" | "http" | "bad_response" | "stream"
|
|
64
|
+
|
|
65
|
+
export class HubTransportError extends Error {
|
|
66
|
+
override readonly name = "HubTransportError"
|
|
67
|
+
/** HTTP status, for `http`. */
|
|
68
|
+
readonly status?: number
|
|
69
|
+
|
|
70
|
+
constructor(
|
|
71
|
+
readonly kind: TransportKind,
|
|
72
|
+
message: string,
|
|
73
|
+
options: { readonly status?: number; readonly cause?: unknown } = {},
|
|
74
|
+
) {
|
|
75
|
+
super(message, options.cause !== undefined ? { cause: options.cause } : undefined)
|
|
76
|
+
if (options.status !== undefined) this.status = options.status
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** True for a HubError (with one of `codes`, when given). */
|
|
81
|
+
export const isHubError = (error: unknown, ...codes: ErrorCode[]): error is HubError =>
|
|
82
|
+
error instanceof HubError && (codes.length === 0 || codes.includes(error.code))
|
|
83
|
+
|
|
84
|
+
/** What a needs_user failure carries: why (the evaluation) and the Decision it opened for the user, if any. */
|
|
85
|
+
export interface NeedsUser {
|
|
86
|
+
readonly evaluation?: Evaluation
|
|
87
|
+
readonly decisionID?: string
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The needs_user details of an error (undefined for any other error). */
|
|
91
|
+
export function needsUserOf(error: unknown): NeedsUser | undefined {
|
|
92
|
+
if (!isHubError(error, "needs_user")) return undefined
|
|
93
|
+
const { evaluation, decisionID } = error.envelope
|
|
94
|
+
return {
|
|
95
|
+
...(typeof evaluation === "object" && evaluation !== null ? { evaluation: evaluation as Evaluation } : {}),
|
|
96
|
+
...(typeof decisionID === "string" ? { decisionID } : {}),
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The envelope inside a parsed body, if it is one (also the console routes' {error: message, code, hint?}). */
|
|
101
|
+
export function envelopeOf(body: unknown): Envelope | undefined {
|
|
102
|
+
const raw = body as { error?: unknown; code?: unknown; hint?: unknown } | null
|
|
103
|
+
const error = raw?.error as Envelope | undefined
|
|
104
|
+
if (typeof error === "object" && error !== null && typeof error.code === "string" && typeof error.message === "string") return error
|
|
105
|
+
if (typeof raw?.error === "string" && typeof raw.code === "string") return { code: raw.code, message: raw.error, ...(typeof raw.hint === "string" ? { hint: raw.hint } : {}) }
|
|
106
|
+
return undefined
|
|
107
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// The hub's API client (@huynle/hub-sdk): a typed client for /api/agent (HubClient), the error envelope as typed
|
|
2
|
+
// errors (HubError, HubTransportError), the answer types, the SSE parser of the watch stream, and the pure
|
|
3
|
+
// envelope renderer/sanitiser and address parser shared with the hub, launches, and webhook verification.
|
|
4
|
+
export * from "./address.ts"
|
|
5
|
+
export * from "./client.ts"
|
|
6
|
+
export * from "./envelope.ts"
|
|
7
|
+
export * from "./errors.ts"
|
|
8
|
+
export * from "./sse.ts"
|
|
9
|
+
export * from "./webhook.ts"
|
|
10
|
+
export type * from "./types.ts"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Server-sent events (GET /api/agent/watch): an incremental parser, and the event stream of a response.
|
|
2
|
+
import { HubTransportError } from "./errors.ts"
|
|
3
|
+
import type { WatchEvent } from "./types.ts"
|
|
4
|
+
|
|
5
|
+
/** Parses SSE text incrementally: feed chunks, get complete events (events without data are skipped). */
|
|
6
|
+
export class SseParser {
|
|
7
|
+
#buffer = ""
|
|
8
|
+
/** The last `id:` seen (it carries over to later events, as in EventSource). */
|
|
9
|
+
#id = ""
|
|
10
|
+
|
|
11
|
+
push(chunk: string): WatchEvent[] {
|
|
12
|
+
this.#buffer += chunk.replace(/\r\n?/g, "\n")
|
|
13
|
+
const out: WatchEvent[] = []
|
|
14
|
+
let end: number
|
|
15
|
+
while ((end = this.#buffer.indexOf("\n\n")) >= 0) {
|
|
16
|
+
const block = this.#buffer.slice(0, end)
|
|
17
|
+
this.#buffer = this.#buffer.slice(end + 2)
|
|
18
|
+
let event = "message"
|
|
19
|
+
const data: string[] = []
|
|
20
|
+
for (const line of block.split("\n")) {
|
|
21
|
+
if (line.startsWith(":")) continue
|
|
22
|
+
const colon = line.indexOf(":")
|
|
23
|
+
const field = colon < 0 ? line : line.slice(0, colon)
|
|
24
|
+
const value = colon < 0 ? "" : line.slice(colon + 1).replace(/^ /, "")
|
|
25
|
+
if (field === "event") event = value
|
|
26
|
+
else if (field === "data") data.push(value)
|
|
27
|
+
else if (field === "id" && !value.includes("\0")) this.#id = value
|
|
28
|
+
}
|
|
29
|
+
if (data.length) out.push({ event, data: data.join("\n"), ...(this.#id ? { id: this.#id } : {}) })
|
|
30
|
+
}
|
|
31
|
+
return out
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The named events of a heartbeat the hub sends to keep the stream open. */
|
|
36
|
+
const HEARTBEAT = "ping"
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The events of an SSE response until it ends (heartbeats skipped). Ends quietly once `signal` aborts; a stream that
|
|
40
|
+
* breaks otherwise is a `stream` HubTransportError.
|
|
41
|
+
*/
|
|
42
|
+
export async function* sseEvents(response: Response, signal?: AbortSignal): AsyncGenerator<WatchEvent, void, undefined> {
|
|
43
|
+
if (!response.body) throw new HubTransportError("bad_response", "the hub sent no watch stream")
|
|
44
|
+
const reader = response.body.getReader()
|
|
45
|
+
const decoder = new TextDecoder()
|
|
46
|
+
const parser = new SseParser()
|
|
47
|
+
const stop = () => void reader.cancel().catch(() => {})
|
|
48
|
+
signal?.addEventListener("abort", stop, { once: true })
|
|
49
|
+
try {
|
|
50
|
+
for (;;) {
|
|
51
|
+
if (signal?.aborted) return
|
|
52
|
+
let chunk: Awaited<ReturnType<typeof reader.read>>
|
|
53
|
+
try {
|
|
54
|
+
chunk = await reader.read()
|
|
55
|
+
} catch (cause) {
|
|
56
|
+
if (signal?.aborted) return
|
|
57
|
+
throw new HubTransportError("stream", `the watch stream failed (${cause instanceof Error ? cause.message : String(cause)})`, { cause })
|
|
58
|
+
}
|
|
59
|
+
if (chunk.done || signal?.aborted) return
|
|
60
|
+
for (const event of parser.push(decoder.decode(chunk.value, { stream: true }))) {
|
|
61
|
+
if (event.event === HEARTBEAT) continue
|
|
62
|
+
yield event
|
|
63
|
+
if (signal?.aborted) return
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} finally {
|
|
67
|
+
signal?.removeEventListener("abort", stop)
|
|
68
|
+
stop()
|
|
69
|
+
}
|
|
70
|
+
}
|