@polderlabs/bizar 6.2.5 → 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 (540) hide show
  1. package/.claude/CLAUDE.md +15 -0
  2. package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
  3. package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
  4. package/.claude/agents/_shared/SKILLS.md +109 -0
  5. package/.claude/agents/agent-browser.md +80 -0
  6. package/.claude/agents/baldr.md +49 -0
  7. package/.claude/agents/forseti.md +51 -0
  8. package/.claude/agents/frigg.md +42 -0
  9. package/.claude/agents/heimdall.md +33 -0
  10. package/.claude/agents/hermod.md +53 -0
  11. package/.claude/agents/mimir.md +49 -0
  12. package/.claude/agents/odin.md +287 -0
  13. package/.claude/agents/quick.md +34 -0
  14. package/.claude/agents/semble-search.md +50 -0
  15. package/.claude/agents/thor.md +53 -0
  16. package/.claude/agents/tyr.md +56 -0
  17. package/.claude/agents/vidarr.md +54 -0
  18. package/.claude/agents/vor.md +53 -0
  19. package/.claude/commands/audit.md +25 -0
  20. package/.claude/commands/bizar.md +22 -0
  21. package/.claude/commands/explain.md +17 -0
  22. package/.claude/commands/init.md +29 -0
  23. package/.claude/commands/learn.md +44 -0
  24. package/.claude/commands/plan.md +35 -0
  25. package/.claude/commands/plow-through.md +50 -0
  26. package/.claude/commands/pr-review.md +49 -0
  27. package/.claude/commands/setup-provider.md +96 -0
  28. package/.claude/commands/tailscale-serve.md +100 -0
  29. package/.claude/commands/team.md +132 -0
  30. package/.claude/commands/test.md +62 -0
  31. package/.claude/commands/validate.md +68 -0
  32. package/.claude/commands/visual-plan.md +24 -0
  33. package/.claude/hooks/README.md +92 -0
  34. package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
  35. package/.claude/hooks/pretooluse-bash.mjs +81 -0
  36. package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
  37. package/.claude/hooks/sessionend-recall.mjs +74 -0
  38. package/.claude/hooks/sessionstart-prime.mjs +80 -0
  39. package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
  40. package/.claude/hooks/worker-suggest.mjs +110 -0
  41. package/.claude/settings.json +125 -0
  42. package/.claude/skills/9router/SKILL.md +80 -0
  43. package/.claude/skills/9router-chat/SKILL.md +73 -0
  44. package/.claude/skills/9router-embeddings/SKILL.md +69 -0
  45. package/.claude/skills/9router-image/SKILL.md +86 -0
  46. package/.claude/skills/9router-stt/SKILL.md +79 -0
  47. package/.claude/skills/9router-tts/SKILL.md +80 -0
  48. package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
  49. package/.claude/skills/9router-web-search/SKILL.md +91 -0
  50. package/.claude/skills/bizar/README.md +9 -0
  51. package/.claude/skills/bizar/SKILL.md +450 -0
  52. package/.claude/skills/cpp-coding-standards/README.md +28 -0
  53. package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
  54. package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
  55. package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
  56. package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
  57. package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
  58. package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
  59. package/.claude/skills/cpp-testing/README.md +28 -0
  60. package/.claude/skills/cpp-testing/SKILL.md +304 -0
  61. package/.claude/skills/cpp-testing/references/coverage.md +370 -0
  62. package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
  63. package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
  64. package/.claude/skills/cpp-testing/references/mocking.md +364 -0
  65. package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
  66. package/.claude/skills/cubesandbox/SKILL.md +148 -0
  67. package/.claude/skills/embedded-esp-idf/README.md +41 -0
  68. package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
  69. package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
  70. package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
  71. package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
  72. package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
  73. package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
  74. package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
  75. package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
  76. package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
  77. package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
  78. package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
  79. package/.claude/skills/glyph/SKILL.md +163 -0
  80. package/.claude/skills/harness-engineering/SKILL.md +143 -0
  81. package/.claude/skills/lightrag/SKILL.md +81 -0
  82. package/.claude/skills/memory-protocol/SKILL.md +105 -0
  83. package/.claude/skills/obsidian/SKILL.md +306 -0
  84. package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
  85. package/.claude/skills/self-improvement/SKILL.md +64 -0
  86. package/README.md +87 -59
  87. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-CW6fWKds.js} +3 -3
  88. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
  89. package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
  90. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
  91. package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
  92. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
  93. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
  94. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
  95. package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
  96. package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
  97. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
  98. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
  99. package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
  100. package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
  101. package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
  102. package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
  103. package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
  104. package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
  105. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-w2bDDkAH.js.map} +1 -1
  106. package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
  107. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DXYCA0hC.js.map} +1 -1
  108. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
  109. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
  110. package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
  111. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
  112. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
  113. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
  114. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
  115. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
  116. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
  117. package/bizar-dash/dist/index.html +12 -10
  118. package/bizar-dash/dist/mobile.html +7 -4
  119. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  120. package/bizar-dash/src/server/api.mjs +15 -4
  121. package/bizar-dash/src/server/background-store.mjs +15 -16
  122. package/bizar-dash/src/server/bg-poller.mjs +25 -35
  123. package/bizar-dash/src/server/bg-retry.mjs +66 -194
  124. package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
  125. package/bizar-dash/src/server/claude-info.mjs +412 -0
  126. package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
  127. package/bizar-dash/src/server/claude-sdk.mjs +191 -0
  128. package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
  129. package/bizar-dash/src/server/memory-distillation.mjs +296 -0
  130. package/bizar-dash/src/server/providers-store.mjs +22 -49
  131. package/bizar-dash/src/server/routes/background.mjs +24 -20
  132. package/bizar-dash/src/server/routes/chat.mjs +223 -326
  133. package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
  134. package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
  135. package/bizar-dash/src/server/routes/distill.mjs +129 -0
  136. package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
  137. package/bizar-dash/src/server/routes/tasks.mjs +20 -28
  138. package/bizar-dash/src/server/task-delegator.mjs +76 -77
  139. package/bizar-dash/src/web/App.tsx +4 -0
  140. package/bizar-dash/src/web/components/Tag.tsx +18 -5
  141. package/bizar-dash/src/web/components/Topbar.tsx +3 -0
  142. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
  143. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
  144. package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
  145. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
  146. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
  147. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
  148. package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
  149. package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
  150. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
  151. package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
  152. package/bizar-dash/src/web/lib/types.ts +25 -0
  153. package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
  154. package/bizar-dash/src/web/styles/main.css +251 -0
  155. package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
  156. package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
  157. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
  158. package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
  159. package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
  160. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
  161. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
  162. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
  163. package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
  164. package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
  165. package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
  166. package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
  167. package/bizar-dash/src/web/ui/controls/controls.css +454 -0
  168. package/bizar-dash/src/web/ui/controls/index.ts +33 -0
  169. package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
  170. package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
  171. package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
  172. package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
  173. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
  174. package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
  175. package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
  176. package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
  177. package/bizar-dash/src/web/ui/data/data.css +535 -0
  178. package/bizar-dash/src/web/ui/data/index.ts +31 -0
  179. package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
  180. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
  181. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
  182. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
  183. package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
  184. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
  185. package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
  186. package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
  187. package/bizar-dash/src/web/ui/index.ts +56 -0
  188. package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
  189. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
  190. package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
  191. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
  192. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
  193. package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
  194. package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
  195. package/bizar-dash/src/web/ui/layout/index.ts +33 -0
  196. package/bizar-dash/src/web/ui/layout/layout.css +413 -0
  197. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
  198. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
  199. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
  200. package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
  201. package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
  202. package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
  203. package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
  204. package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
  205. package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
  206. package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
  207. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
  208. package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
  209. package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
  210. package/bizar-dash/src/web/ui/styles/globals.css +86 -0
  211. package/bizar-dash/src/web/ui/styles/reset.css +125 -0
  212. package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
  213. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
  214. package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
  215. package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
  216. package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
  217. package/bizar-dash/src/web/views/Agents.tsx +506 -266
  218. package/bizar-dash/src/web/views/Chat.tsx +8 -8
  219. package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
  220. package/bizar-dash/src/web/views/Overview.tsx +996 -448
  221. package/bizar-dash/src/web/views/Tasks.tsx +277 -273
  222. package/bizar-dash/tests/communication-log.test.tsx +67 -0
  223. package/bizar-dash/tests/dep-graph.test.tsx +40 -0
  224. package/bizar-dash/tests/event-log.test.tsx +61 -0
  225. package/bizar-dash/tests/goal-input.test.tsx +72 -0
  226. package/bizar-dash/tests/goap-planner.test.ts +68 -0
  227. package/bizar-dash/tests/quality-gates.test.tsx +59 -0
  228. package/bizar-dash/tests/setup.ts +31 -1
  229. package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
  230. package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
  231. package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
  232. package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
  233. package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
  234. package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
  235. package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
  236. package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
  237. package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
  238. package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
  239. package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
  240. package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
  241. package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
  242. package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
  243. package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
  244. package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
  245. package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
  246. package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
  247. package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
  248. package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
  249. package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
  250. package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
  251. package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
  252. package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
  253. package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
  254. package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
  255. package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
  256. package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
  257. package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
  258. package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
  259. package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
  260. package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
  261. package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
  262. package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
  263. package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
  264. package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
  265. package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
  266. package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
  267. package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
  268. package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
  269. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
  270. package/bizar-dash/tests/views/Agents.test.tsx +359 -0
  271. package/bizar-dash/tests/views/Overview.test.tsx +413 -0
  272. package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
  273. package/bizar-dash/vitest.config.ts +3 -1
  274. package/cli/__tests__/cost-gate.test.mjs +301 -0
  275. package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
  276. package/cli/bin.mjs +55 -18
  277. package/cli/commands/claim.mjs +282 -0
  278. package/cli/commands/claude-cmd.mjs +348 -0
  279. package/cli/commands/cost.mjs +279 -0
  280. package/cli/commands/install.mjs +12 -11
  281. package/cli/commands/validate.mjs +252 -325
  282. package/cli/cost-gate.mjs +501 -0
  283. package/cli/dev-link.test.mjs +11 -11
  284. package/cli/doctor.mjs +131 -213
  285. package/cli/feature-list-bridge.mjs +400 -0
  286. package/cli/install.mjs +33 -37
  287. package/cli/install.test.mjs +9 -9
  288. package/cli/memory-constants.mjs +17 -0
  289. package/cli/provision-claude.mjs +893 -0
  290. package/cli/provision.mjs +224 -227
  291. package/cli/utils.mjs +72 -58
  292. package/cli/worker-dispatcher.mjs +259 -0
  293. package/cli/worker-dispatcher.test.mjs +204 -0
  294. package/config/AGENTS.md +28 -28
  295. package/config/trigger-patterns.json +186 -0
  296. package/install.sh +66 -44
  297. package/package.json +19 -11
  298. package/packages/sdk/ARCHITECTURE.md +40 -36
  299. package/packages/sdk/package.json +15 -5
  300. package/packages/sdk/src/agent-registry.ts +304 -0
  301. package/packages/sdk/src/consensus/byzantine.ts +587 -0
  302. package/packages/sdk/src/consensus/index.ts +147 -0
  303. package/packages/sdk/src/consensus/queen.ts +173 -0
  304. package/packages/sdk/src/consensus/types.ts +199 -0
  305. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  306. package/packages/sdk/src/federation/audit.ts +156 -0
  307. package/packages/sdk/src/federation/budget.ts +269 -0
  308. package/packages/sdk/src/federation/envelope.ts +144 -0
  309. package/packages/sdk/src/federation/hmac.ts +160 -0
  310. package/packages/sdk/src/federation/index.ts +443 -0
  311. package/packages/sdk/src/federation/pii.ts +241 -0
  312. package/packages/sdk/src/federation/policy.ts +112 -0
  313. package/packages/sdk/src/federation/trust.ts +146 -0
  314. package/packages/sdk/src/fingerprint.ts +0 -0
  315. package/packages/sdk/src/index.ts +101 -69
  316. package/packages/sdk/src/mcp/bin.ts +51 -0
  317. package/packages/sdk/src/mcp/server.ts +848 -0
  318. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  319. package/packages/sdk/src/router/codemod-intent.ts +125 -0
  320. package/packages/sdk/src/router/index.ts +247 -0
  321. package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
  322. package/packages/sdk/src/router/memory-distillation.ts +249 -0
  323. package/packages/sdk/src/router/model-router.ts +235 -0
  324. package/packages/sdk/src/router/q-learning-router.ts +304 -0
  325. package/packages/sdk/src/swarm-topology.ts +279 -0
  326. package/packages/sdk/tests/agent-registry.test.ts +285 -0
  327. package/packages/sdk/tests/consensus.test.ts +376 -0
  328. package/packages/sdk/tests/federation/audit.test.ts +164 -0
  329. package/packages/sdk/tests/federation/budget.test.ts +189 -0
  330. package/packages/sdk/tests/federation/envelope.test.ts +120 -0
  331. package/packages/sdk/tests/federation/hmac.test.ts +194 -0
  332. package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
  333. package/packages/sdk/tests/federation/pii.test.ts +106 -0
  334. package/packages/sdk/tests/federation/policy.test.ts +140 -0
  335. package/packages/sdk/tests/federation/trust.test.ts +124 -0
  336. package/packages/sdk/tests/mcp-tools.test.ts +204 -0
  337. package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
  338. package/packages/sdk/tests/model-router.test.mjs +108 -0
  339. package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
  340. package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
  341. package/packages/sdk/tests/router.test.mjs +91 -0
  342. package/packages/sdk/tests/sdk.test.mjs +172 -0
  343. package/packages/sdk/tests/swarm-topology.test.ts +258 -0
  344. package/packages/sdk/vitest.config.ts +1 -1
  345. package/scripts/bh-full-e2e.mjs +167 -368
  346. package/scripts/check-deps.mjs +28 -46
  347. package/scripts/mirror-claude-md.sh +78 -0
  348. package/scripts/test-in-container.sh +31 -9
  349. package/templates/clean-state-checklist.md +3 -3
  350. package/templates/sprint-contract.md +2 -2
  351. package/bizar-dash/.bizar/activity.log +0 -3
  352. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  353. package/bizar-dash/.omx/state/session.json +0 -10
  354. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  355. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  356. package/bizar-dash/bizar-design/canvas.html +0 -281
  357. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  358. package/bizar-dash/bizar-design/components.css +0 -1665
  359. package/bizar-dash/bizar-design/components.html +0 -557
  360. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  361. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  362. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  363. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  364. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  365. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  366. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  367. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  368. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  369. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  370. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  371. package/bizar-dash/bizar-design/icons.svg +0 -44
  372. package/bizar-dash/bizar-design/index.html +0 -192
  373. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  374. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  375. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  376. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  377. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  378. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  379. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  380. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  381. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  382. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  383. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  384. package/bizar-dash/bizar-design/prototype.js +0 -114
  385. package/bizar-dash/bizar-design/tokens.css +0 -106
  386. package/bizar-dash/dist/assets/MobileChat-BnKN_Ks_.js +0 -1
  387. package/bizar-dash/dist/assets/MobileSettings-DjCPxC-Q.js +0 -1
  388. package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
  389. package/bizar-dash/dist/assets/main-DYiZqMrn.js +0 -18
  390. package/bizar-dash/dist/assets/main-DYiZqMrn.js.map +0 -1
  391. package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
  392. package/bizar-dash/dist/assets/markdown-C6mXtQxD.js +0 -1
  393. package/bizar-dash/dist/assets/mobile-CMHqtLV2.js +0 -1
  394. package/bizar-dash/dist/assets/mobile-layout-3jIhHX_p.js +0 -2
  395. package/bizar-dash/dist/assets/mobile-layout-3jIhHX_p.js.map +0 -1
  396. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
  397. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
  398. package/bizar-dash/dist/assets/useSlashCommands-DtITw8Xv.js +0 -2
  399. package/bizar-dash/dist/assets/useSlashCommands-DtITw8Xv.js.map +0 -1
  400. package/bizar-dash/dist/assets/vendor-CeHGtduv.js +0 -29
  401. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  402. package/bizar-dash/node_modules/.package-lock.json +0 -6
  403. package/bizar-dash/package-lock.json +0 -6
  404. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  405. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  406. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  407. package/cli/commands/cline-cmd.mjs +0 -289
  408. package/cli/commands/validate.test.mjs +0 -379
  409. package/cli/doctor.test.mjs +0 -350
  410. package/config/cline.json.template +0 -342
  411. package/packages/sdk/src/client.ts +0 -188
  412. package/packages/sdk/src/cline-events.ts +0 -134
  413. package/packages/sdk/src/cline-types.ts +0 -66
  414. package/packages/sdk/src/cline.ts +0 -339
  415. package/packages/sdk/src/errors.ts +0 -129
  416. package/packages/sdk/src/events.ts +0 -153
  417. package/packages/sdk/src/types.ts +0 -176
  418. package/packages/sdk/tests/client.test.ts +0 -217
  419. package/packages/sdk/tests/errors.test.ts +0 -108
  420. package/packages/sdk/tests/events.test.ts +0 -139
  421. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  422. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  423. package/plugins/bizar/ARCHITECTURE.md +0 -142
  424. package/plugins/bizar/CONSTRAINTS.md +0 -67
  425. package/plugins/bizar/LICENSE +0 -21
  426. package/plugins/bizar/README.md +0 -448
  427. package/plugins/bizar/index.ts +0 -925
  428. package/plugins/bizar/package.json +0 -39
  429. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  430. package/plugins/bizar/src/background-state.ts +0 -641
  431. package/plugins/bizar/src/background.ts +0 -1806
  432. package/plugins/bizar/src/cline-runner.ts +0 -203
  433. package/plugins/bizar/src/clineruntime.ts +0 -227
  434. package/plugins/bizar/src/commands-impl.ts +0 -151
  435. package/plugins/bizar/src/commands.ts +0 -1799
  436. package/plugins/bizar/src/compaction.d.mts +0 -48
  437. package/plugins/bizar/src/compaction.mjs +0 -192
  438. package/plugins/bizar/src/dashboard-client.ts +0 -233
  439. package/plugins/bizar/src/event-stream.ts +0 -606
  440. package/plugins/bizar/src/fingerprint.ts +0 -120
  441. package/plugins/bizar/src/handoff.ts +0 -79
  442. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  443. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  444. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  445. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  446. package/plugins/bizar/src/http-client.ts +0 -467
  447. package/plugins/bizar/src/key-rotation.ts +0 -218
  448. package/plugins/bizar/src/logger.ts +0 -144
  449. package/plugins/bizar/src/loop-engineering.ts +0 -241
  450. package/plugins/bizar/src/loop.ts +0 -176
  451. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  452. package/plugins/bizar/src/odin.ts +0 -227
  453. package/plugins/bizar/src/options.ts +0 -470
  454. package/plugins/bizar/src/plan-fs.ts +0 -323
  455. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  456. package/plugins/bizar/src/report.ts +0 -178
  457. package/plugins/bizar/src/research-prompt.ts +0 -35
  458. package/plugins/bizar/src/serve-info.ts +0 -228
  459. package/plugins/bizar/src/serve.ts +0 -496
  460. package/plugins/bizar/src/settings.ts +0 -349
  461. package/plugins/bizar/src/state.ts +0 -298
  462. package/plugins/bizar/src/tool-discipline.ts +0 -105
  463. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  464. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  465. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  466. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  467. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  468. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  469. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  470. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  471. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  472. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  473. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  474. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  475. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  476. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  477. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  478. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  479. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  480. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  481. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  482. package/plugins/bizar/src/tools/sandbox.ts +0 -232
  483. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  484. package/plugins/bizar/src/tools/team-status.ts +0 -76
  485. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  486. package/plugins/bizar/src/trajectory.ts +0 -104
  487. package/plugins/bizar/tests/README.md +0 -99
  488. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  489. package/plugins/bizar/tests/background-state.test.ts +0 -277
  490. package/plugins/bizar/tests/background.test.ts +0 -402
  491. package/plugins/bizar/tests/block.test.ts +0 -195
  492. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  493. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  494. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  495. package/plugins/bizar/tests/commands.test.ts +0 -584
  496. package/plugins/bizar/tests/compaction.test.ts +0 -264
  497. package/plugins/bizar/tests/config.test.ts +0 -128
  498. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  499. package/plugins/bizar/tests/dispose.test.ts +0 -336
  500. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  501. package/plugins/bizar/tests/event.test.ts +0 -262
  502. package/plugins/bizar/tests/fingerprint.test.ts +0 -190
  503. package/plugins/bizar/tests/http-client.test.ts +0 -404
  504. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  505. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  506. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  507. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  508. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  509. package/plugins/bizar/tests/loop.test.ts +0 -397
  510. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  511. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  512. package/plugins/bizar/tests/odin.test.ts +0 -125
  513. package/plugins/bizar/tests/options.test.ts +0 -329
  514. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  515. package/plugins/bizar/tests/safety.test.ts +0 -281
  516. package/plugins/bizar/tests/serve.test.ts +0 -339
  517. package/plugins/bizar/tests/settings.test.ts +0 -351
  518. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  519. package/plugins/bizar/tests/state.test.ts +0 -276
  520. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  521. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  522. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  523. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  524. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  525. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  526. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  527. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  528. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  529. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  530. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  531. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  532. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  533. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  534. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  535. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  536. package/plugins/bizar/tests/tools/sandbox.test.ts +0 -117
  537. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  538. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  539. package/plugins/bizar/tsconfig.json +0 -29
  540. package/scripts/mirror-agents-md.sh +0 -69
@@ -0,0 +1,160 @@
1
+ /**
2
+ * federation/hmac.ts — HMAC-SHA-256 signing + verification for
3
+ * federation envelopes.
4
+ *
5
+ * F-038 — security-critical. Pinned by AGENTS.md hard constraint:
6
+ * "MUST use crypto.timingSafeEqual for HMAC comparison
7
+ * (timing-attack resistant)."
8
+ * "MUST use crypto.randomUUID() for nonces (128-bit random)."
9
+ *
10
+ * Nonce strategy:
11
+ * - Sender generates a fresh `crypto.randomUUID()` per envelope.
12
+ * - Receiver tracks every nonce it has seen in a TTL-bounded Set.
13
+ * - An envelope whose nonce appears twice is a replay → reject.
14
+ * - An envelope whose timestamp is older than `nonceWindowMs`
15
+ * (default 5 min) is also a replay → reject.
16
+ *
17
+ * No native deps. Pure Node `node:crypto`.
18
+ */
19
+
20
+ import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
21
+ import {
22
+ canonicalSignablePayload,
23
+ type FederationEnvelope,
24
+ } from "./envelope.js";
25
+
26
+ /** Default freshness window for HMAC verification (5 minutes). */
27
+ export const DEFAULT_NONCE_WINDOW_MS = 5 * 60 * 1000;
28
+
29
+ /** Cap on the receiver's seen-nonce set so it can't grow unbounded. */
30
+ const SEEN_NONCE_CAP = 10_000;
31
+
32
+ /** Compute a deterministic 64-char hex HMAC-SHA-256 over the envelope's
33
+ * canonical signable payload. */
34
+ export function signEnvelope<T>(
35
+ envelope: FederationEnvelope<T>,
36
+ secret: string,
37
+ ): string {
38
+ if (typeof secret !== "string" || secret.length === 0) {
39
+ throw new Error("signEnvelope: secret must be a non-empty string");
40
+ }
41
+ const payload = canonicalSignablePayload(envelope);
42
+ return createHmac("sha256", secret).update(payload).digest("hex");
43
+ }
44
+
45
+ export interface VerifyOptions {
46
+ /** Freshness window. Envelopes older than this are rejected.
47
+ * Defaults to 5 minutes. */
48
+ readonly nonceWindowMs?: number;
49
+ /** Optional clock-skew offset (ms) to *add* to the freshness
50
+ * window (e.g. for poorly-synced peers). Defaults to 0. */
51
+ readonly clockSkewMs?: number;
52
+ /** Optional explicit timestamp for deterministic tests. */
53
+ readonly now?: number;
54
+ }
55
+
56
+ export type VerifyOutcome =
57
+ | { ok: true }
58
+ | {
59
+ ok: false;
60
+ reason:
61
+ | "signature_mismatch"
62
+ | "nonce_replay"
63
+ | "envelope_expired"
64
+ | "envelope_from_future"
65
+ | "invalid_signature_format";
66
+ };
67
+
68
+ /** Pure verifier — no shared state. The caller owns the seen-nonce
69
+ * cache (see `NonceCache` below) and passes it in via `seen`. */
70
+ export function verifySignature<T>(
71
+ envelope: FederationEnvelope<T>,
72
+ secret: string,
73
+ seen: ReadonlySet<string>,
74
+ opts: VerifyOptions = {},
75
+ ): VerifyOutcome {
76
+ if (typeof secret !== "string" || secret.length === 0) {
77
+ return { ok: false, reason: "invalid_signature_format" };
78
+ }
79
+ if (typeof envelope.hmacSignature !== "string" || envelope.hmacSignature.length === 0) {
80
+ return { ok: false, reason: "invalid_signature_format" };
81
+ }
82
+
83
+ // Freshness — reject before we touch the HMAC code path so we
84
+ // don't burn cycles on ancient replays.
85
+ const now = opts.now ?? Date.now();
86
+ const ts = new Date(envelope.timestamp).getTime();
87
+ if (!Number.isFinite(ts)) return { ok: false, reason: "envelope_expired" };
88
+ const ageMs = now - ts;
89
+ const window = (opts.nonceWindowMs ?? DEFAULT_NONCE_WINDOW_MS) + (opts.clockSkewMs ?? 0);
90
+ if (ageMs > window) return { ok: false, reason: "envelope_expired" };
91
+ if (ageMs < -window) return { ok: false, reason: "envelope_from_future" };
92
+
93
+ // Nonce replay — checked AFTER freshness so a delayed-but-unique
94
+ // envelope doesn't get falsely fingerprinted as a replay.
95
+ if (seen.has(envelope.nonce)) return { ok: false, reason: "nonce_replay" };
96
+
97
+ // Constant-time signature compare. Both buffers must be the same
98
+ // length for timingSafeEqual; if lengths differ, signature_mismatch.
99
+ const expected = signEnvelope(envelope, secret);
100
+ const a = Buffer.from(expected, "hex");
101
+ let b: Buffer;
102
+ try {
103
+ b = Buffer.from(envelope.hmacSignature, "hex");
104
+ } catch {
105
+ return { ok: false, reason: "invalid_signature_format" };
106
+ }
107
+ if (a.length !== b.length) return { ok: false, reason: "signature_mismatch" };
108
+ if (!timingSafeEqual(a, b)) return { ok: false, reason: "signature_mismatch" };
109
+
110
+ return { ok: true };
111
+ }
112
+
113
+ /** Mutable nonce cache with TTL eviction + hard cap. The receiver
114
+ * keeps one per remote node (or a single global one for the skeleton). */
115
+ export class NonceCache {
116
+ private readonly seen = new Map<string, number>(); // nonce → expiryMs
117
+ private readonly windowMs: number;
118
+
119
+ constructor(windowMs: number = DEFAULT_NONCE_WINDOW_MS) {
120
+ this.windowMs = windowMs;
121
+ }
122
+
123
+ /** True if the nonce is fresh (not seen in windowMs). Adds it
124
+ * to the cache as a side effect. */
125
+ check(nonce: string, now: number = Date.now()): boolean {
126
+ this.evict(now);
127
+ if (this.seen.has(nonce)) return false;
128
+ if (this.seen.size >= SEEN_NONCE_CAP) {
129
+ // Hard cap — evict the oldest entry to make room.
130
+ const oldest = this.seen.keys().next().value;
131
+ if (oldest !== undefined) this.seen.delete(oldest);
132
+ }
133
+ this.seen.set(nonce, now + this.windowMs);
134
+ return true;
135
+ }
136
+
137
+ /** True if the nonce is in the cache (read-only). */
138
+ has(nonce: string): boolean {
139
+ return this.seen.has(nonce);
140
+ }
141
+
142
+ size(): number {
143
+ return this.seen.size;
144
+ }
145
+
146
+ clear(): void {
147
+ this.seen.clear();
148
+ }
149
+
150
+ private evict(now: number): void {
151
+ for (const [nonce, expiry] of this.seen) {
152
+ if (expiry <= now) this.seen.delete(nonce);
153
+ }
154
+ }
155
+ }
156
+
157
+ /** Helper — produce a fresh nonce via `crypto.randomUUID()`. */
158
+ export function freshNonce(): string {
159
+ return randomUUID();
160
+ }
@@ -0,0 +1,443 @@
1
+ /**
2
+ * federation/index.ts — top-level orchestrator + public exports.
3
+ *
4
+ * F-038 — composes the eight federation primitives into a single
5
+ * `createFederation(opts)` factory. The orchestrator wires:
6
+ *
7
+ * sign — produce a signed FederationEnvelope (with fresh nonce +
8
+ * PII redaction + audit log entry).
9
+ * verify — verify an inbound envelope (HMAC + nonce window +
10
+ * trust + policy + audit log entry).
11
+ * send — high-level helper: sign + persist outgoing audit.
12
+ * receive — high-level helper: verify + accept-or-reject + persist
13
+ * inbound audit.
14
+ * status — snapshot for the `federation_status` MCP tool.
15
+ *
16
+ * No native deps. Pure TS over Node `crypto` + `fs`.
17
+ */
18
+
19
+ import { randomUUID } from "node:crypto";
20
+
21
+ import {
22
+ canonicalSignablePayload,
23
+ emptyScanResult,
24
+ type EnvelopeBudget,
25
+ type FederationEnvelope,
26
+ type FederationMessageType,
27
+ } from "./envelope.js";
28
+ import { freshNonce, NonceCache, signEnvelope, verifySignature } from "./hmac.js";
29
+ import { apply, isPiiMode, type PiiMode, type PiiResult } from "./pii.js";
30
+ import { TrustEvaluator, type PeerState } from "./trust.js";
31
+ import { PolicyEngine, type PolicyDecision } from "./policy.js";
32
+ import { AuditService } from "./audit.js";
33
+ import { FederationBudget, validateBudgetInput, type PerPeerBudget } from "./budget.js";
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Public re-exports
37
+ // ---------------------------------------------------------------------------
38
+
39
+ export {
40
+ FEDERATION_MESSAGE_TYPES,
41
+ TRUST_AFFECTING_MESSAGE_TYPES,
42
+ isFederationMessageType,
43
+ canonicalSignablePayload,
44
+ envelopeAgeMs,
45
+ emptyScanResult,
46
+ type EnvelopeBudget,
47
+ type FederationEnvelope,
48
+ type FederationMessageType,
49
+ type PiiScanAction,
50
+ type PiiScanDetection,
51
+ type PiiScanResult,
52
+ } from "./envelope.js";
53
+
54
+ export {
55
+ DEFAULT_NONCE_WINDOW_MS,
56
+ NonceCache,
57
+ freshNonce,
58
+ signEnvelope,
59
+ verifySignature,
60
+ type VerifyOptions,
61
+ type VerifyOutcome,
62
+ } from "./hmac.js";
63
+
64
+ export {
65
+ PII_MODES,
66
+ isPiiMode,
67
+ PiiPipeline,
68
+ apply,
69
+ type ApplyOptions,
70
+ type PiiAction,
71
+ type PiiCategory,
72
+ type PiiDetection,
73
+ type PiiMode,
74
+ type PiiResult,
75
+ } from "./pii.js";
76
+
77
+ export {
78
+ MAX_TRUST_AGE_MS,
79
+ MIN_TRUST_SCORE,
80
+ TrustEvaluator,
81
+ type PeerState,
82
+ type TrustDecision,
83
+ } from "./trust.js";
84
+
85
+ export {
86
+ DEFAULT_MAX_HOPS,
87
+ PolicyEngine,
88
+ type PolicyConfig,
89
+ type PolicyDecision,
90
+ } from "./policy.js";
91
+
92
+ export {
93
+ DEFAULT_AUDIT_PATH,
94
+ AuditService,
95
+ type AuditDecision,
96
+ type AuditEntry,
97
+ type AuditServiceOpts,
98
+ } from "./audit.js";
99
+
100
+ export {
101
+ DEFAULT_BUDGET_PATH,
102
+ MAX_TOKENS_CEILING,
103
+ MAX_USD_CEILING,
104
+ FederationBudget,
105
+ validateBudgetInput,
106
+ type FederationBudgetOpts,
107
+ type PerPeerBudget,
108
+ type ReserveResult,
109
+ } from "./budget.js";
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // Orchestrator
113
+ // ---------------------------------------------------------------------------
114
+
115
+ export interface FederationStatusSnapshot {
116
+ readonly nodeId: string;
117
+ readonly nonceCacheSize: number;
118
+ readonly auditSizeBytes: number;
119
+ readonly auditPath: string;
120
+ readonly budget: {
121
+ readonly path: string;
122
+ readonly perPeer: readonly PerPeerBudget[];
123
+ readonly outstandingReservations: number;
124
+ };
125
+ readonly peers: readonly PeerState[];
126
+ }
127
+
128
+ export interface CreateFederationOpts {
129
+ /** Local node id stamped into audit + status payloads. */
130
+ readonly nodeId: string;
131
+ /** Shared HMAC secret. Sender + receiver MUST match. */
132
+ readonly secret: string;
133
+ /** PII redaction mode applied on `sign()`. */
134
+ readonly piiMode?: PiiMode;
135
+ /** Override audit log path. */
136
+ readonly auditPath?: string;
137
+ /** Override budget JSON path. */
138
+ readonly budgetPath?: string;
139
+ /** Optional explicit PolicyEngine (for custom allowlists/blocklists). */
140
+ readonly policy?: PolicyEngine;
141
+ /** Optional explicit TrustEvaluator (custom allowlist). */
142
+ readonly trust?: TrustEvaluator;
143
+ /** Optional explicit AuditService (test-only override). */
144
+ readonly audit?: AuditService;
145
+ /** Optional explicit FederationBudget (test-only override). */
146
+ readonly budget?: FederationBudget;
147
+ }
148
+
149
+ export interface FederationHandle {
150
+ readonly nodeId: string;
151
+ /** PII redaction mode currently in effect. */
152
+ getPiiMode(): PiiMode;
153
+ setPiiMode(mode: PiiMode): void;
154
+ /** Sign + redact + audit. The resulting envelope is ready to
155
+ * transmit to the peer. */
156
+ sign<T>(input: SignInput<T>): FederationEnvelope<T>;
157
+ /** Verify + admit-or-reject + audit. The caller decides what
158
+ * to do with the result. */
159
+ receive<T>(envelope: FederationEnvelope<T>): ReceiveResult;
160
+ /** Snapshot for the `federation_status` MCP tool. */
161
+ status(): FederationStatusSnapshot;
162
+ /** Direct access to the underlying services — for advanced
163
+ * consumers + tests. */
164
+ readonly services: {
165
+ readonly trust: TrustEvaluator;
166
+ readonly policy: PolicyEngine;
167
+ readonly audit: AuditService;
168
+ readonly budget: FederationBudget;
169
+ readonly nonces: NonceCache;
170
+ };
171
+ }
172
+
173
+ export interface SignInput<T> {
174
+ readonly targetNodeId: string;
175
+ readonly sessionId: string;
176
+ readonly messageType: FederationMessageType;
177
+ readonly payload: T;
178
+ readonly budget?: EnvelopeBudget;
179
+ /** If true, skip PII redaction. Defaults to false. */
180
+ readonly skipPii?: boolean;
181
+ }
182
+
183
+ export interface ReceiveResult {
184
+ readonly trusted: boolean;
185
+ readonly policyAllowed: boolean;
186
+ readonly hmacValid: boolean;
187
+ readonly pii: PiiResult;
188
+ readonly envelope: FederationEnvelope;
189
+ readonly rejectionReason?: string;
190
+ }
191
+
192
+ /** Build the orchestrator handle. */
193
+ export function createFederation(opts: CreateFederationOpts): FederationHandle {
194
+ if (!opts || typeof opts.nodeId !== "string" || opts.nodeId.length === 0) {
195
+ throw new Error("createFederation: nodeId is required");
196
+ }
197
+ if (typeof opts.secret !== "string" || opts.secret.length === 0) {
198
+ throw new Error("createFederation: secret is required");
199
+ }
200
+ const modeRef: { value: PiiMode } = { value: isPiiMode(opts.piiMode) ? opts.piiMode : "soc2" };
201
+
202
+ const trust = opts.trust ?? new TrustEvaluator({ allowlist: [] });
203
+ const policy = opts.policy ?? new PolicyEngine();
204
+ const audit = opts.audit ?? new AuditService({ nodeId: opts.nodeId, path: opts.auditPath });
205
+ const budget = opts.budget ?? new FederationBudget({ path: opts.budgetPath });
206
+ const nonces = new NonceCache();
207
+
208
+ function getPiiMode(): PiiMode { return modeRef.value; }
209
+ function setPiiMode(m: PiiMode): void {
210
+ if (!isPiiMode(m)) throw new Error(`unknown PII mode: ${m}`);
211
+ modeRef.value = m;
212
+ }
213
+
214
+ function sign<T>(input: SignInput<T>): FederationEnvelope<T> {
215
+ const validated = input.budget
216
+ ? validateBudgetInput(input.budget)
217
+ : { ok: true as const, maxTokens: Number.POSITIVE_INFINITY, maxUsd: Number.POSITIVE_INFINITY, maxHops: 8 };
218
+ if (!validated.ok) throw new Error(`sign: bad budget: ${validated.error}`);
219
+
220
+ const env: FederationEnvelope<T> = {
221
+ envelopeId: randomUUID(),
222
+ sourceNodeId: opts.nodeId,
223
+ targetNodeId: input.targetNodeId,
224
+ sessionId: input.sessionId,
225
+ messageType: input.messageType,
226
+ payload: input.payload,
227
+ timestamp: new Date().toISOString(),
228
+ nonce: freshNonce(),
229
+ hmacSignature: "", // filled in below
230
+ piiScanResult: emptyScanResult(),
231
+ budget: {
232
+ maxTokens: validated.maxTokens,
233
+ maxUsd: validated.maxUsd,
234
+ maxHops: validated.maxHops,
235
+ },
236
+ hopCount: 0,
237
+ hopsRemaining: validated.maxHops,
238
+ };
239
+
240
+ // PII redaction over the stringified payload — keep the result
241
+ // in `piiScanResult` so the receiver can audit what was stripped.
242
+ let pii: PiiResult = { transformed: "", detections: [], actionsApplied: [], blocked: false, mode: modeRef.value };
243
+ if (!input.skipPii && typeof input.payload === "string") {
244
+ pii = apply(input.payload, modeRef.value);
245
+ if (pii.blocked) {
246
+ audit.record({
247
+ ts: new Date().toISOString(),
248
+ envelopeId: env.envelopeId,
249
+ sourceNodeId: env.sourceNodeId,
250
+ targetNodeId: env.targetNodeId,
251
+ messageType: env.messageType,
252
+ nonce: env.nonce,
253
+ allowed: false,
254
+ reason: `pii_blocked (mode=${modeRef.value})`,
255
+ layer: "budget",
256
+ });
257
+ }
258
+ }
259
+
260
+ const finalEnv: FederationEnvelope<T> = {
261
+ ...env,
262
+ payload: (pii.transformed ? (pii.transformed as unknown as T) : input.payload),
263
+ piiScanResult: pii.detections.length > 0
264
+ ? {
265
+ scanned: true,
266
+ piiFound: true,
267
+ detections: pii.detections.map((d) => ({
268
+ type: d.category,
269
+ action: "redact",
270
+ confidence: d.confidence,
271
+ count: 1,
272
+ })),
273
+ actionsApplied: pii.actionsApplied.map((a) => a.action),
274
+ scanDurationMs: 0,
275
+ }
276
+ : emptyScanResult(),
277
+ };
278
+
279
+ const signature = signEnvelope(finalEnv, opts.secret);
280
+ const signed: FederationEnvelope<T> = { ...finalEnv, hmacSignature: signature };
281
+
282
+ audit.record({
283
+ ts: signed.timestamp,
284
+ envelopeId: signed.envelopeId,
285
+ sourceNodeId: signed.sourceNodeId,
286
+ targetNodeId: signed.targetNodeId,
287
+ messageType: signed.messageType,
288
+ nonce: signed.nonce,
289
+ allowed: true,
290
+ reason: `signed (pii_mode=${modeRef.value})`,
291
+ layer: "sent",
292
+ });
293
+ return signed;
294
+ }
295
+
296
+ function receive<T>(envelope: FederationEnvelope<T>): ReceiveResult {
297
+ // 1. HMAC + freshness + nonce replay
298
+ const verifyOut = verifySignature(envelope, opts.secret, nonces as unknown as ReadonlySet<string>);
299
+ if (verifyOut.ok) {
300
+ nonces.check(envelope.nonce);
301
+ }
302
+
303
+ const piiScanResult = envelope.piiScanResult ?? emptyScanResult();
304
+ const pii: PiiResult = {
305
+ transformed: typeof envelope.payload === "string" ? envelope.payload : "",
306
+ detections: piiScanResult.detections.map((d) => ({
307
+ category: d.type as never,
308
+ value: "",
309
+ offset: 0,
310
+ confidence: d.confidence,
311
+ })),
312
+ actionsApplied: piiScanResult.actionsApplied.map((a) => ({ category: "email", action: a })),
313
+ blocked: false,
314
+ mode: modeRef.value,
315
+ };
316
+
317
+ let trusted = false;
318
+ let policyAllowed = false;
319
+ let rejectionReason: string | undefined;
320
+
321
+ if (!verifyOut.ok) {
322
+ rejectionReason = `hmac:${verifyOut.reason}`;
323
+ audit.record({
324
+ ts: new Date().toISOString(),
325
+ envelopeId: envelope.envelopeId,
326
+ sourceNodeId: envelope.sourceNodeId,
327
+ targetNodeId: envelope.targetNodeId,
328
+ messageType: envelope.messageType,
329
+ nonce: envelope.nonce,
330
+ allowed: false,
331
+ reason: rejectionReason,
332
+ layer: "hmac",
333
+ });
334
+ } else {
335
+ // 2. Trust
336
+ const peer: PeerState = trust.getPeerState(envelope.sourceNodeId);
337
+ const trustOut = trust.evaluate(envelope, peer);
338
+ trusted = trustOut.allowed;
339
+ if (!trusted) {
340
+ rejectionReason = `trust:${trustOut.reason}`;
341
+ trust.recordOutcome(envelope.sourceNodeId, false);
342
+ audit.record({
343
+ ts: new Date().toISOString(),
344
+ envelopeId: envelope.envelopeId,
345
+ sourceNodeId: envelope.sourceNodeId,
346
+ targetNodeId: envelope.targetNodeId,
347
+ messageType: envelope.messageType,
348
+ nonce: envelope.nonce,
349
+ allowed: false,
350
+ reason: rejectionReason,
351
+ layer: "trust",
352
+ });
353
+ } else {
354
+ trust.recordOutcome(envelope.sourceNodeId, true);
355
+ // 3. Policy (hops + blocklist + message allowlist)
356
+ const polOut: PolicyDecision = policy.enforce(envelope, envelope.budget);
357
+ policyAllowed = polOut.allowed;
358
+ if (!polOut.allowed) {
359
+ rejectionReason = `policy:${polOut.denialReason}`;
360
+ audit.record({
361
+ ts: new Date().toISOString(),
362
+ envelopeId: envelope.envelopeId,
363
+ sourceNodeId: envelope.sourceNodeId,
364
+ targetNodeId: envelope.targetNodeId,
365
+ messageType: envelope.messageType,
366
+ nonce: envelope.nonce,
367
+ allowed: false,
368
+ reason: rejectionReason,
369
+ layer: "policy",
370
+ });
371
+ } else {
372
+ audit.record({
373
+ ts: new Date().toISOString(),
374
+ envelopeId: envelope.envelopeId,
375
+ sourceNodeId: envelope.sourceNodeId,
376
+ targetNodeId: envelope.targetNodeId,
377
+ messageType: envelope.messageType,
378
+ nonce: envelope.nonce,
379
+ allowed: true,
380
+ reason: `accepted (score=${trustOut.score.toFixed(3)})`,
381
+ layer: "received",
382
+ });
383
+ }
384
+ }
385
+ }
386
+
387
+ return {
388
+ trusted,
389
+ policyAllowed,
390
+ hmacValid: verifyOut.ok,
391
+ pii,
392
+ envelope,
393
+ rejectionReason,
394
+ };
395
+ }
396
+
397
+ function status(): FederationStatusSnapshot {
398
+ // Synthesize a peer list from audit history + TrustEvaluator internal map.
399
+ const peerIds = new Set<string>();
400
+ const tail = audit.tail(1000);
401
+ for (const entry of tail) peerIds.add(entry.sourceNodeId);
402
+ const peerSnapshots: PeerState[] = [];
403
+ for (const id of peerIds) peerSnapshots.push(trust.getPeerState(id));
404
+
405
+ return {
406
+ nodeId: opts.nodeId,
407
+ nonceCacheSize: nonces.size(),
408
+ auditSizeBytes: audit.size(),
409
+ auditPath: audit.getPath(),
410
+ budget: {
411
+ path: opts.budgetPath ?? ".harness/federation-budget.json",
412
+ perPeer: budget.snapshot(),
413
+ outstandingReservations: budget.outstanding().length,
414
+ },
415
+ peers: peerSnapshots,
416
+ };
417
+ }
418
+
419
+ return {
420
+ nodeId: opts.nodeId,
421
+ getPiiMode,
422
+ setPiiMode,
423
+ sign,
424
+ receive,
425
+ status,
426
+ services: { trust, policy, audit, budget, nonces },
427
+ };
428
+ }
429
+
430
+ // ---------------------------------------------------------------------------
431
+ // Convenience helper — re-export `canonicalSignablePayload` so callers
432
+ // that want to compute their own signature can import it from the top.
433
+ // ---------------------------------------------------------------------------
434
+
435
+ export { canonicalSignablePayload as buildSignablePayload };
436
+
437
+ // ---------------------------------------------------------------------------
438
+ // Helper for tests — produce a fresh envelope-id.
439
+ // ---------------------------------------------------------------------------
440
+
441
+ export function freshEnvelopeId(): string {
442
+ return randomUUID();
443
+ }