@staix/agent-hub 0.20.0 → 0.22.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.
Files changed (183) hide show
  1. package/CHANGELOG.md +66 -3
  2. package/README.md +2 -2
  3. package/docs/agent-notes/README.md +11 -0
  4. package/docs/agent-notes/adapters.md +7 -3
  5. package/docs/agent-notes/benchmarks.md +27 -0
  6. package/docs/agent-notes/budget.md +2 -1
  7. package/docs/agent-notes/bus.md +3 -3
  8. package/docs/agent-notes/daemon.md +17 -8
  9. package/docs/agent-notes/local-worker.md +4 -0
  10. package/docs/agent-notes/models.md +2 -0
  11. package/docs/agent-notes/tasks.md +17 -9
  12. package/docs/agent-notes/tests.md +9 -2
  13. package/docs/bench.md +1 -1
  14. package/docs/data-policy.md +2 -0
  15. package/docs/dogfood.md +39 -4
  16. package/docs/events.md +2 -1
  17. package/docs/memory.md +9 -3
  18. package/docs/operations.md +610 -62
  19. package/docs/profiles.md +13 -1
  20. package/docs/quickstart.md +18 -9
  21. package/docs/research.md +7 -4
  22. package/docs/sdlc.md +54 -10
  23. package/docs/security.md +396 -34
  24. package/docs/smoke.md +133 -0
  25. package/docs/specs/2026-09-19-agent-hub-design.md +1101 -22
  26. package/docs/verification/2026-10-27-0.19.0.md +5 -5
  27. package/docs/verification/2026-10-28-claude-2.1.311-2.1.312-bash-permission.json +635 -0
  28. package/docs/verification/2026-10-28-claude-2.1.311-2.1.312-permission-transport.json +403 -0
  29. package/docs/verification/2026-10-28-claude-implementer-permission-triage.md +123 -0
  30. package/docs/verification/2026-10-28-jcode-0.99.1-usage.md +41 -0
  31. package/docs/verification/2026-10-28-realpath-name-audit.md +222 -0
  32. package/docs/verification/2026-10-28-routing-f0bb8ad0.md +1000 -0
  33. package/docs/verification/2026-10-29-0.21.0.md +61 -0
  34. package/docs/verification/2026-10-29-model-effort-capabilities.md +123 -0
  35. package/docs/verification/2026-10-29-modelrouting-b152ddb9.md +953 -0
  36. package/docs/verification/2026-10-30-0.22.0.md +49 -0
  37. package/docs/verification/2026-10-30-445-capability-probes.md +172 -0
  38. package/docs/verification/2026-10-30-bus-delivery-operational-settings.md +77 -0
  39. package/docs/verification/2026-10-30-jcode-ac4.md +24 -0
  40. package/docs/verification/2026-10-30-jcode-ac6.md +52 -0
  41. package/docs/verification/2026-10-30-recovery-wait-settings.md +141 -0
  42. package/docs/verification/claude-implementer-permission-triage.ts +160 -0
  43. package/docs/verification/claude-permission-transport-native.py +71 -14
  44. package/docs/verification/profiles/YYYY-MM-DD-research.md +1 -1
  45. package/docs/verified.json +15 -15
  46. package/package.json +2 -2
  47. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  48. package/plugins/agent-hub/server.js +1016 -280
  49. package/src/adapters/acp.ts +79 -3
  50. package/src/adapters/channel-peer.ts +4 -0
  51. package/src/adapters/claude-channel.ts +13 -6
  52. package/src/adapters/claude-implementer.ts +60 -7
  53. package/src/adapters/codex-appserver.ts +77 -4
  54. package/src/adapters/conformance/fakes/jcode-agent.ts +6 -2
  55. package/src/adapters/conformance/kit.ts +3 -9
  56. package/src/adapters/definitions/builtin-metadata.ts +3 -114
  57. package/src/adapters/definitions/native-config-defaults.ts +1 -1
  58. package/src/adapters/definitions/native-config-policy.ts +3 -2
  59. package/src/adapters/definitions/native-context.ts +12 -0
  60. package/src/adapters/external-metadata.ts +48 -0
  61. package/src/adapters/external-modules.ts +63 -3
  62. package/src/adapters/jcode.ts +6 -2
  63. package/src/adapters/local-worker.ts +40 -25
  64. package/src/adapters/native-proof-ports.ts +10 -0
  65. package/src/adapters/registry-types.ts +4 -0
  66. package/src/broker/protocol.ts +203 -0
  67. package/src/broker/server.ts +314 -0
  68. package/src/broker/store.ts +548 -0
  69. package/src/cli/bench.ts +3 -2
  70. package/src/cli/broker.ts +58 -0
  71. package/src/cli/conductor-recovery.ts +142 -0
  72. package/src/cli/configured-acp-entry.ts +26 -6
  73. package/src/cli/console-state.ts +59 -17
  74. package/src/cli/console.ts +17 -2
  75. package/src/cli/facts-hook.ts +3 -1
  76. package/src/cli/help.ts +29 -16
  77. package/src/cli/identity.ts +25 -10
  78. package/src/cli/init.ts +34 -7
  79. package/src/cli/intake-output.ts +33 -0
  80. package/src/cli/learn-output.ts +38 -0
  81. package/src/cli/main.ts +334 -73
  82. package/src/cli/output.ts +41 -1
  83. package/src/cli/recovery-package.ts +18 -1
  84. package/src/cli/recovery-waits.ts +26 -0
  85. package/src/cli/role-holders.ts +35 -0
  86. package/src/cli/room.ts +304 -0
  87. package/src/cli/say-input.ts +16 -0
  88. package/src/cli/schedule-output.ts +49 -0
  89. package/src/cli/sdlc-output.ts +44 -6
  90. package/src/cli/smoke-pty-bridge.ts +82 -0
  91. package/src/cli/smoke-pty.ts +153 -0
  92. package/src/cli/smoke-run.ts +139 -0
  93. package/src/cli/smoke-target.ts +130 -0
  94. package/src/cli/source-output.ts +29 -0
  95. package/src/cli/task-output.ts +3 -2
  96. package/src/cli/upgrade-runtime.ts +112 -28
  97. package/src/cli/upgrade.ts +68 -8
  98. package/src/hub/ask.ts +76 -12
  99. package/src/hub/board.ts +132 -22
  100. package/src/hub/bus.ts +416 -65
  101. package/src/hub/child-process.ts +2 -0
  102. package/src/hub/ci-watch.ts +42 -20
  103. package/src/hub/claude-failure-stage.ts +85 -0
  104. package/src/hub/claude-shell-wrapper.ts +11 -5
  105. package/src/hub/conductor.ts +17 -4
  106. package/src/hub/config-apply.ts +34 -6
  107. package/src/hub/config-reload.ts +7 -5
  108. package/src/hub/config-trust.ts +7 -1
  109. package/src/hub/context-window.ts +33 -3
  110. package/src/hub/control-client.ts +14 -2
  111. package/src/hub/corpus-config.ts +34 -0
  112. package/src/hub/corpus-evidence.ts +184 -0
  113. package/src/hub/corpus.ts +373 -0
  114. package/src/hub/cost-governance.ts +26 -0
  115. package/src/hub/daemon.ts +1209 -183
  116. package/src/hub/deliverable-files.ts +8 -2
  117. package/src/hub/delivery-journal.ts +200 -73
  118. package/src/hub/dogfood-profile.ts +32 -5
  119. package/src/hub/dogfood-read.ts +6 -2
  120. package/src/hub/envelope.ts +11 -0
  121. package/src/hub/eval-gate.ts +131 -0
  122. package/src/hub/events.ts +1 -1
  123. package/src/hub/external-instance.ts +69 -0
  124. package/src/hub/facts.ts +15 -5
  125. package/src/hub/folder-trigger.ts +223 -0
  126. package/src/hub/hub-tools.ts +2 -1
  127. package/src/hub/inference.ts +20 -5
  128. package/src/hub/instance-config.ts +69 -3
  129. package/src/hub/instance-execution.ts +6 -2
  130. package/src/hub/instances.ts +32 -4
  131. package/src/hub/intake.ts +125 -0
  132. package/src/hub/learning.ts +117 -0
  133. package/src/hub/lifecycle.ts +7 -3
  134. package/src/hub/limits.ts +12 -5
  135. package/src/hub/native-permission-request.ts +77 -0
  136. package/src/hub/operational-authority.ts +63 -5
  137. package/src/hub/operational-settings.ts +154 -0
  138. package/src/hub/operational-view.ts +1 -1
  139. package/src/hub/packs.ts +132 -0
  140. package/src/hub/path-policy.ts +7 -0
  141. package/src/hub/peer-doing.ts +130 -0
  142. package/src/hub/peers.ts +12 -0
  143. package/src/hub/queue-backpressure.ts +58 -0
  144. package/src/hub/read-tools.ts +2 -0
  145. package/src/hub/recovery-authority.ts +151 -0
  146. package/src/hub/recovery-policy.ts +220 -0
  147. package/src/hub/research.ts +24 -14
  148. package/src/hub/restart.ts +7 -0
  149. package/src/hub/routing.ts +54 -11
  150. package/src/hub/schedules.ts +266 -0
  151. package/src/hub/sdlc-merge.ts +38 -14
  152. package/src/hub/sdlc-metrics.ts +32 -10
  153. package/src/hub/sdlc-queue.ts +7 -1
  154. package/src/hub/sdlc-release.ts +1 -1
  155. package/src/hub/sdlc.ts +37 -7
  156. package/src/hub/security-baseline.ts +38 -0
  157. package/src/hub/settings.ts +27 -2
  158. package/src/hub/shipped-packs.ts +8 -0
  159. package/src/hub/snapshots.ts +72 -6
  160. package/src/hub/source-read.ts +160 -0
  161. package/src/hub/sources.ts +311 -0
  162. package/src/hub/tasks.ts +987 -110
  163. package/src/hub/workflow.ts +1 -1
  164. package/src/local/doc-read.ts +69 -0
  165. package/src/local/proxy.ts +4 -13
  166. package/src/local/tools.ts +37 -3
  167. package/src/local/web-fetch-config.ts +43 -0
  168. package/src/local/web-fetch.ts +183 -0
  169. package/src/memory/brief.ts +85 -13
  170. package/src/memory/capture.ts +1 -1
  171. package/src/rooms/application.ts +114 -0
  172. package/src/rooms/boundary.ts +103 -0
  173. package/src/rooms/commands.ts +294 -0
  174. package/src/rooms/crypto.ts +371 -0
  175. package/src/rooms/link.ts +584 -0
  176. package/src/rooms/policy.ts +82 -0
  177. package/src/rooms/remote-peer.ts +80 -0
  178. package/src/rooms/service.ts +426 -0
  179. package/src/rooms/status.ts +146 -0
  180. package/src/rooms/store.ts +1210 -0
  181. package/src/rooms/wire.ts +465 -0
  182. package/src/ui/index.html +91 -4
  183. package/templates/packs/example.pack.json +13 -0
@@ -0,0 +1,146 @@
1
+ import { types } from "node:util";
2
+ import type { PeerState } from "../hub/envelope.ts";
3
+ import { decodeBase64url, encodeBase64url } from "./crypto.ts";
4
+ import { parseRemotePeerId } from "./application.ts";
5
+
6
+ const ROOM_LIMIT = 64;
7
+ const REMOTE_PEER_LIMIT = 4096;
8
+ const REMOTE_PEER_TOTAL_LIMIT = 4096;
9
+ const MEMBER_LIMIT = 64;
10
+ const UINT64_MAX = 18_446_744_073_709_551_615n;
11
+ const DATE_MAX_MS = 8_640_000_000_000_000;
12
+ const NAME = /^[a-z][a-z0-9-]{0,31}$/;
13
+ const FINGERPRINT = /^[0-9a-f]{64}$/;
14
+ const EPOCH = /^[1-9][0-9]{0,19}$/;
15
+ const LINK_STATES = new Set(["online", "connecting", "offline", "left"]);
16
+ const PEER_STATES = new Set<PeerState>(["idle", "busy", "paused", "offline"]);
17
+
18
+ export interface RoomStatusPeer {
19
+ id: string;
20
+ state: PeerState;
21
+ }
22
+
23
+ export interface RoomRelayStats {
24
+ since: number;
25
+ outbound: number | null;
26
+ inbound: number | null;
27
+ withheld: number | null;
28
+ }
29
+
30
+ /** Allowlisted room metadata. Missing member counts and peer lists stay unknown. */
31
+ export interface RoomStatusView {
32
+ name: string;
33
+ room: string;
34
+ owner: string;
35
+ member: string;
36
+ epoch: string;
37
+ link: "online" | "connecting" | "offline" | "left" | null;
38
+ memberCount: number | null;
39
+ remotePeers: RoomStatusPeer[] | null;
40
+ relays: RoomRelayStats | null;
41
+ }
42
+
43
+ function plainRecord(value: unknown): value is Record<string, unknown> {
44
+ if (!value || typeof value !== "object" || types.isProxy(value) || Array.isArray(value)) return false;
45
+ try { return Object.getPrototypeOf(value) === Object.prototype; } catch { return false; }
46
+ }
47
+
48
+ function plainArray(value: unknown): value is unknown[] {
49
+ return !!value && typeof value === "object" && !types.isProxy(value) && Array.isArray(value);
50
+ }
51
+
52
+ /** Read own data properties only; accessors and hostile proxies are never evaluated. */
53
+ function ownField(value: unknown, key: string): { present: boolean; value?: unknown } {
54
+ if (!value || typeof value !== "object" || types.isProxy(value)) return { present: false };
55
+ try {
56
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
57
+ if (!descriptor) return { present: false };
58
+ return Object.hasOwn(descriptor, "value") ? { present: true, value: descriptor.value } : { present: true };
59
+ } catch { return { present: false }; }
60
+ }
61
+
62
+ function ownData(value: unknown, key: string): unknown {
63
+ const field = ownField(value, key);
64
+ return field.present ? field.value : undefined;
65
+ }
66
+
67
+ function arrayItem(value: unknown[], index: number): unknown {
68
+ if (types.isProxy(value)) return undefined;
69
+ try {
70
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
71
+ return descriptor && Object.hasOwn(descriptor, "value") ? descriptor.value : undefined;
72
+ } catch { return undefined; }
73
+ }
74
+
75
+ function roomId(value: unknown): value is string {
76
+ if (typeof value !== "string" || value.length !== 43) return false;
77
+ try { return encodeBase64url(decodeBase64url(value, 32)) === value; } catch { return false; }
78
+ }
79
+
80
+ function validEpoch(value: unknown): value is string {
81
+ if (typeof value !== "string" || !EPOCH.test(value)) return false;
82
+ try { return BigInt(value) <= UINT64_MAX; } catch { return false; }
83
+ }
84
+
85
+ function memberCount(value: unknown): number | null {
86
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= MEMBER_LIMIT ? value : null;
87
+ }
88
+
89
+ /** Invalid or absent remote peer metadata stays unknown; no body, title, or arbitrary row is copied. */
90
+ function remotePeers(value: unknown, remaining: number): RoomStatusPeer[] | null {
91
+ if (!plainArray(value) || value.length > REMOTE_PEER_LIMIT || value.length > remaining) return null;
92
+ const result: RoomStatusPeer[] = [], ids = new Set<string>();
93
+ for (let index = 0; index < value.length; index++) {
94
+ const item = arrayItem(value, index);
95
+ if (!plainRecord(item)) return null;
96
+ const id = ownData(item, "id"), state = ownData(item, "state");
97
+ if (typeof id !== "string" || !parseRemotePeerId(id) || typeof state !== "string" || !PEER_STATES.has(state as PeerState) || ids.has(id)) return null;
98
+ ids.add(id);
99
+ result.push({ id, state: state as PeerState });
100
+ }
101
+ return result;
102
+ }
103
+
104
+ function relayCount(value: unknown): number | null {
105
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
106
+ }
107
+
108
+ /** Relay totals are daemon-boot scoped; absent, malformed or inconsistent values stay unknown. */
109
+ function relayStats(value: unknown): RoomRelayStats | null {
110
+ if (!plainRecord(value)) return null;
111
+ const since = ownData(value, "since");
112
+ if (typeof since !== "number" || !Number.isSafeInteger(since) || since <= 0 || since > DATE_MAX_MS) return null;
113
+ const outbound = relayCount(ownData(value, "outbound")), inbound = relayCount(ownData(value, "inbound"));
114
+ const rawWithheld = relayCount(ownData(value, "withheld"));
115
+ const withheld = outbound !== null && rawWithheld !== null && rawWithheld <= outbound ? rawWithheld : null;
116
+ return { since, outbound, inbound, withheld };
117
+ }
118
+
119
+ /** Project RoomCommands.rows-compatible data to body-free room status metadata. */
120
+ export function projectRoomStatus(value: unknown): RoomStatusView[] {
121
+ try {
122
+ if (!plainArray(value) || value.length > ROOM_LIMIT) return [];
123
+ const views: RoomStatusView[] = [];
124
+ let remainingRemotePeers = REMOTE_PEER_TOTAL_LIMIT;
125
+ for (let index = 0; index < value.length; index++) {
126
+ const item = arrayItem(value, index);
127
+ if (!plainRecord(item)) continue;
128
+ const name = ownData(item, "name"), room = ownData(item, "room"), owner = ownData(item, "owner");
129
+ const member = ownData(item, "member"), epoch = ownData(item, "epoch");
130
+ if (typeof name !== "string" || !NAME.test(name) || !roomId(room) || typeof owner !== "string" || !FINGERPRINT.test(owner)
131
+ || typeof member !== "string" || !FINGERPRINT.test(member) || !validEpoch(epoch)) continue;
132
+ const canonicalLink = ownField(item, "link"), rawLink = canonicalLink.present ? canonicalLink.value : ownData(item, "state");
133
+ const canonicalMemberCount = ownField(item, "memberCount"), rawMemberCount = canonicalMemberCount.present ? canonicalMemberCount.value : ownData(item, "members");
134
+ const peers = remotePeers(ownData(item, "remotePeers"), remainingRemotePeers);
135
+ if (peers !== null) remainingRemotePeers -= peers.length;
136
+ views.push({
137
+ name, room, owner, member, epoch,
138
+ link: typeof rawLink === "string" && LINK_STATES.has(rawLink) ? rawLink as RoomStatusView["link"] : null,
139
+ memberCount: memberCount(rawMemberCount),
140
+ remotePeers: peers,
141
+ relays: relayStats(ownData(item, "relays")),
142
+ });
143
+ }
144
+ return views;
145
+ } catch { return []; }
146
+ }