@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.
- package/.claude/hooks/sessionend-recall.mjs +3 -3
- package/.claude/hooks/worker-suggest.mjs +110 -0
- package/.claude/settings.json +9 -0
- package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js → EnvVarsSection-CW6fWKds.js} +3 -3
- package/bizar-dash/dist/assets/{EnvVarsSection-B58aiJiE.js.map → EnvVarsSection-CW6fWKds.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileChat-D7zRhU9K.js +1 -0
- package/bizar-dash/dist/assets/{MobileChat-BJrqwVDd.js.map → MobileChat-D7zRhU9K.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +1 -0
- package/bizar-dash/dist/assets/{MobileSettings-CEQNJNLJ.js.map → MobileSettings-K-sNsn_r.js.map} +1 -1
- package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js → Toast-WTxc3m2g.js} +1 -1
- package/bizar-dash/dist/assets/{Toast-Cpl6-E63.js.map → Toast-WTxc3m2g.js.map} +1 -1
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js +1 -0
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -0
- package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js +1 -0
- package/bizar-dash/dist/assets/fuzzy-l0sNRNKZ.js.map +1 -0
- package/bizar-dash/dist/assets/{icons-Do5N2jmX.js → icons-B0AKnYI3.js} +98 -103
- package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -0
- package/bizar-dash/dist/assets/main-C-Md3DaY.css +1 -0
- package/bizar-dash/dist/assets/main-CO8fIxQK.js +18 -0
- package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +1 -0
- package/bizar-dash/dist/assets/markdown-w2bDDkAH.js +1 -0
- package/bizar-dash/dist/assets/{markdown-tOLaD6nm.js.map → markdown-w2bDDkAH.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-DXYCA0hC.js +1 -0
- package/bizar-dash/dist/assets/{mobile-DYCHcUpq.js.map → mobile-DXYCA0hC.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js +2 -0
- package/bizar-dash/dist/assets/mobile-layout-DSmtNPja.js.map +1 -0
- package/bizar-dash/dist/assets/react-vendor-BnuhLJ6X.css +1 -0
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js +46 -0
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -0
- package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js +2 -0
- package/bizar-dash/dist/assets/useSlashCommands-3DFLOfpk.js.map +1 -0
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js +45 -0
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -0
- package/bizar-dash/dist/index.html +12 -10
- package/bizar-dash/dist/mobile.html +7 -4
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +11 -0
- package/bizar-dash/src/server/memory-consolidator.mjs +218 -0
- package/bizar-dash/src/server/memory-distillation.mjs +296 -0
- package/bizar-dash/src/server/routes/distill.mjs +129 -0
- package/bizar-dash/src/server/routes/goal-planner.mjs +236 -0
- package/bizar-dash/src/web/App.tsx +4 -0
- package/bizar-dash/src/web/components/Tag.tsx +18 -5
- package/bizar-dash/src/web/components/Topbar.tsx +3 -0
- package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +126 -0
- package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +163 -0
- package/bizar-dash/src/web/components/agents/QualityGates.tsx +123 -0
- package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +127 -0
- package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +148 -0
- package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +160 -0
- package/bizar-dash/src/web/components/goals/GoalInput.tsx +86 -0
- package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +111 -0
- package/bizar-dash/src/web/lib/goapPlanner.ts +614 -0
- package/bizar-dash/src/web/lib/types.ts +25 -0
- package/bizar-dash/src/web/styles/agents-redesign.css +311 -0
- package/bizar-dash/src/web/styles/main.css +251 -0
- package/bizar-dash/src/web/styles/tasks-redesign.css +231 -0
- package/bizar-dash/src/web/ui/controls/Button.tsx +77 -0
- package/bizar-dash/src/web/ui/controls/Checkbox.tsx +95 -0
- package/bizar-dash/src/web/ui/controls/IconButton.tsx +66 -0
- package/bizar-dash/src/web/ui/controls/Kbd.tsx +24 -0
- package/bizar-dash/src/web/ui/controls/NumberInput.tsx +77 -0
- package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +109 -0
- package/bizar-dash/src/web/ui/controls/SearchInput.tsx +91 -0
- package/bizar-dash/src/web/ui/controls/Select.tsx +92 -0
- package/bizar-dash/src/web/ui/controls/Slider.tsx +70 -0
- package/bizar-dash/src/web/ui/controls/TextInput.tsx +67 -0
- package/bizar-dash/src/web/ui/controls/Toggle.tsx +79 -0
- package/bizar-dash/src/web/ui/controls/controls.css +454 -0
- package/bizar-dash/src/web/ui/controls/index.ts +33 -0
- package/bizar-dash/src/web/ui/data/BarChart.tsx +60 -0
- package/bizar-dash/src/web/ui/data/DataTable.tsx +216 -0
- package/bizar-dash/src/web/ui/data/EmptyState.tsx +60 -0
- package/bizar-dash/src/web/ui/data/ErrorState.tsx +56 -0
- package/bizar-dash/src/web/ui/data/KeyValueList.tsx +106 -0
- package/bizar-dash/src/web/ui/data/LoadingState.tsx +65 -0
- package/bizar-dash/src/web/ui/data/Sparkline.tsx +87 -0
- package/bizar-dash/src/web/ui/data/StatTile.tsx +87 -0
- package/bizar-dash/src/web/ui/data/data.css +535 -0
- package/bizar-dash/src/web/ui/data/index.ts +31 -0
- package/bizar-dash/src/web/ui/feedback/Badge.tsx +49 -0
- package/bizar-dash/src/web/ui/feedback/Dialog.tsx +209 -0
- package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +69 -0
- package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +50 -0
- package/bizar-dash/src/web/ui/feedback/Toast.tsx +200 -0
- package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +126 -0
- package/bizar-dash/src/web/ui/feedback/feedback.css +314 -0
- package/bizar-dash/src/web/ui/feedback/index.ts +43 -0
- package/bizar-dash/src/web/ui/index.ts +56 -0
- package/bizar-dash/src/web/ui/layout/AppShell.tsx +51 -0
- package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +97 -0
- package/bizar-dash/src/web/ui/layout/Panel.tsx +73 -0
- package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +39 -0
- package/bizar-dash/src/web/ui/layout/Sidebar.tsx +131 -0
- package/bizar-dash/src/web/ui/layout/Tabs.tsx +133 -0
- package/bizar-dash/src/web/ui/layout/Topbar.tsx +42 -0
- package/bizar-dash/src/web/ui/layout/index.ts +33 -0
- package/bizar-dash/src/web/ui/layout/layout.css +413 -0
- package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +199 -0
- package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +95 -0
- package/bizar-dash/src/web/ui/navigation/NavLink.tsx +93 -0
- package/bizar-dash/src/web/ui/navigation/index.ts +17 -0
- package/bizar-dash/src/web/ui/navigation/navigation.css +343 -0
- package/bizar-dash/src/web/ui/primitives/Box.tsx +91 -0
- package/bizar-dash/src/web/ui/primitives/Grid.tsx +49 -0
- package/bizar-dash/src/web/ui/primitives/Inline.tsx +55 -0
- package/bizar-dash/src/web/ui/primitives/Separator.tsx +46 -0
- package/bizar-dash/src/web/ui/primitives/Stack.tsx +54 -0
- package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +26 -0
- package/bizar-dash/src/web/ui/primitives/index.ts +23 -0
- package/bizar-dash/src/web/ui/primitives/primitives.css +183 -0
- package/bizar-dash/src/web/ui/styles/globals.css +86 -0
- package/bizar-dash/src/web/ui/styles/reset.css +125 -0
- package/bizar-dash/src/web/ui/styles/tokens.css +195 -0
- package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +142 -0
- package/bizar-dash/src/web/ui/theme/tokens.ts +131 -0
- package/bizar-dash/src/web/ui/theme/useTheme.ts +22 -0
- package/bizar-dash/src/web/ui/utils/cx.ts +42 -0
- package/bizar-dash/src/web/views/Agents.tsx +506 -266
- package/bizar-dash/src/web/views/GoalPlanner.tsx +158 -0
- package/bizar-dash/src/web/views/Overview.tsx +996 -448
- package/bizar-dash/src/web/views/Tasks.tsx +277 -273
- package/bizar-dash/tests/communication-log.test.tsx +67 -0
- package/bizar-dash/tests/dep-graph.test.tsx +40 -0
- package/bizar-dash/tests/event-log.test.tsx +61 -0
- package/bizar-dash/tests/goal-input.test.tsx +72 -0
- package/bizar-dash/tests/goap-planner.test.ts +68 -0
- package/bizar-dash/tests/quality-gates.test.tsx +59 -0
- package/bizar-dash/tests/setup.ts +31 -1
- package/bizar-dash/tests/ui/controls/Button.test.tsx +50 -0
- package/bizar-dash/tests/ui/controls/Checkbox.test.tsx +44 -0
- package/bizar-dash/tests/ui/controls/IconButton.test.tsx +37 -0
- package/bizar-dash/tests/ui/controls/Kbd.test.tsx +39 -0
- package/bizar-dash/tests/ui/controls/NumberInput.test.tsx +56 -0
- package/bizar-dash/tests/ui/controls/RadioGroup.test.tsx +58 -0
- package/bizar-dash/tests/ui/controls/SearchInput.test.tsx +52 -0
- package/bizar-dash/tests/ui/controls/Select.test.tsx +66 -0
- package/bizar-dash/tests/ui/controls/Slider.test.tsx +41 -0
- package/bizar-dash/tests/ui/controls/TextInput.test.tsx +44 -0
- package/bizar-dash/tests/ui/controls/Toggle.test.tsx +39 -0
- package/bizar-dash/tests/ui/data/BarChart.test.tsx +55 -0
- package/bizar-dash/tests/ui/data/DataTable.test.tsx +112 -0
- package/bizar-dash/tests/ui/data/EmptyState.test.tsx +57 -0
- package/bizar-dash/tests/ui/data/ErrorState.test.tsx +47 -0
- package/bizar-dash/tests/ui/data/KeyValueList.test.tsx +59 -0
- package/bizar-dash/tests/ui/data/LoadingState.test.tsx +37 -0
- package/bizar-dash/tests/ui/data/Sparkline.test.tsx +56 -0
- package/bizar-dash/tests/ui/data/StatTile.test.tsx +69 -0
- package/bizar-dash/tests/ui/feedback/Badge.test.tsx +41 -0
- package/bizar-dash/tests/ui/feedback/Dialog.test.tsx +99 -0
- package/bizar-dash/tests/ui/feedback/ProgressBar.test.tsx +66 -0
- package/bizar-dash/tests/ui/feedback/StatusDot.test.tsx +41 -0
- package/bizar-dash/tests/ui/feedback/Toast.test.tsx +124 -0
- package/bizar-dash/tests/ui/feedback/Tooltip.test.tsx +102 -0
- package/bizar-dash/tests/ui/layout/AppShell.test.tsx +50 -0
- package/bizar-dash/tests/ui/layout/Breadcrumbs.test.tsx +85 -0
- package/bizar-dash/tests/ui/layout/Panel.test.tsx +52 -0
- package/bizar-dash/tests/ui/layout/PanelHeader.test.tsx +32 -0
- package/bizar-dash/tests/ui/layout/Sidebar.test.tsx +95 -0
- package/bizar-dash/tests/ui/layout/Tabs.test.tsx +87 -0
- package/bizar-dash/tests/ui/layout/Topbar.test.tsx +41 -0
- package/bizar-dash/tests/ui/navigation/CommandPalette.test.tsx +105 -0
- package/bizar-dash/tests/ui/navigation/NavGroup.test.tsx +55 -0
- package/bizar-dash/tests/ui/navigation/NavLink.test.tsx +61 -0
- package/bizar-dash/tests/ui/primitives/Box.test.tsx +49 -0
- package/bizar-dash/tests/ui/primitives/Grid.test.tsx +37 -0
- package/bizar-dash/tests/ui/primitives/Inline.test.tsx +33 -0
- package/bizar-dash/tests/ui/primitives/Separator.test.tsx +34 -0
- package/bizar-dash/tests/ui/primitives/Stack.test.tsx +45 -0
- package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +27 -0
- package/bizar-dash/tests/views/Agents.test.tsx +359 -0
- package/bizar-dash/tests/views/Overview.test.tsx +413 -0
- package/bizar-dash/tests/views/Tasks.test.tsx +250 -0
- package/bizar-dash/vitest.config.ts +3 -1
- package/cli/__tests__/cost-gate.test.mjs +301 -0
- package/cli/__tests__/feature-list-bridge.test.mjs +371 -0
- package/cli/bin.mjs +38 -0
- package/cli/commands/claim.mjs +282 -0
- package/cli/commands/cost.mjs +279 -0
- package/cli/cost-gate.mjs +501 -0
- package/cli/feature-list-bridge.mjs +400 -0
- package/cli/memory-constants.mjs +17 -0
- package/cli/worker-dispatcher.mjs +259 -0
- package/cli/worker-dispatcher.test.mjs +204 -0
- package/config/trigger-patterns.json +186 -0
- package/package.json +2 -2
- package/packages/sdk/package.json +1 -1
- package/packages/sdk/src/agent-registry.ts +304 -0
- package/packages/sdk/src/consensus/byzantine.ts +587 -0
- package/packages/sdk/src/consensus/index.ts +147 -0
- package/packages/sdk/src/consensus/queen.ts +173 -0
- package/packages/sdk/src/consensus/types.ts +199 -0
- package/packages/sdk/src/federation/audit.ts +156 -0
- package/packages/sdk/src/federation/budget.ts +269 -0
- package/packages/sdk/src/federation/envelope.ts +144 -0
- package/packages/sdk/src/federation/hmac.ts +160 -0
- package/packages/sdk/src/federation/index.ts +443 -0
- package/packages/sdk/src/federation/pii.ts +241 -0
- package/packages/sdk/src/federation/policy.ts +112 -0
- package/packages/sdk/src/federation/trust.ts +146 -0
- package/packages/sdk/src/index.ts +67 -0
- package/packages/sdk/src/mcp/server.ts +351 -1
- package/packages/sdk/src/router/codemod-intent.ts +125 -0
- package/packages/sdk/src/router/index.ts +247 -0
- package/packages/sdk/src/router/memory-distillation-shim.mjs +18 -0
- package/packages/sdk/src/router/memory-distillation.ts +249 -0
- package/packages/sdk/src/router/model-router.ts +235 -0
- package/packages/sdk/src/router/q-learning-router.ts +304 -0
- package/packages/sdk/src/swarm-topology.ts +279 -0
- package/packages/sdk/tests/agent-registry.test.ts +285 -0
- package/packages/sdk/tests/consensus.test.ts +376 -0
- package/packages/sdk/tests/federation/audit.test.ts +164 -0
- package/packages/sdk/tests/federation/budget.test.ts +189 -0
- package/packages/sdk/tests/federation/envelope.test.ts +120 -0
- package/packages/sdk/tests/federation/hmac.test.ts +194 -0
- package/packages/sdk/tests/federation/orchestrator.test.ts +176 -0
- package/packages/sdk/tests/federation/pii.test.ts +106 -0
- package/packages/sdk/tests/federation/policy.test.ts +140 -0
- package/packages/sdk/tests/federation/trust.test.ts +124 -0
- package/packages/sdk/tests/mcp-tools.test.ts +204 -0
- package/packages/sdk/tests/memory-distillation.test.mjs +186 -0
- package/packages/sdk/tests/model-router.test.mjs +108 -0
- package/packages/sdk/tests/q-learning-router.test.mjs +100 -0
- package/packages/sdk/tests/router-orchestrator.test.mjs +172 -0
- package/packages/sdk/tests/router.test.mjs +91 -0
- package/packages/sdk/tests/sdk.test.mjs +26 -2
- package/packages/sdk/tests/swarm-topology.test.ts +258 -0
- package/scripts/bh-full-e2e.mjs +11 -15
- package/bizar-dash/dist/assets/MobileChat-BJrqwVDd.js +0 -1
- package/bizar-dash/dist/assets/MobileSettings-CEQNJNLJ.js +0 -1
- package/bizar-dash/dist/assets/icons-Do5N2jmX.js.map +0 -1
- package/bizar-dash/dist/assets/main-IvfQAOfy.js +0 -18
- package/bizar-dash/dist/assets/main-IvfQAOfy.js.map +0 -1
- package/bizar-dash/dist/assets/main-ietCEg_R.css +0 -1
- package/bizar-dash/dist/assets/markdown-tOLaD6nm.js +0 -1
- package/bizar-dash/dist/assets/mobile-DYCHcUpq.js +0 -1
- package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js +0 -2
- package/bizar-dash/dist/assets/mobile-layout-CBHjpwsb.js.map +0 -1
- package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js +0 -40
- package/bizar-dash/dist/assets/react-vendor-Dn4wqh4Z.js.map +0 -1
- package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js +0 -2
- package/bizar-dash/dist/assets/useSlashCommands-Bd7_FA6U.js.map +0 -1
- package/bizar-dash/dist/assets/vendor-C843201K.js +0 -29
- package/bizar-dash/dist/assets/vendor-C843201K.js.map +0 -1
- 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-
|
|
33
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
34
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
35
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
36
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
37
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
38
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
39
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
40
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
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/
|
|
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-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
17
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
18
|
-
<link rel="modulepreload" crossorigin href="/assets/
|
|
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>
|
package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"4.1.10","results":[[":tests/
|
|
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
|
+
}
|