@polderlabs/bizar 6.3.0 → 7.0.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 (245) hide show
  1. package/.claude/hooks/sessionend-recall.mjs +3 -3
  2. package/.claude/hooks/worker-suggest.mjs +110 -0
  3. package/.claude/settings.json +9 -0
  4. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js → EnvVarsSection-CW6fWKds.js} +3 -3
  5. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
  6. package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
  7. package/bizar-dash/dist/assets/{MobileChat-BJrqwVDd.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
  8. package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
  9. package/bizar-dash/dist/assets/{MobileSettings-CEQNJNLJ.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
  10. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
  11. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
  12. package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
  13. package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
  14. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
  15. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
  16. package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
  17. package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
  18. package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
  19. package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
  20. package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
  21. package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
  22. package/bizar-dash/dist/assets/{markdown-tOLaD6nm.js.map → markdown-w2bDDkAH.js.map} +1 -1
  23. package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
  24. package/bizar-dash/dist/assets/{mobile-DYCHcUpq.js.map → mobile-DXYCA0hC.js.map} +1 -1
  25. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
  26. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
  27. package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
  28. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
  29. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
  30. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
  31. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
  32. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
  33. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
  34. package/bizar-dash/dist/index.html +12 -10
  35. package/bizar-dash/dist/mobile.html +7 -4
  36. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  37. package/bizar-dash/src/server/api.mjs +11 -0
  38. package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
  39. package/bizar-dash/src/server/memory-distillation.mjs +296 -0
  40. package/bizar-dash/src/server/routes/distill.mjs +129 -0
  41. package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
  42. package/bizar-dash/src/web/App.tsx +4 -0
  43. package/bizar-dash/src/web/components/Tag.tsx +18 -5
  44. package/bizar-dash/src/web/components/Topbar.tsx +3 -0
  45. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
  46. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
  47. package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
  48. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
  49. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
  50. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
  51. package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
  52. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
  53. package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
  54. package/bizar-dash/src/web/lib/types.ts +25 -0
  55. package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
  56. package/bizar-dash/src/web/styles/main.css +251 -0
  57. package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
  58. package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
  59. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
  60. package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
  61. package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
  62. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
  63. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
  64. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
  65. package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
  66. package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
  67. package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
  68. package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
  69. package/bizar-dash/src/web/ui/controls/controls.css +454 -0
  70. package/bizar-dash/src/web/ui/controls/index.ts +33 -0
  71. package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
  72. package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
  73. package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
  74. package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
  75. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
  76. package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
  77. package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
  78. package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
  79. package/bizar-dash/src/web/ui/data/data.css +535 -0
  80. package/bizar-dash/src/web/ui/data/index.ts +31 -0
  81. package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
  82. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
  83. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
  84. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
  85. package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
  86. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
  87. package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
  88. package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
  89. package/bizar-dash/src/web/ui/index.ts +56 -0
  90. package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
  91. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
  92. package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
  93. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
  94. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
  95. package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
  96. package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
  97. package/bizar-dash/src/web/ui/layout/index.ts +33 -0
  98. package/bizar-dash/src/web/ui/layout/layout.css +413 -0
  99. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
  100. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
  101. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
  102. package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
  103. package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
  104. package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
  105. package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
  106. package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
  107. package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
  108. package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
  109. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
  110. package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
  111. package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
  112. package/bizar-dash/src/web/ui/styles/globals.css +86 -0
  113. package/bizar-dash/src/web/ui/styles/reset.css +125 -0
  114. package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
  115. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
  116. package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
  117. package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
  118. package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
  119. package/bizar-dash/src/web/views/Agents.tsx +506 -266
  120. package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
  121. package/bizar-dash/src/web/views/Overview.tsx +996 -448
  122. package/bizar-dash/src/web/views/Tasks.tsx +277 -273
  123. package/bizar-dash/tests/communication-log.test.tsx +67 -0
  124. package/bizar-dash/tests/dep-graph.test.tsx +40 -0
  125. package/bizar-dash/tests/event-log.test.tsx +61 -0
  126. package/bizar-dash/tests/goal-input.test.tsx +72 -0
  127. package/bizar-dash/tests/goap-planner.test.ts +68 -0
  128. package/bizar-dash/tests/quality-gates.test.tsx +59 -0
  129. package/bizar-dash/tests/setup.ts +31 -1
  130. package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
  131. package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
  132. package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
  133. package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
  134. package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
  135. package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
  136. package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
  137. package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
  138. package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
  139. package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
  140. package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
  141. package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
  142. package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
  143. package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
  144. package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
  145. package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
  146. package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
  147. package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
  148. package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
  149. package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
  150. package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
  151. package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
  152. package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
  153. package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
  154. package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
  155. package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
  156. package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
  157. package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
  158. package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
  159. package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
  160. package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
  161. package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
  162. package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
  163. package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
  164. package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
  165. package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
  166. package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
  167. package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
  168. package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
  169. package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
  170. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
  171. package/bizar-dash/tests/views/Agents.test.tsx +359 -0
  172. package/bizar-dash/tests/views/Overview.test.tsx +413 -0
  173. package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
  174. package/bizar-dash/vitest.config.ts +3 -1
  175. package/cli/__tests__/cost-gate.test.mjs +301 -0
  176. package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
  177. package/cli/bin.mjs +38 -0
  178. package/cli/commands/claim.mjs +282 -0
  179. package/cli/commands/cost.mjs +279 -0
  180. package/cli/cost-gate.mjs +501 -0
  181. package/cli/feature-list-bridge.mjs +400 -0
  182. package/cli/memory-constants.mjs +17 -0
  183. package/cli/worker-dispatcher.mjs +259 -0
  184. package/cli/worker-dispatcher.test.mjs +204 -0
  185. package/config/trigger-patterns.json +186 -0
  186. package/package.json +2 -2
  187. package/packages/sdk/package.json +1 -1
  188. package/packages/sdk/src/agent-registry.ts +304 -0
  189. package/packages/sdk/src/consensus/byzantine.ts +587 -0
  190. package/packages/sdk/src/consensus/index.ts +147 -0
  191. package/packages/sdk/src/consensus/queen.ts +173 -0
  192. package/packages/sdk/src/consensus/types.ts +199 -0
  193. package/packages/sdk/src/federation/audit.ts +156 -0
  194. package/packages/sdk/src/federation/budget.ts +269 -0
  195. package/packages/sdk/src/federation/envelope.ts +144 -0
  196. package/packages/sdk/src/federation/hmac.ts +160 -0
  197. package/packages/sdk/src/federation/index.ts +443 -0
  198. package/packages/sdk/src/federation/pii.ts +241 -0
  199. package/packages/sdk/src/federation/policy.ts +112 -0
  200. package/packages/sdk/src/federation/trust.ts +146 -0
  201. package/packages/sdk/src/index.ts +67 -0
  202. package/packages/sdk/src/mcp/server.ts +351 -1
  203. package/packages/sdk/src/router/codemod-intent.ts +125 -0
  204. package/packages/sdk/src/router/index.ts +247 -0
  205. package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
  206. package/packages/sdk/src/router/memory-distillation.ts +249 -0
  207. package/packages/sdk/src/router/model-router.ts +235 -0
  208. package/packages/sdk/src/router/q-learning-router.ts +304 -0
  209. package/packages/sdk/src/swarm-topology.ts +279 -0
  210. package/packages/sdk/tests/agent-registry.test.ts +285 -0
  211. package/packages/sdk/tests/consensus.test.ts +376 -0
  212. package/packages/sdk/tests/federation/audit.test.ts +164 -0
  213. package/packages/sdk/tests/federation/budget.test.ts +189 -0
  214. package/packages/sdk/tests/federation/envelope.test.ts +120 -0
  215. package/packages/sdk/tests/federation/hmac.test.ts +194 -0
  216. package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
  217. package/packages/sdk/tests/federation/pii.test.ts +106 -0
  218. package/packages/sdk/tests/federation/policy.test.ts +140 -0
  219. package/packages/sdk/tests/federation/trust.test.ts +124 -0
  220. package/packages/sdk/tests/mcp-tools.test.ts +204 -0
  221. package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
  222. package/packages/sdk/tests/model-router.test.mjs +108 -0
  223. package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
  224. package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
  225. package/packages/sdk/tests/router.test.mjs +91 -0
  226. package/packages/sdk/tests/sdk.test.mjs +26 -2
  227. package/packages/sdk/tests/swarm-topology.test.ts +258 -0
  228. package/scripts/bh-full-e2e.mjs +11 -15
  229. package/bizar-dash/dist/assets/MobileChat-BJrqwVDd.js +0 -1
  230. package/bizar-dash/dist/assets/MobileSettings-CEQNJNLJ.js +0 -1
  231. package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
  232. package/bizar-dash/dist/assets/main-IvfQAOfy.js +0 -18
  233. package/bizar-dash/dist/assets/main-IvfQAOfy.js.map +0 -1
  234. package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
  235. package/bizar-dash/dist/assets/markdown-tOLaD6nm.js +0 -1
  236. package/bizar-dash/dist/assets/mobile-DYCHcUpq.js +0 -1
  237. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js +0 -2
  238. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js.map +0 -1
  239. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
  240. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
  241. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js +0 -2
  242. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js.map +0 -1
  243. package/bizar-dash/dist/assets/vendor-C843201K.js +0 -29
  244. package/bizar-dash/dist/assets/vendor-C843201K.js.map +0 -1
  245. package/packages/sdk/package-lock.json +0 -32
@@ -0,0 +1,112 @@
1
+ /**
2
+ * federation/policy.ts — PolicyEngine: enforces per-call envelope
3
+ * constraints (maxHops, action allowlist, peer blocklist).
4
+ *
5
+ * F-038 — ported from ruflo
6
+ * `v3/@claude-flow/plugin-agent-federation/src/application/policy-engine.ts`
7
+ * but stripped to the three checks the skeleton needs:
8
+ *
9
+ * 1. maxHops — envelope.hopCount must be < budget.maxHops
10
+ * (default ceiling = 3 hops).
11
+ * 2. message — envelope.messageType must be in the action
12
+ * allowlist.
13
+ * 3. peer — source node must NOT be in the blocklist.
14
+ *
15
+ * `enforce(envelope, budget)` returns a discriminated result so
16
+ * callers can map directly to an MCP error string.
17
+ */
18
+
19
+ import {
20
+ FEDERATION_MESSAGE_TYPES,
21
+ isFederationMessageType,
22
+ type EnvelopeBudget,
23
+ type FederationEnvelope,
24
+ type FederationMessageType,
25
+ } from "./envelope.js";
26
+
27
+ /** Hard ceiling on hops — matches the spec's "≤ 3" rule. */
28
+ export const DEFAULT_MAX_HOPS = 3;
29
+
30
+ export type PolicyDecision =
31
+ | { allowed: true }
32
+ | {
33
+ allowed: false;
34
+ denialReason:
35
+ | "max_hops_exceeded"
36
+ | "message_type_not_allowed"
37
+ | "peer_blocked"
38
+ | "budget_missing"
39
+ | "budget_invalid";
40
+ };
41
+
42
+ export interface PolicyConfig {
43
+ /** Set of message kinds accepted by this node. Defaults to all
44
+ * 16 ruflo kinds — narrow via `allowedMessageTypes`. */
45
+ readonly allowedMessageTypes?: readonly FederationMessageType[];
46
+ /** Set of sourceNodeIds that are NEVER accepted (blocklist). */
47
+ readonly peerBlocklist?: readonly string[];
48
+ /** Override the default maxHops ceiling. */
49
+ readonly maxHops?: number;
50
+ }
51
+
52
+ export class PolicyEngine {
53
+ private readonly allowed: Set<FederationMessageType>;
54
+ private readonly blocked: Set<string>;
55
+ private readonly maxHops: number;
56
+
57
+ constructor(cfg: PolicyConfig = {}) {
58
+ this.allowed = new Set(cfg.allowedMessageTypes ?? FEDERATION_MESSAGE_TYPES);
59
+ this.blocked = new Set((cfg.peerBlocklist ?? []).map((s) => String(s)));
60
+ this.maxHops = cfg.maxHops ?? DEFAULT_MAX_HOPS;
61
+ }
62
+
63
+ /** Runtime mutator — narrow the allowlist after construction. */
64
+ allowMessageType(t: FederationMessageType): void {
65
+ this.allowed.add(t);
66
+ }
67
+
68
+ /** Runtime mutator — narrow the allowlist after construction. */
69
+ denyMessageType(t: FederationMessageType): void {
70
+ this.allowed.delete(t);
71
+ }
72
+
73
+ /** Runtime mutator — block / unblock a peer at runtime. */
74
+ setBlocked(nodeId: string, blocked: boolean): void {
75
+ if (blocked) this.blocked.add(nodeId);
76
+ else this.blocked.delete(nodeId);
77
+ }
78
+
79
+ /** Admit or reject an envelope given its budget context. */
80
+ enforce(envelope: FederationEnvelope, budget: EnvelopeBudget | undefined): PolicyDecision {
81
+ // 0. The budget object must exist — without it we can't enforce
82
+ // the maxHops ceiling.
83
+ if (!budget) return { allowed: false, denialReason: "budget_missing" };
84
+ if (typeof budget.maxHops !== "number" || !Number.isFinite(budget.maxHops)) {
85
+ return { allowed: false, denialReason: "budget_invalid" };
86
+ }
87
+
88
+ // 1. Peer blocklist
89
+ if (this.blocked.has(envelope.sourceNodeId)) {
90
+ return { allowed: false, denialReason: "peer_blocked" };
91
+ }
92
+
93
+ // 2. Message type allowlist
94
+ if (!isFederationMessageType(envelope.messageType)) {
95
+ return { allowed: false, denialReason: "message_type_not_allowed" };
96
+ }
97
+ if (!this.allowed.has(envelope.messageType)) {
98
+ return { allowed: false, denialReason: "message_type_not_allowed" };
99
+ }
100
+
101
+ // 3. maxHops — current hopCount must be strictly LESS than the
102
+ // ceiling. A freshly-origin envelope has hopCount=0 so a
103
+ // maxHops=3 budget admits it.
104
+ const hopCount = envelope.hopCount ?? 0;
105
+ const effectiveCeiling = Math.min(budget.maxHops, this.maxHops);
106
+ if (hopCount >= effectiveCeiling) {
107
+ return { allowed: false, denialReason: "max_hops_exceeded" };
108
+ }
109
+
110
+ return { allowed: true };
111
+ }
112
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * federation/trust.ts — TrustEvaluator: peer allowlist + recent fail
3
+ * rate + envelope age → trust score.
4
+ *
5
+ * F-038 — ported from ruflo
6
+ * `v3/@claude-flow/plugin-agent-federation/src/application/trust-evaluator.ts`
7
+ * (computeScore shape), stripped down for the skeleton:
8
+ *
9
+ * evaluate(envelope, peer) → { allowed, reason, score }
10
+ *
11
+ * Inputs:
12
+ * - peer (PeerState): { nodeId, allowlisted, recentFailRate, lastSeenMs }
13
+ * - envelope: FederationEnvelope
14
+ *
15
+ * Scoring (pure function):
16
+ * baseScore = peer.allowlisted ? 0.6 : 0.0
17
+ * freshness = clamp(1 - ageMs / MAX_AGE_MS, 0, 1) * 0.2
18
+ * reliability = clamp(1 - peer.recentFailRate, 0, 1) * 0.2
19
+ * score = baseScore + freshness + reliability
20
+ *
21
+ * Decision:
22
+ * allowed = peer.allowlisted AND ageMs <= MAX_AGE_MS AND score >= MIN_SCORE
23
+ *
24
+ * State — per-node recent fail rate + last-seen are tracked
25
+ * in a Map so repeated calls from the same peer update the
26
+ * picture. Failures can be recorded via `recordFailure(nodeId)`.
27
+ */
28
+
29
+ import { envelopeAgeMs, type FederationEnvelope } from "./envelope.js";
30
+
31
+ /** Maximum envelope age we'll trust (5 minutes — matches the
32
+ * HMAC freshness window). Older envelopes fail freshness
33
+ * independently of HMAC verification. */
34
+ export const MAX_TRUST_AGE_MS = 5 * 60 * 1000;
35
+
36
+ /** Minimum composite trust score required to admit an envelope. */
37
+ export const MIN_TRUST_SCORE = 0.7;
38
+
39
+ /** Number of recent failures tracked per peer for fail-rate calc. */
40
+ const FAILURE_WINDOW = 20;
41
+
42
+ export interface PeerState {
43
+ readonly nodeId: string;
44
+ readonly allowlisted: boolean;
45
+ /** Failure rate over the last `FAILURE_WINDOW` calls (0..1). */
46
+ readonly recentFailRate: number;
47
+ /** Last activity timestamp (ms epoch). Used as a tiebreaker. */
48
+ readonly lastSeenMs?: number;
49
+ }
50
+
51
+ export type TrustDecision =
52
+ | { allowed: true; score: number; reason: string }
53
+ | { allowed: false; score: number; reason: string };
54
+
55
+ export class TrustEvaluator {
56
+ private readonly allowlist: Set<string>;
57
+ private readonly failHistory = new Map<string, { failures: boolean[]; lastSeenMs: number }>();
58
+
59
+ constructor(opts: { allowlist?: readonly string[] } = {}) {
60
+ this.allowlist = new Set((opts.allowlist ?? []).map((s) => String(s)));
61
+ }
62
+
63
+ /** Add or remove a node from the trust allowlist at runtime. */
64
+ setAllowlisted(nodeId: string, allowlisted: boolean): void {
65
+ if (allowlisted) this.allowlist.add(nodeId);
66
+ else this.allowlist.delete(nodeId);
67
+ }
68
+
69
+ isAllowlisted(nodeId: string): boolean {
70
+ return this.allowlist.has(nodeId);
71
+ }
72
+
73
+ /** Snapshot the per-peer state seen by `evaluate()`. */
74
+ getPeerState(nodeId: string, _now: number = Date.now()): PeerState {
75
+ const rec = this.failHistory.get(nodeId);
76
+ const total = rec?.failures.length ?? 0;
77
+ const failures = rec?.failures.filter((b) => b).length ?? 0;
78
+ return {
79
+ nodeId,
80
+ allowlisted: this.allowlist.has(nodeId),
81
+ recentFailRate: total === 0 ? 0 : failures / total,
82
+ lastSeenMs: rec?.lastSeenMs,
83
+ };
84
+ }
85
+
86
+ /** Record that an exchange with `nodeId` succeeded/failed. Sliding
87
+ * window of `FAILURE_WINDOW` most-recent events. */
88
+ recordOutcome(nodeId: string, ok: boolean, now: number = Date.now()): void {
89
+ const rec = this.failHistory.get(nodeId) ?? { failures: [], lastSeenMs: now };
90
+ rec.failures.push(!ok);
91
+ if (rec.failures.length > FAILURE_WINDOW) rec.failures.shift();
92
+ rec.lastSeenMs = now;
93
+ this.failHistory.set(nodeId, rec);
94
+ }
95
+
96
+ /** Compute the trust score (0..1). Pure function — useful for tests
97
+ * and for the orchestrator's `status` tool.
98
+ *
99
+ * baseScore = 0.3 if allowlisted else 0.0 (allowlist is necessary, not sufficient)
100
+ * freshness = (1 - ageMs / MAX_TRUST_AGE_MS) * 0.3 (envelope must be fresh)
101
+ * reliability = (1 - peer.recentFailRate) * 0.4 (peer must be reliable)
102
+ *
103
+ * MIN_TRUST_SCORE = 0.5 — a peer needs AT LEAST 2 of the 3 axes
104
+ * in good standing to pass.
105
+ */
106
+ computeScore(envelope: FederationEnvelope, peer: PeerState, now: number = Date.now()): number {
107
+ if (!peer.allowlisted) return 0;
108
+ const baseScore = 0.3;
109
+ const ageMs = envelopeAgeMs(envelope, now);
110
+ const freshness = Math.max(0, Math.min(1, 1 - ageMs / MAX_TRUST_AGE_MS)) * 0.3;
111
+ const reliability = Math.max(0, Math.min(1, 1 - peer.recentFailRate)) * 0.4;
112
+ return Math.max(0, Math.min(1, baseScore + freshness + reliability));
113
+ }
114
+
115
+ /** Admit or reject an envelope based on the per-peer trust state. */
116
+ evaluate(envelope: FederationEnvelope, peer: PeerState, now: number = Date.now()): TrustDecision {
117
+ if (!peer.allowlisted) {
118
+ return {
119
+ allowed: false,
120
+ score: 0,
121
+ reason: `peer_not_allowlisted: ${peer.nodeId}`,
122
+ };
123
+ }
124
+ const ageMs = envelopeAgeMs(envelope, now);
125
+ if (ageMs > MAX_TRUST_AGE_MS) {
126
+ return {
127
+ allowed: false,
128
+ score: 0,
129
+ reason: `envelope_too_old: ${ageMs}ms`,
130
+ };
131
+ }
132
+ const score = this.computeScore(envelope, peer, now);
133
+ if (score < MIN_TRUST_SCORE) {
134
+ return {
135
+ allowed: false,
136
+ score,
137
+ reason: `score_below_floor: ${score.toFixed(3)} < ${MIN_TRUST_SCORE}`,
138
+ };
139
+ }
140
+ return {
141
+ allowed: true,
142
+ score,
143
+ reason: `score=${score.toFixed(3)} (peer_allowlisted=true, age=${ageMs}ms, fail_rate=${peer.recentFailRate.toFixed(3)})`,
144
+ };
145
+ }
146
+ }
@@ -44,4 +44,71 @@ export {
44
44
  } from "./mcp/server.js";
45
45
  export type { SdkMcpToolDef, SdkMcpServerConfig } from "./mcp/server.js";
46
46
 
47
+ // F-032 — Swarm coordination primitives.
48
+ export {
49
+ BizarAgentRegistry,
50
+ bizarAgentRegistry,
51
+ } from "./agent-registry.js";
52
+ export type {
53
+ AgentRecord,
54
+ AgentStatus,
55
+ RegisterAgentInput,
56
+ RegisterAgentResult,
57
+ ListAgentsInput,
58
+ ListAgentsResult,
59
+ TerminateAgentInput,
60
+ TerminateAgentResult,
61
+ } from "./agent-registry.js";
62
+
63
+ export {
64
+ SwarmTopologyRegistry,
65
+ swarmTopologyRegistry,
66
+ initSwarm,
67
+ getSwarm,
68
+ listSwarms,
69
+ recordAgentInSwarm,
70
+ decommissionSwarm,
71
+ SWARM_TOPOLOGIES,
72
+ DEFAULT_TOPOLOGY,
73
+ DEFAULT_MAX_AGENTS,
74
+ DEFAULT_SWARM_ID,
75
+ } from "./swarm-topology.js";
76
+ export type {
77
+ SwarmRecord,
78
+ SwarmTopology,
79
+ InitSwarmInput,
80
+ InitSwarmResult,
81
+ } from "./swarm-topology.js";
82
+
83
+ // F-039 — Byzantine fault-tolerant consensus (thin PBFT port).
84
+ export {
85
+ ByzantineConsensus,
86
+ type ByzantineConsensusOpts,
87
+ QueenCoordinator,
88
+ type QueenCoordinatorOpts,
89
+ createConsensus,
90
+ getSharedConsensus,
91
+ resetSharedConsensus,
92
+ type ConsensusHandle,
93
+ type CreateConsensusOpts,
94
+ PHASE_ORDER,
95
+ DEFAULT_QUORUM,
96
+ DEFAULT_PEER_COUNT,
97
+ DEFAULT_MAX_FAULTS,
98
+ } from "./consensus/index.js";
99
+ export type {
100
+ CommitResult,
101
+ ConsensusOpts,
102
+ ConsensusStatus,
103
+ Decision,
104
+ Phase,
105
+ ProposeResult,
106
+ Proposal,
107
+ ProposalSnapshot,
108
+ ProposalStatus,
109
+ Vote,
110
+ VoteResult,
111
+ ViewChangeResult,
112
+ } from "./consensus/types.js";
113
+
47
114
  export { SDK_VERSION } from "./version.js";