@huynle/hub 0.6.1 → 0.7.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 +800 -0
- package/Dockerfile +30 -0
- package/README.md +870 -66
- package/package.json +45 -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 +155 -0
- package/packages/cli/dist/hub-cli.js +10162 -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 +122 -0
- package/packages/codex/src/paths.ts +65 -0
- package/packages/codex/src/sessions.ts +578 -0
- package/packages/codex/src/spoke.ts +249 -0
- package/packages/codex/src/stdio.ts +101 -0
- package/packages/codex/src/websocket.ts +206 -0
- package/packages/codex/src/wrapper.ts +100 -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 +60 -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 +502 -0
- package/packages/sdk/src/envelope.ts +108 -0
- package/packages/sdk/src/errors.ts +106 -0
- package/packages/sdk/src/index.ts +10 -0
- package/packages/sdk/src/sse.ts +67 -0
- package/packages/sdk/src/types.ts +458 -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 +79 -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 +142 -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 +185 -0
- package/src/central/agent/directory.ts +473 -0
- package/src/central/agent/envelope.ts +51 -0
- package/src/central/agent/errors.ts +72 -0
- package/src/central/agent/escalation.ts +219 -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 +389 -0
- package/src/central/agent/routes.ts +278 -0
- package/src/central/agent/session-tokens.ts +227 -0
- package/src/central/agent/versioned.ts +26 -0
- package/src/central/agent/watch.ts +221 -0
- package/src/central/agent/webhook-routes.ts +78 -0
- package/src/central/agent/webhooks.ts +449 -0
- package/src/central/agent-data.ts +177 -0
- package/src/central/auth.ts +224 -121
- package/src/central/backend/file-state.ts +240 -0
- package/src/central/backend/index.ts +113 -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 +244 -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 +1067 -171
- package/src/central/import.ts +318 -0
- package/src/central/main.ts +211 -12
- 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 +572 -189
- package/src/central/token-keys.ts +165 -0
- package/src/config.ts +49 -1
- package/src/index.ts +165 -12
- 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 +68 -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/assets/highlight-y4rJE6Tt.js +5 -0
- package/web/dist/assets/index-D9zMbxSg.css +1 -0
- package/web/dist/assets/index-db1z4duA.js +20 -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/index.html +9 -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,116 @@
|
|
|
1
|
+
// Prompt references (design §2.4): hub addresses typed into a prompt get context, never routing. The pure parts
|
|
2
|
+
// (find, resolve, render) live in the spoke SDK; the OpenCode prompt hook stays here.
|
|
3
|
+
import { HubClient } from "../../packages/sdk/src/index.ts"
|
|
4
|
+
import { findReferences, renderReferences, resolveReferences, type Mention, type ReferenceSnapshot } from "../../packages/spoke-sdk/src/prompt-refs.ts"
|
|
5
|
+
import { isHubPrompt } from "./conversation"
|
|
6
|
+
import type { HubToolSpoke } from "./hub-tool"
|
|
7
|
+
|
|
8
|
+
export * from "../../packages/spoke-sdk/src/prompt-refs.ts"
|
|
9
|
+
|
|
10
|
+
/** The longest a prompt waits for the hub (design §2.4: ≤ 1.5 s); then it goes on without context. */
|
|
11
|
+
export const PROMPT_REF_TIMEOUT_MS = 1500
|
|
12
|
+
/** How long one session's lookup (or failure) is reused. */
|
|
13
|
+
export const PROMPT_REF_TTL_MS = 10_000
|
|
14
|
+
/** Cached sessions at most (expired ones are dropped first). */
|
|
15
|
+
const CACHE_MAX = 200
|
|
16
|
+
|
|
17
|
+
export const REFERENCE_FILE_NAME = "hub-references.txt"
|
|
18
|
+
const REFERENCE_FILE_DESCRIPTION = "hub: the sessions this prompt's @addresses name (context from the hub plugin)"
|
|
19
|
+
|
|
20
|
+
/** OpenCode's prompt hook event (plugin SessionPrompt), the parts used here. */
|
|
21
|
+
export interface PromptEvent {
|
|
22
|
+
readonly sessionID: string
|
|
23
|
+
readonly messageID?: string
|
|
24
|
+
readonly delivery?: string
|
|
25
|
+
metadata?: Record<string, unknown>
|
|
26
|
+
prompt: {
|
|
27
|
+
text: string
|
|
28
|
+
files?: { uri: string; name?: string; description?: string; mention?: Mention }[]
|
|
29
|
+
agents?: { name: string; mention?: Mention }[]
|
|
30
|
+
skills?: { name?: string; mention?: Mention }[]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PromptReferencesOptions {
|
|
35
|
+
readonly timeoutMs?: number
|
|
36
|
+
readonly ttlMs?: number
|
|
37
|
+
readonly now?: () => number
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The hook: adds hub context for @name / @@role addresses as one text file; never changes the prompt text. */
|
|
41
|
+
export class PromptReferences {
|
|
42
|
+
readonly #spoke: () => HubToolSpoke | undefined
|
|
43
|
+
readonly #timeoutMs: number
|
|
44
|
+
readonly #ttlMs: number
|
|
45
|
+
readonly #now: () => number
|
|
46
|
+
readonly #cache = new Map<string, { at: number; snapshot: Promise<ReferenceSnapshot | undefined> }>()
|
|
47
|
+
|
|
48
|
+
constructor(spoke: () => HubToolSpoke | undefined, options: PromptReferencesOptions = {}) {
|
|
49
|
+
this.#spoke = spoke
|
|
50
|
+
this.#timeoutMs = Math.min(options.timeoutMs ?? PROMPT_REF_TIMEOUT_MS, PROMPT_REF_TIMEOUT_MS)
|
|
51
|
+
this.#ttlMs = options.ttlMs ?? PROMPT_REF_TTL_MS
|
|
52
|
+
this.#now = options.now ?? Date.now
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Never throws and never waits longer than the timeout (fail open). */
|
|
56
|
+
async onPrompt(event: PromptEvent): Promise<void> {
|
|
57
|
+
try {
|
|
58
|
+
const prompt = event?.prompt
|
|
59
|
+
if (!prompt || typeof prompt.text !== "string" || isHubPrompt(event.metadata)) return
|
|
60
|
+
const addresses = findReferences(prompt)
|
|
61
|
+
if (!addresses.length) return
|
|
62
|
+
const spoke = this.#spoke()
|
|
63
|
+
const identity = spoke?.shellIdentity(event.sessionID)
|
|
64
|
+
if (!spoke || !identity?.token || !identity.url) return
|
|
65
|
+
const { token, url } = identity
|
|
66
|
+
const snapshot = await this.#snapshot(event.sessionID, () => this.#fetch({ token, url }, spoke.hubSupports("messaging")))
|
|
67
|
+
if (!snapshot) return
|
|
68
|
+
const refs = resolveReferences(addresses, snapshot, event.sessionID)
|
|
69
|
+
if (!refs.length) return
|
|
70
|
+
prompt.files = [...(prompt.files ?? []), referenceFile(renderReferences(refs))]
|
|
71
|
+
} catch {
|
|
72
|
+
// Fail open: the prompt goes on without context.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#snapshot(sessionID: string, load: () => Promise<ReferenceSnapshot | undefined>): Promise<ReferenceSnapshot | undefined> {
|
|
77
|
+
const now = this.#now()
|
|
78
|
+
const cached = this.#cache.get(sessionID)
|
|
79
|
+
if (cached && now - cached.at <= this.#ttlMs) return cached.snapshot
|
|
80
|
+
for (const [key, value] of this.#cache) if (now - value.at > this.#ttlMs) this.#cache.delete(key)
|
|
81
|
+
// Still full: drop the oldest (Map keeps insertion order).
|
|
82
|
+
while (this.#cache.size >= CACHE_MAX) this.#cache.delete(this.#cache.keys().next().value!)
|
|
83
|
+
const snapshot = load().catch(() => undefined)
|
|
84
|
+
this.#cache.set(sessionID, { at: now, snapshot })
|
|
85
|
+
return snapshot
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** who (required), status and inbox (optional details), in parallel, all within the timeout. */
|
|
89
|
+
async #fetch(identity: { token: string; url: string }, messaging: boolean): Promise<ReferenceSnapshot | undefined> {
|
|
90
|
+
const client = new HubClient({ url: identity.url, token: identity.token })
|
|
91
|
+
const abort = new AbortController()
|
|
92
|
+
let timer: ReturnType<typeof setTimeout> | undefined
|
|
93
|
+
const deadline = new Promise<undefined>((resolve) => {
|
|
94
|
+
timer = setTimeout(() => {
|
|
95
|
+
abort.abort()
|
|
96
|
+
resolve(undefined)
|
|
97
|
+
}, this.#timeoutMs)
|
|
98
|
+
})
|
|
99
|
+
const signal = { signal: abort.signal }
|
|
100
|
+
const optional = <T>(promise: Promise<T>) => promise.catch(() => undefined)
|
|
101
|
+
const lookup = Promise.all([client.who(signal), optional(client.status(signal)), messaging ? optional(client.inbox(signal)) : undefined]).then(
|
|
102
|
+
([who, status, inbox]): ReferenceSnapshot => ({ who: who.sessions, ...(status ? { status } : {}), ...(inbox ? { waiting: inbox.waiting } : {}) }),
|
|
103
|
+
)
|
|
104
|
+
try {
|
|
105
|
+
return await Promise.race([lookup, deadline])
|
|
106
|
+
} finally {
|
|
107
|
+
clearTimeout(timer)
|
|
108
|
+
lookup.catch(() => undefined)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** The context as an inline text file (the spike's mechanism: the model sees it inside the same user message). */
|
|
114
|
+
export function referenceFile(text: string): { uri: string; name: string; description: string } {
|
|
115
|
+
return { uri: `data:text/plain;base64,${Buffer.from(text, "utf8").toString("base64")}`, name: REFERENCE_FILE_NAME, description: REFERENCE_FILE_DESCRIPTION }
|
|
116
|
+
}
|