@polderlabs/bizar 6.3.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/.claude/hooks/sessionend-recall.mjs +3 -3
  2. package/.claude/hooks/worker-suggest.mjs +110 -0
  3. package/.claude/settings.json +9 -0
  4. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js → EnvVarsSection-CW6fWKds.js} +3 -3
  5. package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
  6. package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
  7. package/bizar-dash/dist/assets/{MobileChat-BJrqwVDd.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
  8. package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
  9. package/bizar-dash/dist/assets/{MobileSettings-CEQNJNLJ.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
  10. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
  11. package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
  12. package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
  13. package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
  14. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
  15. package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
  16. package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
  17. package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
  18. package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
  19. package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
  20. package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
  21. package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
  22. package/bizar-dash/dist/assets/{markdown-tOLaD6nm.js.map → markdown-w2bDDkAH.js.map} +1 -1
  23. package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
  24. package/bizar-dash/dist/assets/{mobile-DYCHcUpq.js.map → mobile-DXYCA0hC.js.map} +1 -1
  25. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
  26. package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
  27. package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
  28. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
  29. package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
  30. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
  31. package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
  32. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
  33. package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
  34. package/bizar-dash/dist/index.html +12 -10
  35. package/bizar-dash/dist/mobile.html +7 -4
  36. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  37. package/bizar-dash/src/server/api.mjs +11 -0
  38. package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
  39. package/bizar-dash/src/server/memory-distillation.mjs +296 -0
  40. package/bizar-dash/src/server/routes/distill.mjs +129 -0
  41. package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
  42. package/bizar-dash/src/web/App.tsx +4 -0
  43. package/bizar-dash/src/web/components/Tag.tsx +18 -5
  44. package/bizar-dash/src/web/components/Topbar.tsx +3 -0
  45. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
  46. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
  47. package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
  48. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
  49. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
  50. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
  51. package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
  52. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
  53. package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
  54. package/bizar-dash/src/web/lib/types.ts +25 -0
  55. package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
  56. package/bizar-dash/src/web/styles/main.css +251 -0
  57. package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
  58. package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
  59. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
  60. package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
  61. package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
  62. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
  63. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
  64. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
  65. package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
  66. package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
  67. package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
  68. package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
  69. package/bizar-dash/src/web/ui/controls/controls.css +454 -0
  70. package/bizar-dash/src/web/ui/controls/index.ts +33 -0
  71. package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
  72. package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
  73. package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
  74. package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
  75. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
  76. package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
  77. package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
  78. package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
  79. package/bizar-dash/src/web/ui/data/data.css +535 -0
  80. package/bizar-dash/src/web/ui/data/index.ts +31 -0
  81. package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
  82. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
  83. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
  84. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
  85. package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
  86. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
  87. package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
  88. package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
  89. package/bizar-dash/src/web/ui/index.ts +56 -0
  90. package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
  91. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
  92. package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
  93. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
  94. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
  95. package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
  96. package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
  97. package/bizar-dash/src/web/ui/layout/index.ts +33 -0
  98. package/bizar-dash/src/web/ui/layout/layout.css +413 -0
  99. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
  100. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
  101. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
  102. package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
  103. package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
  104. package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
  105. package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
  106. package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
  107. package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
  108. package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
  109. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
  110. package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
  111. package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
  112. package/bizar-dash/src/web/ui/styles/globals.css +86 -0
  113. package/bizar-dash/src/web/ui/styles/reset.css +125 -0
  114. package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
  115. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
  116. package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
  117. package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
  118. package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
  119. package/bizar-dash/src/web/views/Agents.tsx +506 -266
  120. package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
  121. package/bizar-dash/src/web/views/Overview.tsx +996 -448
  122. package/bizar-dash/src/web/views/Tasks.tsx +277 -273
  123. package/bizar-dash/tests/communication-log.test.tsx +67 -0
  124. package/bizar-dash/tests/dep-graph.test.tsx +40 -0
  125. package/bizar-dash/tests/event-log.test.tsx +61 -0
  126. package/bizar-dash/tests/goal-input.test.tsx +72 -0
  127. package/bizar-dash/tests/goap-planner.test.ts +68 -0
  128. package/bizar-dash/tests/quality-gates.test.tsx +59 -0
  129. package/bizar-dash/tests/setup.ts +31 -1
  130. package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
  131. package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
  132. package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
  133. package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
  134. package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
  135. package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
  136. package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
  137. package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
  138. package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
  139. package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
  140. package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
  141. package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
  142. package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
  143. package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
  144. package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
  145. package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
  146. package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
  147. package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
  148. package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
  149. package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
  150. package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
  151. package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
  152. package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
  153. package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
  154. package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
  155. package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
  156. package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
  157. package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
  158. package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
  159. package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
  160. package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
  161. package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
  162. package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
  163. package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
  164. package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
  165. package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
  166. package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
  167. package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
  168. package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
  169. package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
  170. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
  171. package/bizar-dash/tests/views/Agents.test.tsx +359 -0
  172. package/bizar-dash/tests/views/Overview.test.tsx +413 -0
  173. package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
  174. package/bizar-dash/vitest.config.ts +3 -1
  175. package/cli/__tests__/cost-gate.test.mjs +301 -0
  176. package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
  177. package/cli/bin.mjs +38 -0
  178. package/cli/commands/claim.mjs +282 -0
  179. package/cli/commands/cost.mjs +279 -0
  180. package/cli/cost-gate.mjs +501 -0
  181. package/cli/feature-list-bridge.mjs +400 -0
  182. package/cli/memory-constants.mjs +17 -0
  183. package/cli/worker-dispatcher.mjs +259 -0
  184. package/cli/worker-dispatcher.test.mjs +204 -0
  185. package/config/trigger-patterns.json +186 -0
  186. package/package.json +2 -2
  187. package/packages/sdk/package.json +1 -1
  188. package/packages/sdk/src/agent-registry.ts +304 -0
  189. package/packages/sdk/src/consensus/byzantine.ts +587 -0
  190. package/packages/sdk/src/consensus/index.ts +147 -0
  191. package/packages/sdk/src/consensus/queen.ts +173 -0
  192. package/packages/sdk/src/consensus/types.ts +199 -0
  193. package/packages/sdk/src/federation/audit.ts +156 -0
  194. package/packages/sdk/src/federation/budget.ts +269 -0
  195. package/packages/sdk/src/federation/envelope.ts +144 -0
  196. package/packages/sdk/src/federation/hmac.ts +160 -0
  197. package/packages/sdk/src/federation/index.ts +443 -0
  198. package/packages/sdk/src/federation/pii.ts +241 -0
  199. package/packages/sdk/src/federation/policy.ts +112 -0
  200. package/packages/sdk/src/federation/trust.ts +146 -0
  201. package/packages/sdk/src/index.ts +67 -0
  202. package/packages/sdk/src/mcp/server.ts +351 -1
  203. package/packages/sdk/src/router/codemod-intent.ts +125 -0
  204. package/packages/sdk/src/router/index.ts +247 -0
  205. package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
  206. package/packages/sdk/src/router/memory-distillation.ts +249 -0
  207. package/packages/sdk/src/router/model-router.ts +235 -0
  208. package/packages/sdk/src/router/q-learning-router.ts +304 -0
  209. package/packages/sdk/src/swarm-topology.ts +279 -0
  210. package/packages/sdk/tests/agent-registry.test.ts +285 -0
  211. package/packages/sdk/tests/consensus.test.ts +376 -0
  212. package/packages/sdk/tests/federation/audit.test.ts +164 -0
  213. package/packages/sdk/tests/federation/budget.test.ts +189 -0
  214. package/packages/sdk/tests/federation/envelope.test.ts +120 -0
  215. package/packages/sdk/tests/federation/hmac.test.ts +194 -0
  216. package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
  217. package/packages/sdk/tests/federation/pii.test.ts +106 -0
  218. package/packages/sdk/tests/federation/policy.test.ts +140 -0
  219. package/packages/sdk/tests/federation/trust.test.ts +124 -0
  220. package/packages/sdk/tests/mcp-tools.test.ts +204 -0
  221. package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
  222. package/packages/sdk/tests/model-router.test.mjs +108 -0
  223. package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
  224. package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
  225. package/packages/sdk/tests/router.test.mjs +91 -0
  226. package/packages/sdk/tests/sdk.test.mjs +26 -2
  227. package/packages/sdk/tests/swarm-topology.test.ts +258 -0
  228. package/scripts/bh-full-e2e.mjs +11 -15
  229. package/bizar-dash/dist/assets/MobileChat-BJrqwVDd.js +0 -1
  230. package/bizar-dash/dist/assets/MobileSettings-CEQNJNLJ.js +0 -1
  231. package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
  232. package/bizar-dash/dist/assets/main-IvfQAOfy.js +0 -18
  233. package/bizar-dash/dist/assets/main-IvfQAOfy.js.map +0 -1
  234. package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
  235. package/bizar-dash/dist/assets/markdown-tOLaD6nm.js +0 -1
  236. package/bizar-dash/dist/assets/mobile-DYCHcUpq.js +0 -1
  237. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js +0 -2
  238. package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js.map +0 -1
  239. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
  240. package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
  241. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js +0 -2
  242. package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js.map +0 -1
  243. package/bizar-dash/dist/assets/vendor-C843201K.js +0 -29
  244. package/bizar-dash/dist/assets/vendor-C843201K.js.map +0 -1
  245. package/packages/sdk/package-lock.json +0 -32
@@ -29,17 +29,19 @@
29
29
  }
30
30
  })();
31
31
  </script>
32
- <script type="module" crossorigin src="/assets/main-IvfQAOfy.js"></script>
33
- <link rel="modulepreload" crossorigin href="/assets/react-vendor-Dn4wqh4Z.js">
34
- <link rel="modulepreload" crossorigin href="/assets/icons-Do5N2jmX.js">
35
- <link rel="modulepreload" crossorigin href="/assets/mobile-layout-CBHjpwsb.js">
36
- <link rel="modulepreload" crossorigin href="/assets/Toast-Cpl6-E63.js">
37
- <link rel="modulepreload" crossorigin href="/assets/EnvVarsSection-B58aiJiE.js">
38
- <link rel="modulepreload" crossorigin href="/assets/vendor-C843201K.js">
39
- <link rel="modulepreload" crossorigin href="/assets/markdown-tOLaD6nm.js">
40
- <link rel="modulepreload" crossorigin href="/assets/useSlashCommands-Bd7_FA6U.js">
32
+ <script type="module" crossorigin src="/assets/main-CO8fIxQK.js"></script>
33
+ <link rel="modulepreload" crossorigin href="/assets/vendor-Di7Cp-rw.js">
34
+ <link rel="modulepreload" crossorigin href="/assets/flow-BpU0-gK2.js">
35
+ <link rel="modulepreload" crossorigin href="/assets/react-vendor-D3pra6w-.js">
36
+ <link rel="modulepreload" crossorigin href="/assets/icons-B0AKnYI3.js">
37
+ <link rel="modulepreload" crossorigin href="/assets/mobile-layout-DSmtNPja.js">
38
+ <link rel="modulepreload" crossorigin href="/assets/Toast-WTxc3m2g.js">
39
+ <link rel="modulepreload" crossorigin href="/assets/EnvVarsSection-CW6fWKds.js">
40
+ <link rel="modulepreload" crossorigin href="/assets/markdown-w2bDDkAH.js">
41
+ <link rel="modulepreload" crossorigin href="/assets/useSlashCommands-3DFLOfpk.js">
41
42
  <link rel="stylesheet" crossorigin href="/assets/mobile-layout-CJnZNLy3.css">
42
- <link rel="stylesheet" crossorigin href="/assets/main-ietCEg_R.css">
43
+ <link rel="stylesheet" crossorigin href="/assets/react-vendor-BnuhLJ6X.css">
44
+ <link rel="stylesheet" crossorigin href="/assets/main-C-Md3DaY.css">
43
45
  </head>
44
46
  <body>
45
47
  <div id="root"></div>
@@ -12,10 +12,13 @@
12
12
  <link rel="preconnect" href="https://fonts.googleapis.com" />
13
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
14
14
  <link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
15
- <script type="module" crossorigin src="/assets/mobile-DYCHcUpq.js"></script>
16
- <link rel="modulepreload" crossorigin href="/assets/react-vendor-Dn4wqh4Z.js">
17
- <link rel="modulepreload" crossorigin href="/assets/icons-Do5N2jmX.js">
18
- <link rel="modulepreload" crossorigin href="/assets/mobile-layout-CBHjpwsb.js">
15
+ <script type="module" crossorigin src="/assets/mobile-DXYCA0hC.js"></script>
16
+ <link rel="modulepreload" crossorigin href="/assets/vendor-Di7Cp-rw.js">
17
+ <link rel="modulepreload" crossorigin href="/assets/flow-BpU0-gK2.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/react-vendor-D3pra6w-.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/icons-B0AKnYI3.js">
20
+ <link rel="modulepreload" crossorigin href="/assets/mobile-layout-DSmtNPja.js">
21
+ <link rel="stylesheet" crossorigin href="/assets/react-vendor-BnuhLJ6X.css">
19
22
  <link rel="stylesheet" crossorigin href="/assets/mobile-layout-CJnZNLy3.css">
20
23
  </head>
21
24
  <body>
@@ -1 +1 @@
1
- {"version":"4.1.10","results":[[":tests/mobile-layout.test.tsx",{"duration":320.32545200000004,"failed":false}],[":tests/autosave.test.tsx",{"duration":301.22693400000014,"failed":false}],[":tests/eval-web-ui.test.tsx",{"duration":116.93985599999996,"failed":false}],[":tests/mobile-settings.test.tsx",{"duration":221.603749,"failed":false}],[":tests/mobile-overview.test.tsx",{"duration":320.2485939999999,"failed":false}],[":tests/minimax-bar.test.tsx",{"duration":22.62473,"failed":false}],[":tests/BackgroundAgents.test.tsx",{"duration":293.822576,"failed":false}],[":tests/components/settings-search.test.tsx",{"duration":753.5182920000001,"failed":false}],[":tests/a11y/forms.test.tsx",{"duration":94.38952799999993,"failed":true}],[":tests/settings-layout.test.tsx",{"duration":233.74806,"failed":false}],[":tests/a11y.test.tsx",{"duration":1027.422834,"failed":false}],[":tests/mobile-tasks.test.tsx",{"duration":217.895489,"failed":false}],[":tests/components/doctor-panel.test.tsx",{"duration":50.94508099999996,"failed":false}],[":tests/views/topbar.test.tsx",{"duration":515.6951700000001,"failed":false}],[":tests/settings-mode-wiring.test.tsx",{"duration":323.99789299999986,"failed":false}],[":tests/chat-composer.test.tsx",{"duration":285.23247200000003,"failed":false}],[":tests/backup-restore.test.tsx",{"duration":197.0859200000001,"failed":false}],[":tests/views/Memory.test.tsx",{"duration":427.6884359999999,"failed":false}],[":tests/components/Toast.test.tsx",{"duration":151.46341700000005,"failed":false}],[":tests/views/sidebar.test.tsx",{"duration":197.5262919999999,"failed":false}],[":tests/settings-nav.test.tsx",{"duration":322.146624,"failed":false}],[":tests/lib/search-fuzzy.test.ts",{"duration":5.650273999999968,"failed":false}],[":tests/lib/utils.test.ts",{"duration":17.499018999999976,"failed":false}],[":tests/voice-recorder.test.tsx",{"duration":145.993248,"failed":false}],[":tests/components/Modal.test.tsx",{"duration":182.68028600000002,"failed":false}],[":tests/mobile-chat.test.tsx",{"duration":40.88216,"failed":false}],[":tests/memory-graph-view.test.tsx",{"duration":33.883016,"failed":false}],[":tests/hooks/useModal.test.tsx",{"duration":164.85650500000008,"failed":false}],[":tests/components/screenshot-ocr.test.tsx",{"duration":29.824476000000004,"failed":false}],[":tests/hooks/useToast.test.tsx",{"duration":77.48894299999995,"failed":false}],[":tests/components/workspace-selector.test.tsx",{"duration":145.988789,"failed":false}],[":tests/lib/i18n.test.ts",{"duration":2.6850140000000238,"failed":false}],[":tests/components/Button.test.tsx",{"duration":73.86340099999995,"failed":false}],[":tests/components/Spinner.test.tsx",{"duration":47.97077300000001,"failed":false}],[":tests/components/StatusBadge.test.tsx",{"duration":26.21738899999997,"failed":false}],[":tests/components/Card.test.tsx",{"duration":24.035827999999924,"failed":false}]]}
1
+ {"version":"4.1.10","results":[[":tests/eval-web-ui.test.tsx",{"duration":90.141617,"failed":false}],[":tests/views/Agents.test.tsx",{"duration":1129.4144450000001,"failed":false}],[":tests/BackgroundAgents.test.tsx",{"duration":276.399233,"failed":false}],[":tests/components/settings-search.test.tsx",{"duration":726.4820490000001,"failed":false}],[":tests/views/Memory.test.tsx",{"duration":408.13227500000005,"failed":false}],[":tests/views/Overview.test.tsx",{"duration":859.8150840000003,"failed":false}],[":tests/views/Tasks.test.tsx",{"duration":888.7298819999999,"failed":false}],[":tests/mobile-overview.test.tsx",{"duration":210.54887800000006,"failed":false}],[":tests/settings-mode-wiring.test.tsx",{"duration":308.4315459999999,"failed":false}],[":tests/mobile-layout.test.tsx",{"duration":283.86069,"failed":false}],[":tests/backup-restore.test.tsx",{"duration":161.48136599999998,"failed":false}],[":src/web/components/agents/RoutingDecisions.test.tsx",{"duration":53.620813999999996,"failed":false}],[":tests/chat-composer.test.tsx",{"duration":278.741524,"failed":false}],[":tests/mobile-tasks.test.tsx",{"duration":194.2860280000001,"failed":false}],[":tests/autosave.test.tsx",{"duration":243.45155699999998,"failed":false}],[":tests/mobile-settings.test.tsx",{"duration":196.93678,"failed":false}],[":tests/a11y.test.tsx",{"duration":4267.288423,"failed":false}],[":tests/lib/search-fuzzy.test.ts",{"duration":5.8234639999999445,"failed":false}],[":tests/settings-layout.test.tsx",{"duration":215.84758599999998,"failed":false}],[":tests/a11y/forms.test.tsx",{"duration":100.41024599999992,"failed":true}],[":tests/ui/data/DataTable.test.tsx",{"duration":209.18487700000003,"failed":false}],[":tests/settings-nav.test.tsx",{"duration":289.062013,"failed":false}],[":tests/lib/utils.test.ts",{"duration":19.92861300000004,"failed":false}],[":tests/minimax-bar.test.tsx",{"duration":49.89606600000002,"failed":false}],[":tests/ui/feedback/Toast.test.tsx",{"duration":254.20442300000002,"failed":false}],[":tests/ui/navigation/CommandPalette.test.tsx",{"duration":294.548311,"failed":false}],[":tests/components/doctor-panel.test.tsx",{"duration":81.59931099999994,"failed":false}],[":tests/views/sidebar.test.tsx",{"duration":274.0032779999999,"failed":false}],[":tests/ui/layout/Tabs.test.tsx",{"duration":276.09256500000004,"failed":false}],[":tests/views/topbar.test.tsx",{"duration":861.390108,"failed":false}],[":tests/ui/feedback/Tooltip.test.tsx",{"duration":109.88648899999998,"failed":false}],[":tests/components/Toast.test.tsx",{"duration":220.89043600000002,"failed":false}],[":tests/mobile-chat.test.tsx",{"duration":91.99137599999995,"failed":false}],[":tests/voice-recorder.test.tsx",{"duration":152.09344199999998,"failed":false}],[":tests/ui/data/StatTile.test.tsx",{"duration":111.74475499999994,"failed":false}],[":tests/ui/feedback/Dialog.test.tsx",{"duration":249.64788299999998,"failed":false}],[":tests/ui/layout/Sidebar.test.tsx",{"duration":158.61740600000007,"failed":false}],[":tests/goal-input.test.tsx",{"duration":378.88545,"failed":false}],[":tests/goap-planner.test.ts",{"duration":70.64754500000004,"failed":false}],[":tests/components/Modal.test.tsx",{"duration":379.24037999999996,"failed":false}],[":tests/ui/feedback/ProgressBar.test.tsx",{"duration":316.9804250000001,"failed":false}],[":tests/communication-log.test.tsx",{"duration":153.09210300000018,"failed":false}],[":tests/memory-graph-view.test.tsx",{"duration":98.24405100000013,"failed":false}],[":tests/ui/data/KeyValueList.test.tsx",{"duration":216.36391500000013,"failed":false}],[":tests/ui/navigation/NavLink.test.tsx",{"duration":150.2073929999999,"failed":false}],[":tests/hooks/useModal.test.tsx",{"duration":255.65911600000004,"failed":false}],[":tests/ui/layout/Breadcrumbs.test.tsx",{"duration":161.1209960000001,"failed":false}],[":tests/ui/controls/Select.test.tsx",{"duration":175.14181499999995,"failed":false}],[":tests/ui/data/BarChart.test.tsx",{"duration":79.33408600000007,"failed":false}],[":tests/components/screenshot-ocr.test.tsx",{"duration":88.08010200000012,"failed":false}],[":tests/components/workspace-selector.test.tsx",{"duration":247.4938420000001,"failed":false}],[":tests/ui/navigation/NavGroup.test.tsx",{"duration":190.2916439999999,"failed":false}],[":tests/event-log.test.tsx",{"duration":82.9334339999998,"failed":false}],[":tests/ui/controls/RadioGroup.test.tsx",{"duration":230.29615400000012,"failed":false}],[":tests/ui/data/Sparkline.test.tsx",{"duration":86.33221800000001,"failed":false}],[":tests/dep-graph.test.tsx",{"duration":154.20839,"failed":false}],[":tests/quality-gates.test.tsx",{"duration":174.36193300000014,"failed":false}],[":tests/ui/controls/NumberInput.test.tsx",{"duration":149.40149100000008,"failed":false}],[":tests/ui/controls/SearchInput.test.tsx",{"duration":176.44394699999998,"failed":false}],[":tests/ui/layout/Panel.test.tsx",{"duration":78.58078499999988,"failed":false}],[":tests/ui/data/EmptyState.test.tsx",{"duration":180.84135200000014,"failed":false}],[":tests/ui/primitives/Box.test.tsx",{"duration":40.32523200000014,"failed":false}],[":tests/ui/layout/AppShell.test.tsx",{"duration":89.41974600000003,"failed":false}],[":tests/ui/controls/Button.test.tsx",{"duration":284.144323,"failed":false}],[":tests/ui/data/ErrorState.test.tsx",{"duration":216.0029730000001,"failed":false}],[":tests/ui/feedback/StatusDot.test.tsx",{"duration":169.31442400000003,"failed":false}],[":tests/hooks/useToast.test.tsx",{"duration":175.5546750000001,"failed":false}],[":tests/ui/controls/Slider.test.tsx",{"duration":192.89253099999985,"failed":false}],[":tests/ui/layout/Topbar.test.tsx",{"duration":79.371037,"failed":false}],[":tests/ui/data/LoadingState.test.tsx",{"duration":119.85838999999999,"failed":false}],[":tests/ui/controls/TextInput.test.tsx",{"duration":178.7941740000001,"failed":false}],[":tests/lib/i18n.test.ts",{"duration":13.539857999999981,"failed":false}],[":tests/ui/feedback/Badge.test.tsx",{"duration":68.21107300000006,"failed":false}],[":tests/ui/primitives/Stack.test.tsx",{"duration":46.52451499999995,"failed":false}],[":tests/components/Button.test.tsx",{"duration":109.13502100000005,"failed":false}],[":tests/ui/controls/Checkbox.test.tsx",{"duration":108.74041599999987,"failed":false}],[":tests/ui/controls/Toggle.test.tsx",{"duration":97.17910299999994,"failed":false}],[":tests/components/Card.test.tsx",{"duration":43.15031799999997,"failed":false}],[":tests/components/StatusBadge.test.tsx",{"duration":39.455498000000034,"failed":false}],[":tests/ui/primitives/Grid.test.tsx",{"duration":34.393512999999984,"failed":false}],[":tests/ui/controls/IconButton.test.tsx",{"duration":75.47701600000005,"failed":false}],[":tests/ui/primitives/Separator.test.tsx",{"duration":24.607657000000017,"failed":false}],[":tests/ui/primitives/Inline.test.tsx",{"duration":23.645235999999954,"failed":false}],[":tests/ui/controls/Kbd.test.tsx",{"duration":25.579968000000008,"failed":false}],[":tests/ui/layout/PanelHeader.test.tsx",{"duration":26.411457999999925,"failed":false}],[":tests/components/Spinner.test.tsx",{"duration":48.668087000000014,"failed":false}],[":tests/ui/primitives/VisuallyHidden.test.tsx",{"duration":21.951294000000075,"failed":false}]]}
@@ -59,6 +59,9 @@ import { createEvalRouter } from './routes/eval.mjs';
59
59
  import { createWorkspacesRouter } from './routes/workspaces.mjs';
60
60
  import { createUsersRouter } from './routes/users.mjs';
61
61
  import { createVoiceRouter } from './routes/voice.mjs';
62
+ // v6.4.0 — F-036 Goal Planner UI. POST /api/goal-planner/plan returns
63
+ // a GOAP-style A* plan for a plain-English goal.
64
+ import { createGoalPlannerRouter } from './routes/goal-planner.mjs';
62
65
  import { attachUserContext } from './auth.mjs';
63
66
 
64
67
  /**
@@ -140,6 +143,12 @@ export async function createApiRouter({
140
143
  // v5.0.0 — Voice notes (record, transcribe, list, delete, stream audio).
141
144
  router.use(createVoiceRouter({}));
142
145
  router.use(createDiagnosticsRouter());
146
+ // v6.4.0 — F-033 ReasoningBank distillation (ADR-174). Mounted
147
+ // here so the distillation log lives next to the rest of the
148
+ // self-learning surface. Lazy-imported for the same reason as
149
+ // memory.mjs above.
150
+ const { createDistillRouter } = await import('./routes/distill.mjs');
151
+ router.use(createDistillRouter({ projectRoot }));
143
152
  // v6.0.0 — Doctor page API. Mounted right after diagnostics so the
144
153
  // /doctor/* paths live next to the legacy /diagnostics/* surface
145
154
  // they conceptually extend. Each route inside is at its bare path
@@ -147,6 +156,8 @@ export async function createApiRouter({
147
156
  // level once /api is prepended by server.mjs.
148
157
  router.use('/doctor', createDoctorRouter());
149
158
  router.use(createPairRouter({ state, broadcast }));
159
+ // v6.4.0 — F-036 Goal Planner UI. Plain-English goal → A* plan.
160
+ router.use(createGoalPlannerRouter({ broadcast }));
150
161
  router.use(createThemesRouter({ state }));
151
162
  router.use(createNotificationsRouter({ broadcast }));
152
163
  router.use(createArtifactsRouter({ state, broadcast, projectRoot }));
@@ -0,0 +1,218 @@
1
+ /**
2
+ * memory-consolidator.mjs — thin wrapper around `memory-distillation.mjs`.
3
+ *
4
+ * v6.4.0 — ported from ruflo ADR-174. The consolidator reads from the
5
+ * dashboard's `memory-store.mjs`, runs the RETRIEVE → JUDGE → DISTILL
6
+ * → CONSOLIDATE pipeline, and writes promoted patterns back to the
7
+ * vault as new entries of `kind: 'pattern'`.
8
+ *
9
+ * Idempotency: a second run with the same input produces the same
10
+ * patterns. The write-back is deduped by `pattern.id` (file stem
11
+ * `pat_<hash>.md`); already-existing pattern files are skipped, not
12
+ * overwritten. This honours the ADR-174 invariant:
13
+ * "memory_entries source preservation — row count + content
14
+ * unchanged after a run; promoted patterns are additive"
15
+ *
16
+ * Public surface:
17
+ * - runConsolidation({ projectRoot, since }) → { distilled, promoted, byTier, written }
18
+ * - runConsolidationInMemory(entries) → same shape minus `written`
19
+ */
20
+
21
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
22
+ import { dirname, join } from "node:path";
23
+
24
+ import { listNotes, writeNote } from "./memory-store.mjs";
25
+ import { resolveVaultRoot } from "../../../packages/sdk/src/memory/index.js";
26
+ import { runDistillation } from "./memory-distillation.mjs";
27
+
28
+ /**
29
+ * Where the dashboard-side machine-readable distill log is written.
30
+ * `.bizar/distilled-patterns.json` lives at the repo root so that the
31
+ * dashboard UI, the Odin prompt primer, and the verification scripts
32
+ * can all reach it without dipping into the vault. Format is
33
+ * ADR-174-compliant:
34
+ *
35
+ * {
36
+ * "version": 1,
37
+ * "generatedAt": "<iso8601>",
38
+ * "byTier": { "oracle:test-exec": N, "proxy:structural": N, "judge:fable": N },
39
+ * "patterns": [
40
+ * { "id", "kind", "summary", "uses": [...], "evidence": [...],
41
+ * "provenance_tier", "promoted", "score", "forgettingRate" },
42
+ * ...
43
+ * ]
44
+ * }
45
+ */
46
+ export const DISTILLED_PATTERNS_FILE = ".bizar/distilled-patterns.json";
47
+
48
+ /**
49
+ * In-memory variant — pure function over the entries you pass in.
50
+ * Exposed for unit tests and the `memory_distill` MCP tool.
51
+ *
52
+ * @param {Array<Record<string, unknown>>} entries
53
+ */
54
+ export function runConsolidationInMemory(entries) {
55
+ const result = runDistillation(entries);
56
+ return {
57
+ distilled: result.patterns.length,
58
+ promoted: result.promoted.map((p) => p.id),
59
+ patterns: result.patterns,
60
+ byTier: result.byTier,
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Vault-backed variant — reads notes from the dashboard vault, runs
66
+ * the pipeline, and writes promoted patterns back.
67
+ *
68
+ * @param {{ projectRoot?: string, since?: string }} [opts]
69
+ */
70
+ export function runConsolidation(opts = {}) {
71
+ const projectRoot = opts.projectRoot ?? process.cwd();
72
+ const since = opts.since ? new Date(opts.since) : null;
73
+
74
+ // Read every note. `listNotes` is gitignore-aware and skips .obsidian/.
75
+ const notes = listNotes(projectRoot, { limit: 10000 });
76
+
77
+ // Adapter: dashboard's `listNotes` returns the SDK `MemoryNote`
78
+ // shape; the distiller wants the Bizar memory schema. We bridge by
79
+ // aliasing frontmatter fields the distiller reads.
80
+ const entries = notes
81
+ .filter((n) => !since || since <= parseCreatedAt(n))
82
+ .map((n) => ({
83
+ memory_id: n.relPath,
84
+ path: n.relPath,
85
+ relPath: n.relPath,
86
+ frontmatter: n.frontmatter ?? {},
87
+ body: n.body ?? "",
88
+ kind: n.frontmatter?.kind ?? n.frontmatter?.type,
89
+ created: n.frontmatter?.createdAt ?? n.frontmatter?.created,
90
+ createdAt: n.frontmatter?.createdAt,
91
+ updatedAt: n.frontmatter?.updatedAt,
92
+ tags: n.frontmatter?.tags,
93
+ }));
94
+
95
+ const result = runDistillation(entries);
96
+
97
+ // Write promoted patterns back. Idempotent: skip if already exists
98
+ // (a prior run produced the same pattern file).
99
+ const written = [];
100
+ for (const p of result.promoted) {
101
+ const fm = {
102
+ kind: "pattern",
103
+ promoted: true,
104
+ provenance_tier: p.provenance_tier,
105
+ uses: p.uses.length,
106
+ score: p.score,
107
+ createdAt: new Date().toISOString(),
108
+ tags: ["pattern", "distilled"],
109
+ };
110
+ const body = [
111
+ `# ${p.summary}`,
112
+ "",
113
+ `_provenance_tier: ${p.provenance_tier}_`,
114
+ `_promoted: yes_`,
115
+ `_uses: ${p.uses.length}_`,
116
+ "",
117
+ "## Evidence",
118
+ "",
119
+ ...p.evidence,
120
+ ].join("\n");
121
+
122
+ const relPath = `patterns/${p.id}.md`;
123
+ // If the file already exists, leave it alone (idempotent).
124
+ const existing = notes.find((n) => n.relPath === relPath);
125
+ if (existing) continue;
126
+
127
+ try {
128
+ const out = writeNote(projectRoot, relPath, { frontmatter: fm, body });
129
+ written.push(out.relPath);
130
+ } catch {
131
+ // Best-effort writes — a vault with read-only test vault
132
+ // shouldn't crash the distillation.
133
+ }
134
+ }
135
+
136
+ return {
137
+ distilled: result.patterns.length,
138
+ promoted: result.promoted.map((p) => p.id),
139
+ patterns: result.patterns,
140
+ byTier: result.byTier,
141
+ written,
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Write the on-disk distill log (`.bizar/distilled-patterns.json`).
147
+ * Idempotent and best-effort — does NOT throw. Returns the absolute
148
+ * (or relative-to-projectRoot) path of the file written, or `null`
149
+ * if the write was skipped (e.g. directory not writable).
150
+ *
151
+ * Decorates each pattern with:
152
+ * - `forgettingRate`: 0.0–1.0 (smaller = more durable). Computed
153
+ * as `1 / (1 + uses.length)` per ADR-174 §"CONSOLIDATE".
154
+ * - `promoted`: copied from the distiller.
155
+ * - `provenance_tier`: copied verbatim.
156
+ *
157
+ * @param {ReturnType<typeof runConsolidation>} consolidation
158
+ * @param {{ projectRoot?: string, filePath?: string }} [opts]
159
+ * @returns {string | null}
160
+ */
161
+ export function writeDistilledPatternsFile(consolidation, opts = {}) {
162
+ const projectRoot = opts.projectRoot ?? process.cwd();
163
+ const fp = opts.filePath
164
+ ? (opts.filePath.startsWith("/") ? opts.filePath : join(projectRoot, opts.filePath))
165
+ : join(projectRoot, DISTILLED_PATTERNS_FILE);
166
+
167
+ const payload = {
168
+ version: 1,
169
+ generatedAt: new Date().toISOString(),
170
+ byTier: consolidation.byTier ?? {
171
+ "oracle:test-exec": 0,
172
+ "proxy:structural": 0,
173
+ "judge:fable": 0,
174
+ },
175
+ distilled: consolidation.distilled ?? 0,
176
+ promoted: consolidation.promoted ?? [],
177
+ patterns: (consolidation.patterns ?? []).map((p) => ({
178
+ id: p.id,
179
+ kind: p.kind ?? "pattern",
180
+ summary: p.summary ?? "",
181
+ uses: p.uses ?? [],
182
+ evidence: p.evidence ?? [],
183
+ provenance_tier: p.provenance_tier ?? "proxy:structural",
184
+ promoted: Boolean(p.promoted),
185
+ score: typeof p.score === "number" ? p.score : 0.5,
186
+ forgettingRate: forgettingRate(p.uses ?? []),
187
+ })),
188
+ };
189
+
190
+ try {
191
+ mkdirSync(dirname(fp), { recursive: true });
192
+ writeFileSync(fp, JSON.stringify(payload, null, 2), "utf-8");
193
+ return fp;
194
+ } catch {
195
+ return null;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Forgetfulness score (ADR-174 §"forgetting curve"). Patterns with
201
+ * more `uses` are more durable; a brand-new pattern is 1.0 (fully
202
+ * forgettable); a pattern with 4 uses settles at 0.2.
203
+ */
204
+ function forgettingRate(uses) {
205
+ const n = Array.isArray(uses) ? uses.length : 0;
206
+ return 1 / (1 + n);
207
+ }
208
+
209
+ function parseCreatedAt(note) {
210
+ const t = note?.frontmatter?.createdAt ?? note?.frontmatter?.created;
211
+ if (!t) return new Date(0);
212
+ const d = new Date(t);
213
+ return Number.isNaN(d.getTime()) ? new Date(0) : d;
214
+ }
215
+
216
+ /** Re-export so the dashboard server can `import { resolveVaultRoot }
217
+ * from './memory-consolidator.mjs'` when wiring the MCP tool. */
218
+ export { resolveVaultRoot };
@@ -0,0 +1,296 @@
1
+ /**
2
+ * memory-distillation.mjs — RETRIEVE → JUDGE → DISTILL → CONSOLIDATE
3
+ * (ADR-174) applied to an in-memory array of Bizar memory entries.
4
+ *
5
+ * v6.4.0 — ported from ruflo `@claude-flow/neural/src/reasoning-bank.ts`
6
+ * (the 4-step pipeline) + ADR-174 (provenance-tiered promote gate).
7
+ *
8
+ * This is the deterministic, $0 default path. It does NOT call any
9
+ * LLM. Provenance is inferred from the entry's frontmatter: entries
10
+ * flagged with `kind: feedback` or executing a test result become
11
+ * `oracle:test-exec`; everything else becomes `proxy:structural`.
12
+ * (`judge:fable` is reserved for the cost-bounded LLM-judge path
13
+ * enabled by `BIZAR_DISTILL_BUDGET_USD > 0` — out of scope here.)
14
+ *
15
+ * Returned `Pattern` objects carry a `provenance_tier` and a
16
+ * `promoted` flag. Only `oracle:test-exec` (and `judge:fable`)
17
+ * patterns can be promoted; `proxy:structural` patterns stay
18
+ * searchable but never earn the `promoted` boolean.
19
+ *
20
+ * Pure function — no I/O. Idempotent: same input → same output.
21
+ */
22
+
23
+ /** Allowed provenance_tier values per ADR-174. */
24
+ export const PROVENANCE_TIERS = /** @type {const} */ ([
25
+ "oracle:test-exec",
26
+ "proxy:structural",
27
+ "judge:fable",
28
+ ]);
29
+
30
+ /** Default complexity bucket thresholds (length-based, retrofitted with
31
+ * a code-block bonus). Matches ADR-174 §"RETRIEVE" cost = $0 default. */
32
+ const COMPLEXITY_BOUNDS = {
33
+ /** longest body length considered "simple". */
34
+ simpleMax: 600,
35
+ /** longest body length considered "moderate". */
36
+ moderateMax: 2400,
37
+ };
38
+
39
+ /**
40
+ * @typedef {Object} MemoryEntry
41
+ * @property {string} [memory_id]
42
+ * @property {string} [id]
43
+ * @property {string} [path]
44
+ * @property {string} [relPath]
45
+ * @property {Record<string, unknown>} [frontmatter]
46
+ * @property {string} [body]
47
+ * @property {string} [kind] — One of: coding_convention | bug_pattern | task_summary | session_summary | feedback | …
48
+ * @property {string} [type]
49
+ * @property {string} [created]
50
+ * @property {string} [createdAt]
51
+ * @property {string} [updatedAt]
52
+ * @property {string[]} [tags]
53
+ */
54
+
55
+ /**
56
+ * @typedef {Object} Pattern
57
+ * @property {string} id — "pat_<hash>"
58
+ * @property {string} kind — "pattern"
59
+ * @property {string} summary — short headline
60
+ * @property {string[]} uses — entry ids that contributed
61
+ * @property {string[]} evidence — excerpt lines cited as evidence
62
+ * @property {"oracle:test-exec"|"proxy:structural"|"judge:fable"} provenance_tier
63
+ * @property {boolean} promoted — promote gate
64
+ * @property {number} score — heuristic quality
65
+ */
66
+
67
+ /**
68
+ * RETRIEVE → tag each entry with a complexity bucket.
69
+ * Simple: short body, no code block, no test_exec tag.
70
+ * Complex: long body OR has a code block.
71
+ * @param {MemoryEntry} entry
72
+ */
73
+ export function retrieve(entry) {
74
+ const body = String(entry?.body ?? "");
75
+ const fm = entry?.frontmatter ?? {};
76
+ const hasCodeBlock = /```/.test(body);
77
+ const testExec =
78
+ Boolean(fm.test_exec) ||
79
+ Boolean(fm.testExec) ||
80
+ (Array.isArray(fm.tags) && fm.tags.some((t) => String(t).includes("test-exec"))) ||
81
+ (typeof fm.kind === "string" && fm.kind === "feedback");
82
+ const len = body.length;
83
+ let complexity;
84
+ if (hasCodeBlock || len > COMPLEXITY_BOUNDS.moderateMax) complexity = "complex";
85
+ else if (len > COMPLEXITY_BOUNDS.simpleMax) complexity = "moderate";
86
+ else complexity = "simple";
87
+ return { complexity, testExec, hasCodeBlock, length: len };
88
+ }
89
+
90
+ /**
91
+ * JUDGE → assign provenance_tier based on complexity + tags.
92
+ * Oracle tier requires `testExec === true` (execution-observed).
93
+ * @param {MemoryEntry} entry
94
+ * @param {{ complexity: string, testExec: boolean, hasCodeBlock: boolean, length: number }} retrieval
95
+ */
96
+ export function judge(entry, retrieval) {
97
+ if (retrieval.testExec) return "oracle:test-exec";
98
+ // `judge:fable` reserved for the cost-bounded LLM path — not set
99
+ // here. Empty / null bodies (e.g. test stubs) get the proxy
100
+ // structural tier; that's correct — no execution observation, no
101
+ // Fable budget spend, so proxy is honest.
102
+ void entry;
103
+ return "proxy:structural";
104
+ }
105
+
106
+ /**
107
+ * DISTILL → produce a Pattern candidate from a memory entry, if the
108
+ * entry is the kind we surface as a "pattern". Coding conventions and
109
+ * bug patterns are surfaced directly (one each); task/session
110
+ * summaries produce a meta-pattern only if their bodies contain
111
+ * structural keys (`use`, `avoid`, `pattern:`).
112
+ * @param {MemoryEntry} entry
113
+ */
114
+ export function distill(entry) {
115
+ const fm = entry?.frontmatter ?? {};
116
+ const body = String(entry?.body ?? "").trim();
117
+ const id = String(entry?.memory_id ?? entry?.id ?? entry?.path ?? entry?.relPath ?? "");
118
+
119
+ // Surface coding convention / bug pattern entries as 1:1 patterns.
120
+ const kindRaw = (fm.kind ?? entry?.kind ?? entry?.type ?? "").toString().toLowerCase();
121
+ if (kindRaw === "coding_convention" || kindRaw === "bug_pattern") {
122
+ return {
123
+ id: `pat_${shorten(id || body.slice(0, 24))}`,
124
+ kind: "pattern",
125
+ summary: firstLine(body) || "(empty)",
126
+ uses: id ? [id] : [],
127
+ evidence: [snippet(body)],
128
+ };
129
+ }
130
+
131
+ // task_summary / session_summary → look for an embedded pattern
132
+ // tag in the body ("use", "avoid", "pattern:").
133
+ const head = firstLine(body).toLowerCase();
134
+ if (
135
+ kindRaw === "task_summary" ||
136
+ kindRaw === "session_summary" ||
137
+ /\bpattern\s*:/.test(head) ||
138
+ /^\s*(use|avoid|do|don't)\s*:/.test(head)
139
+ ) {
140
+ return {
141
+ id: `pat_${shorten(id || head.replace(/\W+/g, " ").slice(0, 24))}`,
142
+ kind: "pattern",
143
+ summary: firstLine(body) || "(empty)",
144
+ uses: id ? [id] : [],
145
+ evidence: [snippet(body)],
146
+ };
147
+ }
148
+
149
+ return null;
150
+ }
151
+
152
+ /**
153
+ * CONSOLIDATE — given candidate `Pattern` objects, dedupe by
154
+ * substring overlap, count `uses`, set `provenance_tier` (max tier
155
+ * across the cluster) and `promoted` (only if any contributing entry
156
+ * is oracle or judge).
157
+ * @param {Array<Pattern & { _tier: string }>} candidates
158
+ * @returns {{ patterns: Pattern[], promoted: Pattern[], byTier: Record<string, number> }}
159
+ */
160
+ export function consolidate(candidates) {
161
+ // Group near-duplicates by Jaccard-like word-set similarity.
162
+ const groups = [];
163
+ for (const c of candidates) {
164
+ const ws = wordSet(c.summary + " " + c.evidence.join(" "));
165
+ let placed = false;
166
+ for (const g of groups) {
167
+ const gs = wordSet(g.rep.summary + " " + g.rep.evidence.join(" "));
168
+ const sim = jaccard(ws, gs);
169
+ if (sim >= 0.5) {
170
+ g.members.push(c);
171
+ placed = true;
172
+ break;
173
+ }
174
+ }
175
+ if (!placed) groups.push({ rep: c, members: [c] });
176
+ }
177
+
178
+ const patterns = [];
179
+ const byTier = { "oracle:test-exec": 0, "proxy:structural": 0, "judge:fable": 0 };
180
+ for (const g of groups) {
181
+ const allUses = new Set();
182
+ const evidence = [];
183
+ for (const m of g.members) {
184
+ for (const u of m.uses ?? []) allUses.add(u);
185
+ for (const e of m.evidence ?? []) evidence.push(e);
186
+ }
187
+ // Promote-tier max: oracle > judge > proxy.
188
+ const tiers = g.members.map((m) => m._tier);
189
+ let tier = "proxy:structural";
190
+ if (tiers.includes("oracle:test-exec")) tier = "oracle:test-exec";
191
+ else if (tiers.includes("judge:fable")) tier = "judge:fable";
192
+
193
+ const promoted = usesAllows(allUses.size) && (tier === "oracle:test-exec" || tier === "judge:fable");
194
+ const score = 0.5 + (allUses.size * 0.1);
195
+ const pattern = {
196
+ id: g.rep.id,
197
+ kind: "pattern",
198
+ summary: g.rep.summary,
199
+ uses: Array.from(allUses),
200
+ evidence: dedupe(evidence).slice(0, 5),
201
+ provenance_tier: tier,
202
+ promoted,
203
+ score,
204
+ };
205
+ patterns.push(pattern);
206
+ byTier[tier] += 1;
207
+ }
208
+
209
+ const promoted = patterns.filter((p) => p.promoted);
210
+ return { patterns, promoted, byTier };
211
+ }
212
+
213
+ /**
214
+ * Public entry point. Takes an array of memory entries, applies the
215
+ * 4 stages and returns the consolidated pattern set + tier counts.
216
+ * @param {MemoryEntry[]} entries
217
+ */
218
+ export function runDistillation(entries) {
219
+ if (!Array.isArray(entries) || entries.length === 0) {
220
+ return {
221
+ patterns: [],
222
+ promoted: [],
223
+ byTier: { "oracle:test-exec": 0, "proxy:structural": 0, "judge:fable": 0 },
224
+ };
225
+ }
226
+
227
+ const candidates = [];
228
+ for (const entry of entries) {
229
+ const retrieval = retrieve(entry);
230
+ const tier = judge(entry, retrieval);
231
+ const pattern = distill(entry);
232
+ if (!pattern) continue;
233
+ candidates.push({ ...pattern, _tier: tier });
234
+ }
235
+
236
+ return consolidate(candidates);
237
+ }
238
+
239
+ // -----------------------------------------------------------------
240
+ // Tiny helpers (private).
241
+ // -----------------------------------------------------------------
242
+
243
+ function firstLine(s) {
244
+ if (!s) return "";
245
+ const i = s.indexOf("\n");
246
+ return (i < 0 ? s : s.slice(0, i)).trim();
247
+ }
248
+
249
+ function snippet(body) {
250
+ const cleaned = body.replace(/\s+/g, " ").trim();
251
+ return cleaned.length <= 200 ? cleaned : cleaned.slice(0, 200) + "…";
252
+ }
253
+
254
+ function shorten(s) {
255
+ // Stable, short id-hash from arbitrary text.
256
+ let h = 5381 >>> 0;
257
+ for (let i = 0; i < s.length; i++) {
258
+ h = ((h << 5) + h + s.charCodeAt(i)) >>> 0;
259
+ }
260
+ return h.toString(36).slice(0, 10);
261
+ }
262
+
263
+ function wordSet(s) {
264
+ return new Set(
265
+ String(s)
266
+ .toLowerCase()
267
+ .replace(/[^a-z0-9\s]+/g, " ")
268
+ .split(/\s+/)
269
+ .filter((w) => w.length > 2),
270
+ );
271
+ }
272
+
273
+ function jaccard(a, b) {
274
+ if (a.size === 0 && b.size === 0) return 0;
275
+ let inter = 0;
276
+ for (const x of a) if (b.has(x)) inter += 1;
277
+ const union = a.size + b.size - inter;
278
+ return union === 0 ? 0 : inter / union;
279
+ }
280
+
281
+ function usesAllows(n) {
282
+ // ADR-174 promote gate default: requires N≥1 contributing entry.
283
+ // We tighten to N≥3 in consolidate-callers if they want the
284
+ // 'agenticow substrate' default (ADR-170). Here we keep the
285
+ // public function permissive; callers can filter.
286
+ return n >= 1;
287
+ }
288
+
289
+ function dedupe(arr) {
290
+ const seen = new Set();
291
+ const out = [];
292
+ for (const x of arr) {
293
+ if (!seen.has(x)) { seen.add(x); out.push(x); }
294
+ }
295
+ return out;
296
+ }