@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,123 @@
1
+ // src/web/components/agents/QualityGates.tsx — pass/fail rubric display.
2
+ //
3
+ // v6.4.0 — F-036 (Goal Planner UI). Scores the four L09 rubric
4
+ // dimensions (Correctness / Arch compliance / Test coverage /
5
+ // Verification evidence) against the live plan. Each gate turns
6
+ // green when the supplied metric meets the threshold documented in
7
+ // `templates/evaluator-rubric.md`.
8
+ import { Shield, CheckCircle2, XCircle, AlertTriangle } from 'lucide-react';
9
+ import { Card, CardTitle, CardMeta } from '../Card';
10
+ import { Tag } from '../Tag';
11
+ import type { Plan } from '../../lib/goapPlanner';
12
+
13
+ interface Metrics {
14
+ /** 0 or 1 — whether `make check` is green. */
15
+ compileCheck: boolean;
16
+ /** Percentage of touched tests passing. */
17
+ testCoverage: number;
18
+ /** Percentage of arch-rules passing. */
19
+ archScore: number;
20
+ /** Verification evidence (commit hash or test output) present. */
21
+ evidencePresent: boolean;
22
+ }
23
+
24
+ interface GateRow {
25
+ name: string;
26
+ status: 'passed' | 'warning' | 'failed';
27
+ value?: number | boolean;
28
+ threshold?: number | boolean;
29
+ detail: string;
30
+ }
31
+
32
+ interface Props {
33
+ plan: Plan | null;
34
+ metrics: Metrics;
35
+ }
36
+
37
+ function evaluate(metrics: Metrics): GateRow[] {
38
+ const compile: GateRow = metrics.compileCheck
39
+ ? { name: 'Compile check', status: 'passed', value: true, threshold: true, detail: 'make check is green.' }
40
+ : { name: 'Compile check', status: 'failed', value: false, threshold: true, detail: 'Typecheck error — fix before marking passing.' };
41
+
42
+ const coverage: GateRow = metrics.testCoverage >= 80
43
+ ? { name: 'Test coverage', status: 'passed', value: metrics.testCoverage, threshold: 80, detail: 'Coverage meets the B-grade threshold.' }
44
+ : metrics.testCoverage >= 60
45
+ ? { name: 'Test coverage', status: 'warning', value: metrics.testCoverage, threshold: 80, detail: 'Coverage is below the B-grade threshold.' }
46
+ : { name: 'Test coverage', status: 'failed', value: metrics.testCoverage, threshold: 80, detail: 'Coverage is critical.' };
47
+
48
+ const arch: GateRow = metrics.archScore >= 90
49
+ ? { name: 'Arch compliance', status: 'passed', value: metrics.archScore, threshold: 90, detail: 'All non-trivial arch-rules satisfied.' }
50
+ : metrics.archScore >= 70
51
+ ? { name: 'Arch compliance', status: 'warning', value: metrics.archScore, threshold: 90, detail: 'Minor arch-rule violations.' }
52
+ : { name: 'Arch compliance', status: 'failed', value: metrics.archScore, threshold: 90, detail: 'Multiple arch-rule violations.' };
53
+
54
+ const evidence: GateRow = metrics.evidencePresent
55
+ ? { name: 'Verification evidence', status: 'passed', value: true, threshold: true, detail: 'Test output + commit hash captured.' }
56
+ : { name: 'Verification evidence', status: 'failed', value: false, threshold: true, detail: 'No evidence recorded yet.' };
57
+
58
+ return [compile, coverage, arch, evidence];
59
+ }
60
+
61
+ function GateIcon({ status }: { status: GateRow['status'] }) {
62
+ if (status === 'passed') return <CheckCircle2 size={14} className="qg-icon is-pass" />;
63
+ if (status === 'warning') return <AlertTriangle size={14} className="qg-icon is-warn" />;
64
+ return <XCircle size={14} className="qg-icon is-fail" />;
65
+ }
66
+
67
+ function GateTag({ status }: { status: GateRow['status'] }) {
68
+ if (status === 'passed') return <Tag variant="success">passed</Tag>;
69
+ if (status === 'warning') return <Tag variant="warning">warning</Tag>;
70
+ return <Tag variant="error">failed</Tag>;
71
+ }
72
+
73
+ export function QualityGates({ plan, metrics }: Props) {
74
+ const gates = evaluate(metrics);
75
+ const passing = gates.filter((g) => g.status === 'passed').length;
76
+ return (
77
+ <Card className="qg-panel" data-testid="quality-gates">
78
+ <div className="qg-header">
79
+ <CardTitle>
80
+ <Shield size={14} aria-hidden /> Quality gates
81
+ </CardTitle>
82
+ <Tag variant={passing === gates.length ? 'success' : passing > 0 ? 'warning' : 'error'}>
83
+ {passing}/{gates.length} passing
84
+ </Tag>
85
+ </div>
86
+ <CardMeta>
87
+ L09 rubric (Correctness / Arch compliance / Test coverage / Verification evidence) —{' '}
88
+ {plan ? `evaluating against plan with ${plan.steps.length} steps.` : 'awaiting plan.'}
89
+ </CardMeta>
90
+ <ul className="qg-list" data-testid="quality-gates-list">
91
+ {gates.map((gate) => (
92
+ <li
93
+ key={gate.name}
94
+ className={`qg-row is-${gate.status}`}
95
+ data-testid="quality-gates-row"
96
+ data-status={gate.status}
97
+ >
98
+ <div className="qg-row-head">
99
+ <GateIcon status={gate.status} />
100
+ <span className="qg-name">{gate.name}</span>
101
+ <GateTag status={gate.status} />
102
+ </div>
103
+ <div className="qg-row-body">
104
+ <span className="qg-detail">{gate.detail}</span>
105
+ {typeof gate.value === 'number' && (
106
+ <span className="qg-threshold">
107
+ current: {gate.value}% · threshold: {gate.threshold}%
108
+ </span>
109
+ )}
110
+ {typeof gate.value === 'boolean' && (
111
+ <span className="qg-threshold">
112
+ current: {String(gate.value)} · threshold: {String(gate.threshold)}
113
+ </span>
114
+ )}
115
+ </div>
116
+ </li>
117
+ ))}
118
+ </ul>
119
+ </Card>
120
+ );
121
+ }
122
+
123
+ export default QualityGates;
@@ -0,0 +1,127 @@
1
+ // src/web/components/agents/RealTimeEventLog.tsx — streaming event ticker.
2
+ //
3
+ // v6.4.0 — F-036 (Goal Planner UI). Subscribes to ws.ts for ALL
4
+ // events and renders a color-coded ticker. Bounded ring buffer so
5
+ // a runaway server can't fill memory.
6
+ import { useEffect, useMemo, useState } from 'react';
7
+ import { Activity } from 'lucide-react';
8
+ import { Ws } from '../../lib/ws';
9
+ import { Card, CardTitle, CardMeta } from '../Card';
10
+ import { Tag } from '../Tag';
11
+
12
+ const MAX_ROWS = 500;
13
+
14
+ type EventRow = {
15
+ id: string;
16
+ ts: number;
17
+ type: string;
18
+ severity: 'info' | 'success' | 'warning' | 'error' | 'control';
19
+ preview: string;
20
+ };
21
+
22
+ function severityFor(type: string): EventRow['severity'] {
23
+ if (type.startsWith('goal:')) return 'success';
24
+ if (type.startsWith('task:')) return 'info';
25
+ if (type.includes('error') || type.includes('fail')) return 'error';
26
+ if (type.includes('stuck') || type.includes('blocked') || type.includes('warn')) return 'warning';
27
+ if (type === 'ping' || type === 'pong' || type === 'refresh') return 'control';
28
+ return 'info';
29
+ }
30
+
31
+ function previewOf(type: string, payload: Record<string, unknown> | undefined): string {
32
+ if (!payload) return type;
33
+ const keys = Object.keys(payload).slice(0, 3);
34
+ return keys.map((k) => `${k}=${shortVal(payload[k])}`).join(' ') || type;
35
+ }
36
+
37
+ function shortVal(v: unknown): string {
38
+ if (v == null) return 'null';
39
+ if (typeof v === 'string') return v.length > 20 ? `"${v.slice(0, 20)}…"` : `"${v}"`;
40
+ if (typeof v === 'number' || typeof v === 'boolean') return String(v);
41
+ if (Array.isArray(v)) return `[${v.length}]`;
42
+ if (typeof v === 'object') return `{${Object.keys(v).length}}`;
43
+ return String(v);
44
+ }
45
+
46
+ export function RealTimeEventLog() {
47
+ const [rows, setRows] = useState<EventRow[]>([]);
48
+
49
+ useEffect(() => {
50
+ const ws = new Ws();
51
+ const off = ws.on((msg) => {
52
+ const m = msg as { type?: string; ts?: number } & Record<string, unknown>;
53
+ const t = m.type;
54
+ if (!t) return;
55
+ const ts = Number(m.ts) || Date.now();
56
+ const row: EventRow = {
57
+ id: `${ts}-${Math.random().toString(36).slice(2, 7)}`,
58
+ ts,
59
+ type: t,
60
+ severity: severityFor(t),
61
+ preview: previewOf(t, m as Record<string, unknown>),
62
+ };
63
+ setRows((prev) => {
64
+ const next = [...prev, row];
65
+ return next.length > MAX_ROWS ? next.slice(next.length - MAX_ROWS) : next;
66
+ });
67
+ });
68
+ return () => {
69
+ off();
70
+ ws.close();
71
+ };
72
+ }, []);
73
+
74
+ const summary = useMemo(() => {
75
+ const counts: Record<EventRow['severity'], number> = {
76
+ info: 0,
77
+ success: 0,
78
+ warning: 0,
79
+ error: 0,
80
+ control: 0,
81
+ };
82
+ for (const r of rows) counts[r.severity] += 1;
83
+ return counts;
84
+ }, [rows]);
85
+
86
+ return (
87
+ <Card className="event-log" data-testid="event-log">
88
+ <div className="event-log-header">
89
+ <CardTitle>
90
+ <Activity size={14} aria-hidden /> Real-time events
91
+ </CardTitle>
92
+ <Tag variant="neutral" data-testid="event-log-count">{rows.length}</Tag>
93
+ </div>
94
+ <CardMeta>Live WebSocket event ticker · bounded to {MAX_ROWS} rows</CardMeta>
95
+ <div className="event-log-summary" data-testid="event-log-summary">
96
+ <Tag variant="info">info {summary.info}</Tag>
97
+ <Tag variant="success">success {summary.success}</Tag>
98
+ <Tag variant="warning">warning {summary.warning}</Tag>
99
+ <Tag variant="error">error {summary.error}</Tag>
100
+ <Tag variant="neutral">control {summary.control}</Tag>
101
+ </div>
102
+ <ul className="event-log-list" data-testid="event-log-list">
103
+ {rows.length === 0 && (
104
+ <li className="event-log-empty" data-testid="event-log-empty">
105
+ No events yet. Events will stream here as the server emits them.
106
+ </li>
107
+ )}
108
+ {rows.slice().reverse().map((row) => (
109
+ <li
110
+ key={row.id}
111
+ className={`event-log-row is-${row.severity}`}
112
+ data-testid="event-log-row"
113
+ data-severity={row.severity}
114
+ >
115
+ <time className="event-log-time" dateTime={new Date(row.ts).toISOString()}>
116
+ {new Date(row.ts).toLocaleTimeString()}
117
+ </time>
118
+ <code className="event-log-type">{row.type}</code>
119
+ <span className="event-log-preview">{row.preview}</span>
120
+ </li>
121
+ ))}
122
+ </ul>
123
+ </Card>
124
+ );
125
+ }
126
+
127
+ export default RealTimeEventLog;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * src/web/components/agents/RoutingDecisions.test.tsx
3
+ *
4
+ * F-035 — vitest tests for the routing-decisions panel.
5
+ * 3 tests required by the F-035 layers[] spec:
6
+ * 1. renders the empty state when no decisions have been emitted
7
+ * 2. renders a single decision via the `initial` prop
8
+ * 3. renders multiple decisions via the WS subscription path
9
+ *
10
+ * The `subscribe` prop receives a `(msg: WsMessage) => void` handler
11
+ * and returns an unsubscribe function. We capture the handler and
12
+ * drive it directly — no real WebSocket needed.
13
+ */
14
+
15
+ import { describe, it, expect, vi } from 'vitest';
16
+ import { render, screen, fireEvent, act, waitFor } from '@testing-library/react';
17
+ import React from 'react';
18
+ import { RoutingDecisions } from './RoutingDecisions';
19
+ import type { RoutingDecision, WsMessage } from '../../lib/types';
20
+
21
+ const dec = (id: string, tier: RoutingDecision['tier'], model: string, extras: Partial<RoutingDecision> = {}): RoutingDecision => ({
22
+ id,
23
+ ts: 1_700_000_000_000 + Number(id.replace(/\D/g, '') || 0) * 1000,
24
+ tier,
25
+ model,
26
+ task: `task-${id}`,
27
+ costUsd: tier === 'CODEMOD' ? 0 : 0.01,
28
+ latencyMs: 250,
29
+ ...extras,
30
+ });
31
+
32
+ describe('RoutingDecisions', () => {
33
+ it('renders the empty state when no decisions have been emitted', () => {
34
+ render(<RoutingDecisions />);
35
+ const empty = screen.getByTestId('routing-decisions-empty');
36
+ expect(empty).toBeTruthy();
37
+ expect(empty.textContent).toMatch(/No routing decisions yet/i);
38
+ // Confirm table is NOT rendered in empty state.
39
+ expect(screen.queryByRole('table')).toBeNull();
40
+ });
41
+
42
+ it('renders a single decision via the initial prop', () => {
43
+ const one = dec('1', 'CODEMOD', 'codemod:var-to-const');
44
+ render(<RoutingDecisions initial={[one]} />);
45
+
46
+ // Tier badge with the right class
47
+ const row = screen.getByTestId(`routing-row-${one.id}`);
48
+ expect(row).toBeTruthy();
49
+ const badge = row.querySelector('.routing-tier-codemod');
50
+ expect(badge).toBeTruthy();
51
+ expect(badge?.textContent).toBe('CODEMOD');
52
+
53
+ // Model + task + cost columns
54
+ expect(row.querySelector('.routing-model')?.textContent).toBe('codemod:var-to-const');
55
+ expect(row.querySelector('.routing-task')?.textContent).toBe('task-1');
56
+ expect(row.querySelector('.routing-cost')?.textContent).toBe('$0');
57
+ // latency = 250ms → "250ms"
58
+ expect(row.querySelector('.routing-latency')?.textContent).toBe('250ms');
59
+ });
60
+
61
+ it('renders multiple decisions and filters by tier', () => {
62
+ const list: RoutingDecision[] = [
63
+ dec('1', 'CODEMOD', 'codemod:remove-console', { costUsd: 0 }),
64
+ dec('2', 'TIER1', 'haiku', { costUsd: 0.0008 }),
65
+ dec('3', 'TIER2', 'sonnet', { costUsd: 0.012 }),
66
+ dec('4', 'TIER3', 'opus', { costUsd: 0.05 }),
67
+ ];
68
+
69
+ const { rerender } = render(<RoutingDecisions initial={list} />);
70
+ // All four rows present
71
+ for (const d of list) {
72
+ expect(screen.getByTestId(`routing-row-${d.id}`)).toBeTruthy();
73
+ }
74
+
75
+ // Tier filter — only TIER2 row survives
76
+ rerender(<RoutingDecisions initial={list} filterTier="TIER2" />);
77
+ expect(screen.getByTestId('routing-row-3')).toBeTruthy();
78
+ expect(screen.queryByTestId('routing-row-1')).toBeNull();
79
+ expect(screen.queryByTestId('routing-row-2')).toBeNull();
80
+ expect(screen.queryByTestId('routing-row-4')).toBeNull();
81
+
82
+ // Subscribed WS append test — drive a `routing:decision` through
83
+ // the captured handler.
84
+ let capturedHandler: ((msg: WsMessage) => void) | null = null;
85
+ const subscribe = (handler: (msg: WsMessage) => void) => {
86
+ capturedHandler = handler;
87
+ return () => { capturedHandler = null; };
88
+ };
89
+ const appended: RoutingDecision[] = [];
90
+ const onAppend = (d: RoutingDecision) => appended.push(d);
91
+
92
+ rerender(
93
+ <RoutingDecisions
94
+ initial={list}
95
+ subscribe={subscribe}
96
+ onAppend={onAppend}
97
+ filterTier="ALL"
98
+ />,
99
+ );
100
+ expect(capturedHandler).toBeTruthy();
101
+ const fresh = dec('5', 'TIER3', 'opus-2', { costUsd: 0.07, latencyMs: 1200 });
102
+ // Drive the handler inside act() so React commits the setDecisions.
103
+ act(() => {
104
+ capturedHandler!({ type: 'routing:decision', decision: fresh });
105
+ });
106
+ expect(screen.getByTestId('routing-row-5')).toBeTruthy();
107
+ expect(appended).toHaveLength(1);
108
+ expect(appended[0].id).toBe('5');
109
+
110
+ // Malformed message should be ignored (no `routing:decision` type).
111
+ capturedHandler!({ type: 'tasks:change', task: {} as never });
112
+ expect(screen.queryByTestId('routing-row-')).toBeNull();
113
+
114
+ // Empty filterTier = 'ALL' shows everything
115
+ rerender(<RoutingDecisions initial={list} filterTier="ALL" />);
116
+ for (const d of list) {
117
+ expect(screen.getByTestId(`routing-row-${d.id}`)).toBeTruthy();
118
+ }
119
+ });
120
+
121
+ it('respects maxRows by pruning oldest decisions', () => {
122
+ // The component treats `initial` as most-recent-first (same
123
+ // convention as the WS stream). Build the list newest-first so
124
+ // maxRows=3 keeps the last 3 items from the array (the newest).
125
+ const list: RoutingDecision[] = [
126
+ dec('5', 'TIER1', 'haiku'),
127
+ dec('4', 'TIER1', 'haiku'),
128
+ dec('3', 'TIER1', 'haiku'),
129
+ dec('2', 'TIER1', 'haiku'),
130
+ dec('1', 'TIER1', 'haiku'),
131
+ ];
132
+ render(<RoutingDecisions initial={list} maxRows={3} />);
133
+ // Only 3 of 5 should be visible (most-recent first)
134
+ expect(screen.getByTestId('routing-row-5')).toBeTruthy();
135
+ expect(screen.getByTestId('routing-row-4')).toBeTruthy();
136
+ expect(screen.getByTestId('routing-row-3')).toBeTruthy();
137
+ expect(screen.queryByTestId('routing-row-2')).toBeNull();
138
+ expect(screen.queryByTestId('routing-row-1')).toBeNull();
139
+ });
140
+
141
+ it('compact prop toggles a different class', () => {
142
+ const one = dec('1', 'CODEMOD', 'codemod:add-logging');
143
+ const { container, rerender } = render(<RoutingDecisions initial={[one]} />);
144
+ expect(container.querySelector('.routing-decisions-compact')).toBeNull();
145
+ rerender(<RoutingDecisions initial={[one]} compact />);
146
+ expect(container.querySelector('.routing-decisions-compact')).toBeTruthy();
147
+ });
148
+ });
@@ -0,0 +1,160 @@
1
+ // src/web/components/agents/RoutingDecisions.tsx —
2
+ // F-035 (MetaHarness) — 3-tier model routing transparency panel.
3
+ //
4
+ // Mirrors ruflo's [CODEMOD_AVAILABLE] / [TASK_MODEL_RECOMMENDATION]
5
+ // convention (see goal_ui/src/components/agents/ExecutionMonitor.tsx).
6
+ // Renders the most recent routing decisions emitted on the WS
7
+ // `routing:decision` channel with a tier badge (CODEMOD/TIER1/TIER2/TIER3)
8
+ // plus model + cost + latency columns.
9
+ //
10
+ // Tier color scheme (per spec):
11
+ // CODEMOD → green ($0 deterministic codemod intent)
12
+ // TIER1 → blue (model)
13
+ // TIER2 → yellow (model)
14
+ // TIER3 → red (frontier model)
15
+ //
16
+ // Pure functional React. No class components. Vanilla CSS via the
17
+ // existing main.css (.routing-decisions, .routing-tier-* classes).
18
+
19
+ import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
20
+ import type { RoutingDecision, RoutingTier, WsMessage } from '../../lib/types';
21
+
22
+ export type RoutingDecisionsProps = {
23
+ /** Optional WebSocket subscription target. */
24
+ subscribe?: (handler: (msg: WsMessage) => void) => () => void;
25
+ /** Initial seed for tests / preview. */
26
+ initial?: RoutingDecision[];
27
+ /** Cap on visible rows (default 50). Older rows are pruned first. */
28
+ maxRows?: number;
29
+ /** Tier filter — undefined = all tiers. */
30
+ filterTier?: RoutingTier | 'ALL';
31
+ /** Compact (single-row) layout toggle. */
32
+ compact?: boolean;
33
+ /** Test-only callback when a decision is appended. */
34
+ onAppend?: (d: RoutingDecision) => void;
35
+ };
36
+
37
+ const TIER_ORDER: RoutingTier[] = ['CODEMOD', 'TIER1', 'TIER2', 'TIER3'];
38
+
39
+ function tierClass(tier: RoutingTier): string {
40
+ switch (tier) {
41
+ case 'CODEMOD': return 'routing-tier routing-tier-codemod';
42
+ case 'TIER1': return 'routing-tier routing-tier-1';
43
+ case 'TIER2': return 'routing-tier routing-tier-2';
44
+ case 'TIER3': return 'routing-tier routing-tier-3';
45
+ default: return 'routing-tier';
46
+ }
47
+ }
48
+
49
+ function formatCost(c: number | undefined): string {
50
+ if (c == null || !Number.isFinite(c)) return '—';
51
+ if (c === 0) return '$0';
52
+ if (c < 0.0001) return '<$0.0001';
53
+ if (c < 1) return `$${c.toFixed(4)}`;
54
+ return `$${c.toFixed(2)}`;
55
+ }
56
+
57
+ function formatLatency(ms: number | undefined): string {
58
+ if (ms == null || !Number.isFinite(ms)) return '—';
59
+ if (ms < 1000) return `${Math.round(ms)}ms`;
60
+ return `${(ms / 1000).toFixed(2)}s`;
61
+ }
62
+
63
+ function formatTime(ts: number): string {
64
+ try {
65
+ const d = new Date(ts);
66
+ if (Number.isNaN(d.getTime())) return String(ts);
67
+ return d.toLocaleTimeString();
68
+ } catch {
69
+ return String(ts);
70
+ }
71
+ }
72
+
73
+ export function RoutingDecisions(props: RoutingDecisionsProps) {
74
+ const {
75
+ subscribe,
76
+ initial,
77
+ maxRows = 50,
78
+ filterTier,
79
+ compact = false,
80
+ onAppend,
81
+ } = props;
82
+
83
+ const [decisions, setDecisions] = useState<RoutingDecision[]>(() =>
84
+ Array.isArray(initial) ? initial.slice(0, maxRows) : [],
85
+ );
86
+
87
+ const onAppendRef = useRef(onAppend);
88
+ useEffect(() => { onAppendRef.current = onAppend; }, [onAppend]);
89
+
90
+ const handle = useCallback((msg: WsMessage) => {
91
+ if (msg.type !== 'routing:decision') return;
92
+ const d = msg.decision;
93
+ if (!d || !d.id || !d.tier) return;
94
+ setDecisions((cur) => {
95
+ const next = [d, ...cur.filter((x) => x.id !== d.id)];
96
+ if (next.length > maxRows) next.length = maxRows;
97
+ return next;
98
+ });
99
+ onAppendRef.current?.(d);
100
+ }, [maxRows]);
101
+
102
+ // Wire up the WS subscription if one is provided.
103
+ useEffect(() => {
104
+ if (typeof subscribe !== 'function') return undefined;
105
+ return subscribe(handle);
106
+ }, [subscribe, handle]);
107
+
108
+ const visible = useMemo(() => {
109
+ if (!filterTier || filterTier === 'ALL') return decisions;
110
+ return decisions.filter((d) => d.tier === filterTier);
111
+ }, [decisions, filterTier]);
112
+
113
+ // ── Empty state ──────────────────────────────────────────────────
114
+ if (decisions.length === 0) {
115
+ return (
116
+ <div className="routing-decisions routing-decisions-empty" data-testid="routing-decisions-empty">
117
+ <div className="routing-decisions-empty-title">No routing decisions yet</div>
118
+ <div className="routing-decisions-empty-hint">
119
+ When the SDK emits a <code>routing:decision</code> event, the
120
+ most recent <strong>{maxRows}</strong> will appear here.
121
+ </div>
122
+ </div>
123
+ );
124
+ }
125
+
126
+ return (
127
+ <div className={compact ? 'routing-decisions routing-decisions-compact' : 'routing-decisions'} data-testid="routing-decisions">
128
+ <table className="routing-decisions-table" role="table">
129
+ <thead>
130
+ <tr>
131
+ <th scope="col">Tier</th>
132
+ <th scope="col">Model</th>
133
+ <th scope="col">Task</th>
134
+ <th scope="col">Cost</th>
135
+ <th scope="col">Latency</th>
136
+ <th scope="col">When</th>
137
+ </tr>
138
+ </thead>
139
+ <tbody>
140
+ {visible.map((d) => (
141
+ <tr key={d.id} data-testid={`routing-row-${d.id}`} className="routing-row">
142
+ <td>
143
+ <span className={tierClass(d.tier)} title={TIER_ORDER.includes(d.tier) ? `Tier ${d.tier}` : d.tier}>
144
+ {d.tier}
145
+ </span>
146
+ </td>
147
+ <td className="routing-model" title={d.model}>{d.model}</td>
148
+ <td className="routing-task">{d.task || '—'}</td>
149
+ <td className="routing-cost">{formatCost(d.costUsd)}</td>
150
+ <td className="routing-latency">{formatLatency(d.latencyMs)}</td>
151
+ <td className="routing-time" title={String(d.ts)}>{formatTime(d.ts)}</td>
152
+ </tr>
153
+ ))}
154
+ </tbody>
155
+ </table>
156
+ </div>
157
+ );
158
+ }
159
+
160
+ export default RoutingDecisions;