@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,304 @@
1
+ /**
2
+ * router/q-learning-router.ts — Q-learning agent router.
3
+ *
4
+ * v6.4.0 — ported from ruflo `q-learning-router.ts` (8-action softmax
5
+ * agent-route over coder / tester / reviewer / …).
6
+ *
7
+ * Bizar has more than 8 named agents, so the action set is the 8 most
8
+ * commonly delegated targets from `Agent` tool calls (matches
9
+ * `.claude/agents/*.md` to first 8 names). Adding the full
10
+ * 12-agent space could be done in a follow-up but each new agent
11
+ * increases state-action coverage cost; 8 keeps the bandit honest.
12
+ *
13
+ * - State: a 64-dim bag-of-words hash of the task string (FNV-1a
14
+ * folded into 64 buckets). LRU-cached so repeated task patterns
15
+ * are O(1).
16
+ * - Action: one of `odin|frigg|vor|mimir|heimdall|thor|tyr|forseti`.
17
+ * - Reward: `+1` on `recordOutcome(agent, true)`, `0` on false.
18
+ * - Exploration: ε-greedy with ε = 0.1 (configurable).
19
+ *
20
+ * `selectAgent()` returns `{agent, confidence}`. `confidence` is the
21
+ * posterior mean of the picked action's Q-value clamped to [0,1].
22
+ *
23
+ * Tiny surface area by design — the
24
+ * `AgentRouteDecision` shape is what `model_route` /
25
+ * `agent_route` MCP tools expose.
26
+ */
27
+
28
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
29
+ import { dirname, isAbsolute, resolve } from "node:path";
30
+
31
+ import { detectCodemodIntent } from "./codemod-intent.js";
32
+
33
+ export const AGENT_ACTIONS: readonly string[] = [
34
+ "odin",
35
+ "frigg",
36
+ "vor",
37
+ "mimir",
38
+ "heimdall",
39
+ "thor",
40
+ "tyr",
41
+ "forseti",
42
+ ] as const;
43
+
44
+ export type AgentName = (typeof AGENT_ACTIONS)[number];
45
+
46
+ export interface AgentRouteDecision {
47
+ agent: string;
48
+ confidence: number;
49
+ }
50
+
51
+ export interface QLearningRouterOpts {
52
+ stateDim?: number;
53
+ epsilon?: number;
54
+ lruSize?: number;
55
+ seed?: number;
56
+ }
57
+
58
+ const DEFAULT_STATE_DIM = 64;
59
+ const DEFAULT_EPSILON = 0.1;
60
+ const DEFAULT_LRU = 256;
61
+
62
+ const STOPWORDS = new Set([
63
+ "the", "a", "an", "and", "or", "but", "in", "on", "at", "to",
64
+ "for", "of", "with", "by", "is", "are", "be", "was", "were", "this",
65
+ "that", "it", "as", "if", "from", "into", "so", "than",
66
+ ]);
67
+
68
+ export class QLearningRouter {
69
+ private readonly stateDim: number;
70
+ private readonly epsilon: number;
71
+ private readonly lruSize: number;
72
+ // Q[agentIdx][stateBucket] → mean reward for that bucket.
73
+ // Initialised to 0.5 (neutral). Updated by EMA on recordOutcome.
74
+ private readonly q: Float32Array[] = [];
75
+ private readonly counts: Uint32Array[] = [];
76
+ private readonly lru: Map<string, AgentRouteDecision> = new Map();
77
+ private rngState: number;
78
+
79
+ constructor(opts?: QLearningRouterOpts) {
80
+ this.stateDim = opts?.stateDim ?? DEFAULT_STATE_DIM;
81
+ this.epsilon = opts?.epsilon ?? DEFAULT_EPSILON;
82
+ this.lruSize = opts?.lruSize ?? DEFAULT_LRU;
83
+ this.rngState = (opts?.seed ?? 0) | 0;
84
+ for (let i = 0; i < AGENT_ACTIONS.length; i++) {
85
+ this.q.push(new Float32Array(this.stateDim).fill(0.5));
86
+ this.counts.push(new Uint32Array(this.stateDim));
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Greedy ε-soft policy. Returns a cached decision when the same
92
+ * (task) hash has been seen recently (LRU bounded by `lruSize`).
93
+ * Codemod-eligible prompts short-circuit to `heimdall` (the
94
+ * routine-implementation agent) so they still get a "best" agent
95
+ * without paying the bandit lookup cost twice.
96
+ */
97
+ selectAgent(task: string): AgentRouteDecision {
98
+ if (!task || typeof task !== "string") {
99
+ return { agent: "odin", confidence: 0.5 };
100
+ }
101
+
102
+ // Tier-1 codemod-eligible prompt → deterministic safe pick.
103
+ const cm = detectCodemodIntent(task);
104
+ if (cm !== null) {
105
+ return { agent: "heimdall", confidence: 1.0 };
106
+ }
107
+
108
+ const bucket = this.bucketize(task);
109
+ const cacheKey = String(bucket);
110
+ const cached = this.lru.get(cacheKey);
111
+ if (cached) {
112
+ // Touch the LRU entry to mark recently used.
113
+ this.lru.delete(cacheKey);
114
+ this.lru.set(cacheKey, cached);
115
+ return cached;
116
+ }
117
+
118
+ let agentIdx: number;
119
+ let confidence = 0.5;
120
+ if (this.random() < this.epsilon) {
121
+ // Explore: uniformly at random.
122
+ agentIdx = Math.floor(this.random() * AGENT_ACTIONS.length) % AGENT_ACTIONS.length;
123
+ confidence = 0.25;
124
+ } else {
125
+ // Exploit: argmax Q for this bucket. Tie-break by lower count
126
+ // (prefer the less-tried action), then by the canonical order.
127
+ let bestQ = -Infinity;
128
+ let bestCount = Infinity;
129
+ const ties: number[] = [];
130
+ for (let i = 0; i < AGENT_ACTIONS.length; i++) {
131
+ const qv = this.q[i][bucket];
132
+ if (qv > bestQ) {
133
+ bestQ = qv; bestCount = this.counts[i][bucket]; ties.length = 0; ties.push(i);
134
+ } else if (qv === bestQ) {
135
+ const c = this.counts[i][bucket];
136
+ if (c < bestCount) { bestCount = c; ties.length = 0; ties.push(i); }
137
+ else ties.push(i);
138
+ }
139
+ }
140
+ agentIdx = ties[Math.floor(this.random() * ties.length)] ?? 0;
141
+ confidence = clamp01(bestQ);
142
+ }
143
+
144
+ const decision: AgentRouteDecision = {
145
+ agent: AGENT_ACTIONS[agentIdx],
146
+ confidence,
147
+ };
148
+
149
+ // Promote to LRU. LRU has a hard cap; evict oldest on overflow.
150
+ if (this.lru.size >= this.lruSize) {
151
+ const oldest = this.lru.keys().next().value;
152
+ if (oldest !== undefined) this.lru.delete(oldest);
153
+ }
154
+ this.lru.set(cacheKey, decision);
155
+ return decision;
156
+ }
157
+
158
+ /**
159
+ * EMA update of Q[agentIdx][bucket]. Uses the standard
160
+ * Q ← Q + α (reward − Q)
161
+ * where α = 1 / (1 + count) — decreasing step size over time.
162
+ */
163
+ recordOutcome(agent: string, success: boolean): void {
164
+ const idx = AGENT_ACTIONS.indexOf(agent as AgentName);
165
+ if (idx < 0) return;
166
+ // Reward shape: +1 success, 0 failure, normalised to [0,1] in Q.
167
+ const reward = success ? 1.0 : 0.0;
168
+ for (let b = 0; b < this.stateDim; b++) {
169
+ const c = this.counts[idx][b] + 1;
170
+ this.counts[idx][b] = c;
171
+ const alpha = 1 / (1 + c);
172
+ this.q[idx][b] = this.q[idx][b] + alpha * (reward - this.q[idx][b]);
173
+ }
174
+ }
175
+
176
+ /** Read-only access for tests / telemetry. */
177
+ snapshot(): Array<{ agent: string; qMean: number; n: number }> {
178
+ return AGENT_ACTIONS.map((agent, i) => {
179
+ let total = 0;
180
+ let n = 0;
181
+ for (let b = 0; b < this.stateDim; b++) {
182
+ total += this.q[i][b];
183
+ n += this.counts[i][b];
184
+ }
185
+ return {
186
+ agent,
187
+ qMean: n === 0 ? 0.5 : total / this.stateDim,
188
+ n,
189
+ };
190
+ });
191
+ }
192
+
193
+ // -----------------------------------------------------------------
194
+ // Persistence — same JSON-file policy as the model router.
195
+ // -----------------------------------------------------------------
196
+
197
+ /** Stable on-disk serialisation: Q-table per agent, counts, seed. */
198
+ fullSnapshot(): QLearningSnapshot {
199
+ const q: number[][] = [];
200
+ const counts: number[][] = [];
201
+ for (let i = 0; i < AGENT_ACTIONS.length; i++) {
202
+ q.push(Array.from(this.q[i]));
203
+ counts.push(Array.from(this.counts[i]));
204
+ }
205
+ return {
206
+ version: 1,
207
+ stateDim: this.stateDim,
208
+ epsilon: this.epsilon,
209
+ q,
210
+ counts,
211
+ rngSeed: this.rngState,
212
+ };
213
+ }
214
+
215
+ static fromSnapshot(snap: Partial<QLearningSnapshot>): QLearningRouter {
216
+ const inst = new QLearningRouter({
217
+ stateDim: snap.stateDim,
218
+ epsilon: snap.epsilon,
219
+ seed: snap.rngSeed,
220
+ });
221
+ if (snap.q && snap.counts) {
222
+ const dim = inst.stateDim;
223
+ for (let i = 0; i < Math.min(snap.q.length, AGENT_ACTIONS.length); i++) {
224
+ const row = snap.q[i] ?? [];
225
+ const crows = snap.counts[i] ?? [];
226
+ for (let b = 0; b < Math.min(dim, row.length); b++) {
227
+ inst.q[i][b] = row[b];
228
+ inst.counts[i][b] = crows[b] ?? 0;
229
+ }
230
+ }
231
+ }
232
+ return inst;
233
+ }
234
+
235
+ saveTo(path: string): void {
236
+ const fp = isAbsolute(path) ? path : resolve(path);
237
+ mkdirSync(dirname(fp), { recursive: true });
238
+ writeFileSync(fp, JSON.stringify(this.fullSnapshot(), null, 2), "utf-8");
239
+ }
240
+
241
+ static loadFrom(path: string): QLearningRouter {
242
+ try {
243
+ if (!existsSync(path)) return new QLearningRouter();
244
+ const snap = JSON.parse(readFileSync(path, "utf-8")) as Partial<QLearningSnapshot>;
245
+ return QLearningRouter.fromSnapshot(snap);
246
+ } catch {
247
+ return new QLearningRouter();
248
+ }
249
+ }
250
+
251
+ // -----------------------------------------------------------------
252
+ // Helpers (FNV-1a bucketing + seeded RNG).
253
+ // -----------------------------------------------------------------
254
+
255
+ /** FNV-1a 32-bit hash, folded into [0, stateDim). Bag-of-words. */
256
+ private bucketize(text: string): number {
257
+ // Tokenise, drop stopwords.
258
+ const tokens = text
259
+ .toLowerCase()
260
+ .replace(/[^a-z0-9\s]+/g, " ")
261
+ .split(/\s+/)
262
+ .filter((t) => t.length > 1 && !STOPWORDS.has(t));
263
+
264
+ // If everything was stopwords, the whole string is its own bucket.
265
+ const words = tokens.length > 0 ? tokens : [text.toLowerCase().trim()];
266
+
267
+ let acc = 2166136261 >>> 0; // FNV-1a init.
268
+ for (const w of words) {
269
+ let h = 2166136261 >>> 0;
270
+ for (let i = 0; i < w.length; i++) {
271
+ h ^= w.charCodeAt(i);
272
+ h = Math.imul(h, 16777619) >>> 0;
273
+ }
274
+ acc ^= h;
275
+ acc = Math.imul(acc + 0x9e3779b9, 16777619) >>> 0;
276
+ }
277
+ return acc % this.stateDim;
278
+ }
279
+
280
+ private random(): number {
281
+ if (this.rngState !== 0) {
282
+ this.rngState = (this.rngState * 1664525 + 1013904223) | 0;
283
+ const u = (this.rngState >>> 0) / 0xffffffff;
284
+ return u || 1e-12;
285
+ }
286
+ return Math.random() || 1e-12;
287
+ }
288
+ }
289
+
290
+ export interface QLearningSnapshot {
291
+ version: number;
292
+ stateDim: number;
293
+ epsilon: number;
294
+ q: number[][];
295
+ counts: number[][];
296
+ rngSeed: number;
297
+ }
298
+
299
+ function clamp01(n: number): number {
300
+ if (Number.isNaN(n)) return 0;
301
+ if (n < 0) return 0;
302
+ if (n > 1) return 1;
303
+ return n;
304
+ }
@@ -0,0 +1,279 @@
1
+ /**
2
+ * swarm-topology.ts — in-process swarm coordination topology registry.
3
+ *
4
+ * F-032 — ported from ruflo `v3/mcp/tools/swarm-tools.ts` `swarm/init`
5
+ * (line 389). Tracks swarm definitions and the agents assigned to them.
6
+ * No event bus — purely a registry the MCP tools can read/write.
7
+ *
8
+ * The `default` swarm is created lazily on first `initSwarm` call so
9
+ * consumers always have at least one swarm to inspect.
10
+ *
11
+ * Persistence is opt-in: pass `{ persistPath }` to the constructor (or
12
+ * to the `swarmTopologyRegistry` singleton via its mutator) and the
13
+ * registry writes a JSON snapshot to disk after every mutation.
14
+ */
15
+
16
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
17
+ import { dirname } from "node:path";
18
+
19
+ export type SwarmTopology =
20
+ | "hierarchical"
21
+ | "mesh"
22
+ | "adaptive"
23
+ | "collective"
24
+ | "hierarchical-mesh";
25
+
26
+ export const SWARM_TOPOLOGIES: readonly SwarmTopology[] = [
27
+ "hierarchical",
28
+ "mesh",
29
+ "adaptive",
30
+ "collective",
31
+ "hierarchical-mesh",
32
+ ] as const;
33
+
34
+ export const DEFAULT_TOPOLOGY: SwarmTopology = "hierarchical-mesh";
35
+ export const DEFAULT_MAX_AGENTS = 15;
36
+ export const MIN_MAX_AGENTS = 1;
37
+ export const MAX_MAX_AGENTS = 1000;
38
+ export const DEFAULT_SWARM_ID = "default";
39
+
40
+ export interface SwarmRecord {
41
+ swarmId: string;
42
+ topology: SwarmTopology;
43
+ maxAgents: number;
44
+ metadata?: Record<string, unknown>;
45
+ agentIds: string[];
46
+ createdAt: string;
47
+ decommissionedAt?: string;
48
+ }
49
+
50
+ export interface InitSwarmInput {
51
+ swarmId?: string;
52
+ topology?: SwarmTopology;
53
+ maxAgents?: number;
54
+ metadata?: Record<string, unknown>;
55
+ }
56
+
57
+ export interface InitSwarmResult {
58
+ swarmId: string;
59
+ topology: SwarmTopology;
60
+ maxAgents: number;
61
+ createdAt: string;
62
+ metadata?: Record<string, unknown>;
63
+ }
64
+
65
+ export interface SwarmTopologyRegistryOpts {
66
+ /**
67
+ * When set, the registry loads from this file on construction (if it
68
+ * exists) and writes a JSON snapshot after every mutation. The parent
69
+ * directory is created on demand. Path resolution is the caller's
70
+ * responsibility — the registry treats the value as final.
71
+ */
72
+ persistPath?: string;
73
+ }
74
+
75
+ interface PersistShape {
76
+ version: 1;
77
+ swarms: SwarmRecord[];
78
+ }
79
+
80
+ function clampMaxAgents(n: unknown): number {
81
+ const v = typeof n === "number" && Number.isFinite(n) ? Math.floor(n) : DEFAULT_MAX_AGENTS;
82
+ if (v < MIN_MAX_AGENTS) return MIN_MAX_AGENTS;
83
+ if (v > MAX_MAX_AGENTS) return MAX_MAX_AGENTS;
84
+ return v;
85
+ }
86
+
87
+ function normalizeTopology(t: unknown): SwarmTopology {
88
+ if (typeof t === "string" && (SWARM_TOPOLOGIES as readonly string[]).includes(t)) {
89
+ return t as SwarmTopology;
90
+ }
91
+ return DEFAULT_TOPOLOGY;
92
+ }
93
+
94
+ export class SwarmTopologyRegistry {
95
+ private readonly swarms: Map<string, SwarmRecord> = new Map();
96
+ private defaultSeeded = false;
97
+ private persistPath?: string;
98
+
99
+ constructor(opts: SwarmTopologyRegistryOpts = {}) {
100
+ this.persistPath = opts.persistPath;
101
+ if (this.persistPath) this.loadFromDisk();
102
+ }
103
+
104
+ /**
105
+ * Configure (or clear) the persistence path after construction.
106
+ */
107
+ setPersistPath(path: string | undefined): void {
108
+ this.persistPath = path;
109
+ if (path) this.loadFromDisk();
110
+ }
111
+
112
+ private nextSwarmId(): string {
113
+ let i = 1;
114
+ while (this.swarms.has(`swarm-${i}`)) i++;
115
+ return `swarm-${i}`;
116
+ }
117
+
118
+ private ensureDefault(): void {
119
+ if (this.defaultSeeded) return;
120
+ this.defaultSeeded = true;
121
+ if (!this.swarms.has(DEFAULT_SWARM_ID)) {
122
+ const createdAt = new Date().toISOString();
123
+ this.swarms.set(DEFAULT_SWARM_ID, {
124
+ swarmId: DEFAULT_SWARM_ID,
125
+ topology: DEFAULT_TOPOLOGY,
126
+ maxAgents: DEFAULT_MAX_AGENTS,
127
+ agentIds: [],
128
+ createdAt,
129
+ });
130
+ }
131
+ }
132
+
133
+ initSwarm(input: InitSwarmInput = {}): InitSwarmResult {
134
+ this.ensureDefault();
135
+
136
+ let swarmId = input.swarmId?.trim();
137
+ if (!swarmId) swarmId = this.nextSwarmId();
138
+ if (this.swarms.has(swarmId)) {
139
+ throw new Error(`initSwarm: swarm already exists: ${swarmId}`);
140
+ }
141
+
142
+ const topology = normalizeTopology(input.topology);
143
+ const maxAgents = clampMaxAgents(input.maxAgents);
144
+ const createdAt = new Date().toISOString();
145
+ const record: SwarmRecord = {
146
+ swarmId,
147
+ topology,
148
+ maxAgents,
149
+ metadata: input.metadata,
150
+ agentIds: [],
151
+ createdAt,
152
+ };
153
+ this.swarms.set(swarmId, record);
154
+ this.persist();
155
+ return { swarmId, topology, maxAgents, createdAt, metadata: input.metadata };
156
+ }
157
+
158
+ getSwarm(swarmId: string): SwarmRecord | undefined {
159
+ return this.swarms.get(swarmId);
160
+ }
161
+
162
+ listSwarms(): SwarmRecord[] {
163
+ return Array.from(this.swarms.values());
164
+ }
165
+
166
+ recordAgentInSwarm(swarmId: string, agentId: string): SwarmRecord {
167
+ const record = this.swarms.get(swarmId);
168
+ if (!record) {
169
+ throw new Error(`recordAgentInSwarm: swarm not found: ${swarmId}`);
170
+ }
171
+ if (record.decommissionedAt) {
172
+ throw new Error(`recordAgentInSwarm: swarm is decommissioned: ${swarmId}`);
173
+ }
174
+ if (record.agentIds.length >= record.maxAgents && !record.agentIds.includes(agentId)) {
175
+ throw new Error(
176
+ `recordAgentInSwarm: swarm ${swarmId} is at maxAgents (${record.maxAgents})`,
177
+ );
178
+ }
179
+ if (!record.agentIds.includes(agentId)) {
180
+ record.agentIds.push(agentId);
181
+ }
182
+ this.persist();
183
+ return record;
184
+ }
185
+
186
+ decommissionSwarm(swarmId: string): SwarmRecord {
187
+ if (swarmId === DEFAULT_SWARM_ID) {
188
+ throw new Error("decommissionSwarm: cannot decommission the default swarm");
189
+ }
190
+ const record = this.swarms.get(swarmId);
191
+ if (!record) {
192
+ throw new Error(`decommissionSwarm: swarm not found: ${swarmId}`);
193
+ }
194
+ if (record.decommissionedAt) return record;
195
+ record.decommissionedAt = new Date().toISOString();
196
+ this.persist();
197
+ return record;
198
+ }
199
+
200
+ /**
201
+ * Test/dev helper: drop everything.
202
+ */
203
+ reset(): void {
204
+ this.swarms.clear();
205
+ this.defaultSeeded = false;
206
+ if (this.persistPath && existsSync(this.persistPath)) {
207
+ try { writeFileSync(this.persistPath, JSON.stringify({ version: 1, swarms: [] }, null, 2), "utf-8"); }
208
+ catch { /* best-effort */ }
209
+ }
210
+ }
211
+
212
+ // ── Persistence ───────────────────────────────────────────────────────
213
+
214
+ private loadFromDisk(): void {
215
+ if (!this.persistPath || !existsSync(this.persistPath)) return;
216
+ try {
217
+ const raw = readFileSync(this.persistPath, "utf-8");
218
+ const data = JSON.parse(raw) as Partial<PersistShape>;
219
+ if (Array.isArray(data.swarms)) {
220
+ for (const s of data.swarms) {
221
+ if (!s || typeof s.swarmId !== "string") continue;
222
+ this.swarms.set(s.swarmId, s);
223
+ if (s.swarmId === DEFAULT_SWARM_ID) this.defaultSeeded = true;
224
+ }
225
+ }
226
+ } catch {
227
+ // Corrupt or partial file — start fresh.
228
+ }
229
+ }
230
+
231
+ private persist(): void {
232
+ if (!this.persistPath) return;
233
+ try {
234
+ mkdirSync(dirname(this.persistPath), { recursive: true });
235
+ const data: PersistShape = {
236
+ version: 1,
237
+ swarms: Array.from(this.swarms.values()),
238
+ };
239
+ writeFileSync(this.persistPath, JSON.stringify(data, null, 2), "utf-8");
240
+ } catch {
241
+ // Persistence is best-effort.
242
+ }
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Process-wide singleton used by MCP tools. Persistence defaults to
248
+ * `.harness/topology.json` in the current working directory.
249
+ */
250
+ const _sharedRegistry = new SwarmTopologyRegistry({
251
+ persistPath: ".harness/topology.json",
252
+ });
253
+
254
+ export function initSwarm(input: InitSwarmInput = {}): InitSwarmResult {
255
+ return _sharedRegistry.initSwarm(input);
256
+ }
257
+
258
+ export function getSwarm(swarmId: string): SwarmRecord | undefined {
259
+ return _sharedRegistry.getSwarm(swarmId);
260
+ }
261
+
262
+ export function listSwarms(): SwarmRecord[] {
263
+ return _sharedRegistry.listSwarms();
264
+ }
265
+
266
+ export function recordAgentInSwarm(swarmId: string, agentId: string): SwarmRecord {
267
+ return _sharedRegistry.recordAgentInSwarm(swarmId, agentId);
268
+ }
269
+
270
+ export function decommissionSwarm(swarmId: string): SwarmRecord {
271
+ return _sharedRegistry.decommissionSwarm(swarmId);
272
+ }
273
+
274
+ /**
275
+ * Process-wide singleton used by MCP tools. Tests should construct
276
+ * their own `new SwarmTopologyRegistry()` to get an isolated, non-
277
+ * persistent instance.
278
+ */
279
+ export const swarmTopologyRegistry = _sharedRegistry;