@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
|
@@ -31,6 +31,11 @@ describe("SDK build", () => {
|
|
|
31
31
|
"memory/index.js", "memory/index.d.ts",
|
|
32
32
|
"mcp/server.js", "mcp/server.d.ts",
|
|
33
33
|
"mcp/bin.js", "mcp/bin.d.ts",
|
|
34
|
+
// v6.4.0 — F-033 Self-Learning (codemod + bandit + distillation).
|
|
35
|
+
"router/codemod-intent.js", "router/codemod-intent.d.ts",
|
|
36
|
+
"router/model-router.js", "router/model-router.d.ts",
|
|
37
|
+
"router/q-learning-router.js", "router/q-learning-router.d.ts",
|
|
38
|
+
"router/memory-distillation.js", "router/memory-distillation.d.ts",
|
|
34
39
|
]) {
|
|
35
40
|
expect(existsSync(join(distDir, f))).toBe(true);
|
|
36
41
|
}
|
|
@@ -71,10 +76,10 @@ describe("SDK module surface", () => {
|
|
|
71
76
|
expect(typeof mod.DEFAULT_MEMORY_VAULT).toBe("string");
|
|
72
77
|
});
|
|
73
78
|
|
|
74
|
-
test("MCP server module exposes ≥13
|
|
79
|
+
test("MCP server module exposes ≥20 BIZAR_TOOLS (13 core + 4 swarm + 3 self-learning)", async () => {
|
|
75
80
|
const mod = await import("../dist/mcp/server.js");
|
|
76
81
|
expect(Array.isArray(mod.BIZAR_TOOLS)).toBe(true);
|
|
77
|
-
expect(mod.BIZAR_TOOLS.length).toBeGreaterThanOrEqual(
|
|
82
|
+
expect(mod.BIZAR_TOOLS.length).toBeGreaterThanOrEqual(20);
|
|
78
83
|
expect(typeof mod.createBizarMcpServer).toBe("function");
|
|
79
84
|
expect(typeof mod.createBizarMcpServerConfig).toBe("function");
|
|
80
85
|
expect(typeof mod.defineTool).toBe("function");
|
|
@@ -85,12 +90,31 @@ describe("SDK module surface", () => {
|
|
|
85
90
|
"plan_action", "open_kb",
|
|
86
91
|
"loop_list", "loop_status", "loop_start", "loop_stop",
|
|
87
92
|
"graph_query", "graph_path", "danger_check",
|
|
93
|
+
// F-032 — Swarm coordination.
|
|
94
|
+
"agent_spawn", "agent_list", "agent_terminate", "swarm_init",
|
|
95
|
+
// F-033 — Self-learning.
|
|
96
|
+
"model_route", "agent_route", "memory_distill",
|
|
88
97
|
]);
|
|
89
98
|
const have = new Set(mod.BIZAR_TOOLS.map((t) => t.name));
|
|
90
99
|
for (const n of expectedNames) {
|
|
91
100
|
expect(have.has(n)).toBe(true);
|
|
92
101
|
}
|
|
93
102
|
});
|
|
103
|
+
|
|
104
|
+
test("F-033 router modules export the expected API", async () => {
|
|
105
|
+
const cm = await import("../dist/router/codemod-intent.js");
|
|
106
|
+
expect(typeof cm.detectCodemodIntent).toBe("function");
|
|
107
|
+
|
|
108
|
+
const mr = await import("../dist/router/model-router.js");
|
|
109
|
+
expect(typeof mr.ModelRouter).toBe("function");
|
|
110
|
+
|
|
111
|
+
const ql = await import("../dist/router/q-learning-router.js");
|
|
112
|
+
expect(typeof ql.QLearningRouter).toBe("function");
|
|
113
|
+
expect(Array.isArray(ql.AGENT_ACTIONS)).toBe(true);
|
|
114
|
+
|
|
115
|
+
const ds = await import("../dist/router/memory-distillation.js");
|
|
116
|
+
expect(typeof ds.runDistillation).toBe("function");
|
|
117
|
+
});
|
|
94
118
|
});
|
|
95
119
|
|
|
96
120
|
describe("dangerous-patterns behaviour", () => {
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* swarm-topology.test.ts — unit tests for the swarm topology registry.
|
|
3
|
+
*
|
|
4
|
+
* F-032 — covers initSwarm, maxAgents clamping, topology enum, the
|
|
5
|
+
* lazy default swarm, recordAgentInSwarm, decommissionSwarm, and
|
|
6
|
+
* optional JSON persistence.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
10
|
+
import { mkdtempSync, rmSync, existsSync, readFileSync } from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import {
|
|
14
|
+
SwarmTopologyRegistry,
|
|
15
|
+
swarmTopologyRegistry,
|
|
16
|
+
initSwarm,
|
|
17
|
+
getSwarm,
|
|
18
|
+
listSwarms,
|
|
19
|
+
recordAgentInSwarm,
|
|
20
|
+
decommissionSwarm,
|
|
21
|
+
SWARM_TOPOLOGIES,
|
|
22
|
+
DEFAULT_TOPOLOGY,
|
|
23
|
+
DEFAULT_MAX_AGENTS,
|
|
24
|
+
DEFAULT_SWARM_ID,
|
|
25
|
+
type SwarmTopology,
|
|
26
|
+
} from "../src/swarm-topology.js";
|
|
27
|
+
|
|
28
|
+
describe("SwarmTopologyRegistry — class API", () => {
|
|
29
|
+
let reg: SwarmTopologyRegistry;
|
|
30
|
+
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
reg = new SwarmTopologyRegistry();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("initSwarm creates a swarm with defaults when no args", () => {
|
|
36
|
+
const r = reg.initSwarm();
|
|
37
|
+
expect(r.topology).toBe(DEFAULT_TOPOLOGY);
|
|
38
|
+
expect(r.maxAgents).toBe(DEFAULT_MAX_AGENTS);
|
|
39
|
+
expect(r.swarmId).toMatch(/^swarm-\d+$/);
|
|
40
|
+
expect(typeof r.createdAt).toBe("string");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("initSwarm accepts a custom swarmId", () => {
|
|
44
|
+
const r = reg.initSwarm({ swarmId: "alpha" });
|
|
45
|
+
expect(r.swarmId).toBe("alpha");
|
|
46
|
+
expect(reg.getSwarm("alpha")).toBeDefined();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("initSwarm rejects duplicate swarmId", () => {
|
|
50
|
+
reg.initSwarm({ swarmId: "dup" });
|
|
51
|
+
expect(() => reg.initSwarm({ swarmId: "dup" })).toThrow(/already exists/);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("topology enum is enforced — falls back to default for unknown", () => {
|
|
55
|
+
const r = reg.initSwarm({ topology: "unknown" as unknown as SwarmTopology });
|
|
56
|
+
expect(r.topology).toBe(DEFAULT_TOPOLOGY);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("each valid topology is accepted", () => {
|
|
60
|
+
for (const topo of SWARM_TOPOLOGIES) {
|
|
61
|
+
const r = reg.initSwarm({ topology: topo });
|
|
62
|
+
expect(r.topology).toBe(topo);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("maxAgents is clamped to [1, 1000]", () => {
|
|
67
|
+
const lo = reg.initSwarm({ maxAgents: -5 });
|
|
68
|
+
expect(lo.maxAgents).toBe(1);
|
|
69
|
+
const hi = reg.initSwarm({ maxAgents: 9999 });
|
|
70
|
+
expect(hi.maxAgents).toBe(1000);
|
|
71
|
+
const mid = reg.initSwarm({ maxAgents: 50 });
|
|
72
|
+
expect(mid.maxAgents).toBe(50);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("maxAgents defaults to 15", () => {
|
|
76
|
+
const r = reg.initSwarm();
|
|
77
|
+
expect(r.maxAgents).toBe(15);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("non-numeric maxAgents falls back to default", () => {
|
|
81
|
+
const r = reg.initSwarm({ maxAgents: NaN });
|
|
82
|
+
expect(r.maxAgents).toBe(15);
|
|
83
|
+
const r2 = reg.initSwarm({ maxAgents: "50" as unknown as number });
|
|
84
|
+
expect(r2.maxAgents).toBe(15);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("metadata is round-tripped", () => {
|
|
88
|
+
const r = reg.initSwarm({ metadata: { owner: "F-032", region: "us" } });
|
|
89
|
+
expect(reg.getSwarm(r.swarmId)?.metadata).toEqual({ owner: "F-032", region: "us" });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("the 'default' swarm is seeded lazily on first initSwarm call", () => {
|
|
93
|
+
expect(reg.getSwarm(DEFAULT_SWARM_ID)).toBeUndefined();
|
|
94
|
+
reg.initSwarm({ swarmId: "after" });
|
|
95
|
+
const def = reg.getSwarm(DEFAULT_SWARM_ID);
|
|
96
|
+
expect(def).toBeDefined();
|
|
97
|
+
expect(def?.topology).toBe(DEFAULT_TOPOLOGY);
|
|
98
|
+
expect(def?.maxAgents).toBe(DEFAULT_MAX_AGENTS);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("listSwarms includes the default swarm after first initSwarm", () => {
|
|
102
|
+
reg.initSwarm({ swarmId: "x" });
|
|
103
|
+
const all = reg.listSwarms();
|
|
104
|
+
expect(all.map((s) => s.swarmId).sort()).toEqual([DEFAULT_SWARM_ID, "x"].sort());
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("getSwarm on missing id returns undefined", () => {
|
|
108
|
+
expect(reg.getSwarm("nope")).toBeUndefined();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("recordAgentInSwarm appends agentIds and dedupes", () => {
|
|
112
|
+
const r = reg.initSwarm({ swarmId: "team", maxAgents: 3 });
|
|
113
|
+
recordAgentInSwarmOn(reg, "team", "a1");
|
|
114
|
+
recordAgentInSwarmOn(reg, "team", "a2");
|
|
115
|
+
recordAgentInSwarmOn(reg, "team", "a1"); // dedupe
|
|
116
|
+
const swarm = reg.getSwarm("team");
|
|
117
|
+
expect(swarm?.agentIds).toEqual(["a1", "a2"]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("recordAgentInSwarm refuses beyond maxAgents", () => {
|
|
121
|
+
const r = reg.initSwarm({ swarmId: "small", maxAgents: 2 });
|
|
122
|
+
recordAgentInSwarmOn(reg, "small", "a1");
|
|
123
|
+
recordAgentInSwarmOn(reg, "small", "a2");
|
|
124
|
+
expect(() => recordAgentInSwarmOn(reg, "small", "a3")).toThrow(/maxAgents/);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("recordAgentInSwarm throws on missing swarm", () => {
|
|
128
|
+
expect(() => recordAgentInSwarmOn(reg, "ghost", "a1")).toThrow(/not found/);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("decommissionSwarm marks the swarm and refuses further recordAgentInSwarm", () => {
|
|
132
|
+
reg.initSwarm({ swarmId: "doomed" });
|
|
133
|
+
reg.decommissionSwarm("doomed");
|
|
134
|
+
expect(reg.getSwarm("doomed")?.decommissionedAt).toBeDefined();
|
|
135
|
+
expect(() => recordAgentInSwarmOn(reg, "doomed", "a1")).toThrow(/decommissioned/);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("decommissionSwarm refuses the default swarm", () => {
|
|
139
|
+
reg.initSwarm({ swarmId: "trigger" });
|
|
140
|
+
expect(() => reg.decommissionSwarm(DEFAULT_SWARM_ID)).toThrow(/default/);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("decommissionSwarm throws on missing swarm", () => {
|
|
144
|
+
expect(() => reg.decommissionSwarm("ghost")).toThrow(/not found/);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("reset() drops everything including the lazy default seed flag", () => {
|
|
148
|
+
reg.initSwarm({ swarmId: "x" });
|
|
149
|
+
expect(reg.listSwarms().length).toBeGreaterThan(0);
|
|
150
|
+
reg.reset();
|
|
151
|
+
expect(reg.listSwarms().length).toBe(0);
|
|
152
|
+
expect(reg.getSwarm(DEFAULT_SWARM_ID)).toBeUndefined();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Helper — bypass module-level helper to operate on a per-test registry.
|
|
157
|
+
function recordAgentInSwarmOn(
|
|
158
|
+
reg: SwarmTopologyRegistry,
|
|
159
|
+
swarmId: string,
|
|
160
|
+
agentId: string,
|
|
161
|
+
) {
|
|
162
|
+
return reg.recordAgentInSwarm(swarmId, agentId);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
describe("SwarmTopologyRegistry — module-level helpers", () => {
|
|
166
|
+
test("initSwarm helper shares state with swarmTopologyRegistry", () => {
|
|
167
|
+
const r = initSwarm({ swarmId: "shared" });
|
|
168
|
+
expect(swarmTopologyRegistry.getSwarm(r.swarmId)).toBeDefined();
|
|
169
|
+
expect(getSwarm(r.swarmId)?.swarmId).toBe("shared");
|
|
170
|
+
expect(listSwarms().some((s) => s.swarmId === "shared")).toBe(true);
|
|
171
|
+
// cleanup
|
|
172
|
+
swarmTopologyRegistry.decommissionSwarm("shared");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("recordAgentInSwarm helper reflects in swarmTopologyRegistry", () => {
|
|
176
|
+
const r = initSwarm({ swarmId: "record-helper" });
|
|
177
|
+
recordAgentInSwarm(r.swarmId, "agent-x");
|
|
178
|
+
expect(swarmTopologyRegistry.getSwarm(r.swarmId)?.agentIds).toContain("agent-x");
|
|
179
|
+
swarmTopologyRegistry.decommissionSwarm(r.swarmId);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("decommissionSwarm helper reflects in swarmTopologyRegistry", () => {
|
|
183
|
+
const r = initSwarm({ swarmId: "decomm-helper" });
|
|
184
|
+
decommissionSwarm(r.swarmId);
|
|
185
|
+
expect(swarmTopologyRegistry.getSwarm(r.swarmId)?.decommissionedAt).toBeDefined();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("SwarmTopologyRegistry — persistence", () => {
|
|
190
|
+
let dir: string;
|
|
191
|
+
let persistPath: string;
|
|
192
|
+
|
|
193
|
+
beforeEach(() => {
|
|
194
|
+
dir = mkdtempSync(join(tmpdir(), "swarm-topology-"));
|
|
195
|
+
persistPath = join(dir, "topology.json");
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
afterEach(() => {
|
|
199
|
+
if (existsSync(dir)) rmSync(dir, { recursive: true, force: true });
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("a fresh registry with persistPath starts empty when file is missing", () => {
|
|
203
|
+
const reg = new SwarmTopologyRegistry({ persistPath });
|
|
204
|
+
expect(reg.listSwarms()).toEqual([]);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("initSwarm writes a snapshot to disk after each call", () => {
|
|
208
|
+
const reg = new SwarmTopologyRegistry({ persistPath });
|
|
209
|
+
reg.initSwarm({ swarmId: "alpha", topology: "mesh" });
|
|
210
|
+
expect(existsSync(persistPath)).toBe(true);
|
|
211
|
+
const stored = JSON.parse(readFileSync(persistPath, "utf-8")) as {
|
|
212
|
+
swarms: Array<{ swarmId: string; topology: string }>;
|
|
213
|
+
};
|
|
214
|
+
expect(stored.swarms.some((s) => s.swarmId === "alpha" && s.topology === "mesh")).toBe(true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("a new registry reading the same path picks up persisted swarms", () => {
|
|
218
|
+
const reg1 = new SwarmTopologyRegistry({ persistPath });
|
|
219
|
+
reg1.initSwarm({ swarmId: "persisted", topology: "adaptive", maxAgents: 25 });
|
|
220
|
+
expect(reg1.listSwarms().some((s) => s.swarmId === "persisted")).toBe(true);
|
|
221
|
+
|
|
222
|
+
const reg2 = new SwarmTopologyRegistry({ persistPath });
|
|
223
|
+
const got = reg2.getSwarm("persisted");
|
|
224
|
+
expect(got?.topology).toBe("adaptive");
|
|
225
|
+
expect(got?.maxAgents).toBe(25);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("setPersistPath switches the persistence target at runtime", () => {
|
|
229
|
+
const reg = new SwarmTopologyRegistry();
|
|
230
|
+
reg.setPersistPath(persistPath);
|
|
231
|
+
reg.initSwarm({ swarmId: "first" });
|
|
232
|
+
expect(existsSync(persistPath)).toBe(true);
|
|
233
|
+
|
|
234
|
+
const other = join(dir, "topology-other.json");
|
|
235
|
+
reg.setPersistPath(other);
|
|
236
|
+
reg.initSwarm({ swarmId: "second" });
|
|
237
|
+
expect(existsSync(other)).toBe(true);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test("a corrupt persistence file does not crash the registry", () => {
|
|
241
|
+
require("node:fs").writeFileSync(persistPath, "{not json", "utf-8");
|
|
242
|
+
const reg = new SwarmTopologyRegistry({ persistPath });
|
|
243
|
+
expect(reg.listSwarms()).toEqual([]);
|
|
244
|
+
reg.initSwarm({ swarmId: "recovered" });
|
|
245
|
+
expect(reg.getSwarm("recovered")).toBeDefined();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("decommissionSwarm writes decommissionedAt to the persisted file", () => {
|
|
249
|
+
const reg = new SwarmTopologyRegistry({ persistPath });
|
|
250
|
+
reg.initSwarm({ swarmId: "doomed" });
|
|
251
|
+
reg.decommissionSwarm("doomed");
|
|
252
|
+
const stored = JSON.parse(readFileSync(persistPath, "utf-8")) as {
|
|
253
|
+
swarms: Array<{ swarmId: string; decommissionedAt?: string }>;
|
|
254
|
+
};
|
|
255
|
+
const row = stored.swarms.find((s) => s.swarmId === "doomed");
|
|
256
|
+
expect(row?.decommissionedAt).toBeDefined();
|
|
257
|
+
});
|
|
258
|
+
});
|
package/scripts/bh-full-e2e.mjs
CHANGED
|
@@ -90,22 +90,18 @@ if (!existsSync(MCP_BIN_PATH)) {
|
|
|
90
90
|
// ── 3. MCP server exposes the documented tool surface ──────────────────
|
|
91
91
|
try {
|
|
92
92
|
const serverSrc = readFileSync(join(REPO_ROOT, 'packages', 'sdk', 'src', 'mcp', 'server.ts'), 'utf8');
|
|
93
|
+
// Tool surface updated for v6.4.0 (was: bizar_* prefix + sandbox/glyph/plan_comment tools
|
|
94
|
+
// that were removed in the v6.3.0 migration; F-032 + F-033 added agent/router tools).
|
|
93
95
|
const requiredTools = [
|
|
94
|
-
|
|
95
|
-
'
|
|
96
|
-
'
|
|
97
|
-
'
|
|
98
|
-
'
|
|
99
|
-
|
|
100
|
-
'
|
|
101
|
-
|
|
102
|
-
'
|
|
103
|
-
'bizar_graph_query',
|
|
104
|
-
'bizar_graph_path',
|
|
105
|
-
'bizar_graph_explain',
|
|
106
|
-
'bizar_sandbox_run',
|
|
107
|
-
'bizar_sandbox_exec',
|
|
108
|
-
'bizar_loop_engineering',
|
|
96
|
+
// v6.3.0 core
|
|
97
|
+
'memory_read', 'memory_write', 'memory_list', 'memory_search',
|
|
98
|
+
'plan_action', 'open_kb',
|
|
99
|
+
'loop_list', 'loop_status', 'loop_start', 'loop_stop',
|
|
100
|
+
'graph_query', 'graph_path', 'danger_check',
|
|
101
|
+
// F-032 Swarm Coordination
|
|
102
|
+
'agent_spawn', 'agent_list', 'agent_terminate', 'swarm_init',
|
|
103
|
+
// F-033 Self-Learning
|
|
104
|
+
'model_route', 'agent_route', 'memory_distill', 'hooks_route',
|
|
109
105
|
];
|
|
110
106
|
const missing = requiredTools.filter((t) => !serverSrc.includes(t));
|
|
111
107
|
if (missing.length === 0) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{j as n,r as o}from"./react-vendor-Dn4wqh4Z.js";import{C as O,u as T,a as k,b as R,c as E}from"./useSlashCommands-Bd7_FA6U.js";import{u as F}from"./Toast-Cpl6-E63.js";import"./icons-Do5N2jmX.js";import"./mobile-layout-CBHjpwsb.js";import"./markdown-tOLaD6nm.js";import"./vendor-C843201K.js";function $(t){const{activeSource:i}=t;return n.jsx("div",{className:`chat-composer-wrap chat-composer-source-${i??"none"} legacy`,children:n.jsx("div",{className:"chat-composer-pill",children:n.jsx(O,{...t})})})}function G({snapshot:t,settings:i,setActiveTab:g,initialTaskId:j,onClearTaskId:z}){const c=F(),s=T(t,i,j??"");o.useEffect(()=>{s.setToast({error:e=>c.error(e),success:e=>c.success(e),info:e=>c.info(e),warning:e=>c.warning(e)})},[s,c]);const[r,l]=o.useState(""),[f,x]=o.useState(i.defaultAgent||"odin"),[p,C]=o.useState(i.defaultModel||""),[h,v]=o.useState([]),u=o.useRef(null),{suggestions:y,setQuery:m}=k(t);o.useEffect(()=>{m(r)},[r,m]);const P=()=>{var e;return(e=u.current)==null?void 0:e.click()},w=e=>{const d=e.target.files;if(!d)return;const S=[];for(let a=0;a<d.length;a++)S.push(d[a].name);v(a=>{const M=S.filter(N=>!a.includes(N));return[...a,...M]}),u.current&&(u.current.value="")},I=async()=>{const e=r.trim();if(!e)return;l(""),m(""),(await s.onSend(e,f,p,h)).ok&&s.jumpToLatest()};return n.jsxs("div",{className:"chat-shell",children:[n.jsx(R,{activeProject:t.activeProject,sessionCount:s.sessions.length,sessionsOpen:!1,infoOpen:!1,onToggleSessions:()=>{},onToggleInfo:()=>{},onOpenOverview:()=>g==null?void 0:g("overview")}),n.jsx("div",{className:"chat-body",children:n.jsxs("main",{className:"chat-main",children:[n.jsx(E,{messages:s.activeSource==="cline"?s.clineMessages:s.bizarMessages,loading:s.loading,activeProject:t.activeProject,sessionId:s.activeSource==="cline"?s.activeClineSessionId??s.sessionId:s.sessionId,pinned:s.pinned,activeSource:s.activeSource,onPickSuggestion:e=>l(e),onCopy:e=>s.copyMessage(e),onDelete:()=>{},onTogglePin:s.togglePin,onRegenerate:s.onRegenerate}),n.jsx($,{agent:f,setAgent:x,model:p,setModel:C,text:r,setText:l,sending:s.sending,activeSource:s.activeSource,onSend:I,attachments:h,setAttachments:v,suggestions:y,onPickSuggestion:e=>l(`${e.split(" ")[0]} `),agents:t.agents||[],onAttach:P,sessionsOpen:!1,infoOpen:!1}),n.jsx("input",{ref:u,type:"file",multiple:!0,style:{display:"none"},onChange:w})]})})]})}export{G as MobileChat};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r,j as e}from"./react-vendor-Dn4wqh4Z.js";import{a as y,S as E,c as R}from"./mobile-layout-CBHjpwsb.js";import{C as M,a as U,b as B,B as I,G,E as V,S as P,U as A,H as C,T as $,c as H}from"./EnvVarsSection-B58aiJiE.js";import{u as D}from"./Toast-Cpl6-E63.js";import{j as N,aY as k,aR as T,N as F,aa as K,s as O,aC as W,x as w,R as Y,aF as q,I as J,e as Q}from"./icons-Do5N2jmX.js";function X(){const s=D(),[i,t]=r.useState(!0),[c,a]=r.useState(!1),[o,d]=r.useState(!1),[u,g]=r.useState(""),[p,x]=r.useState(""),[f,h]=r.useState(!1),[j,n]=r.useState(0);r.useEffect(()=>{let l=!1;return(async()=>{var S,L;try{const[z,v]=await Promise.all([y.get("/memory/config/global").catch(()=>null),y.get("/memory/status").catch(()=>null)]);if(l)return;z&&g(((L=(S=z.config)==null?void 0:S.git)==null?void 0:L.remoteUrl)||""),v&&(x(v.vaultRoot||""),h(!!v.initialized))}finally{l||t(!1)}})(),()=>{l=!0}},[j]);const b=async()=>{a(!0);try{await y.put("/memory/config/global",{git:{remoteUrl:u}}),s.success("Memory config saved."),n(l=>l+1)}catch(l){s.error(`Save failed: ${l.message}`)}finally{a(!1)}},m=async()=>{d(!0);try{await y.post("/memory/init",{}),s.success("Vault initialised."),n(l=>l+1)}catch(l){s.error(`Initialise failed: ${l.message}`)}finally{d(!1)}};return e.jsxs(M,{id:"settings-memory","data-section":"memory",children:[e.jsxs(U,{children:[e.jsx(N,{size:14})," Memory vault"]}),e.jsx(B,{children:"The vault lives at a default location on disk. Only the git remote URL needs to be configured to enable sync across machines."}),i?e.jsx("div",{className:"flex-center",style:{padding:24},children:e.jsx(E,{size:"sm"})}):e.jsxs("div",{className:"settings-fields",children:[e.jsxs("div",{className:"field",children:[e.jsxs("label",{className:"field-label",children:[e.jsx(k,{size:12,style:{display:"inline",marginRight:4}}),"Vault path"]}),e.jsxs("div",{className:"field-readonly mono","data-testid":"settings-memory-vault-path",style:{fontSize:12,padding:"6px 0"},children:[p||e.jsx("span",{className:"muted",children:"not initialised"}),f?null:e.jsxs(I,{variant:"ghost",size:"sm",onClick:m,disabled:o,style:{marginLeft:12},children:[o?e.jsx(T,{size:12,className:"memory-spin"}):e.jsx(k,{size:12}),"Initialise"]})]})]}),e.jsxs("div",{className:"field",children:[e.jsxs("label",{className:"field-label",htmlFor:"set-memory-git-remote",children:[e.jsx(F,{size:12,style:{display:"inline",marginRight:4}}),"Git remote URL"]}),e.jsx("input",{id:"set-memory-git-remote",className:"input mono",type:"text",value:u,onChange:l=>g(l.target.value),placeholder:"git@github.com:org/repo.git"}),e.jsx("span",{className:"field-hint",children:"Leave empty to use local-only mode (no git sync)."})]}),e.jsx("div",{style:{marginTop:12},children:e.jsxs(I,{variant:"primary",size:"sm",onClick:b,disabled:c,children:[c?e.jsx(T,{size:12,className:"memory-spin"}):e.jsx(K,{size:12}),"Save memory config"]})})]})]})}function Z({settings:s,onSettingsChange:i,autoSave:t}){const c=(o,d)=>{i==null||i(o,d),t==null||t(o,d)},a=o=>{i==null||i("ui",{...s.ui,...o}),t==null||t("ui",{...s.ui,...o})};return e.jsx(G,{settings:s,patchUi:a,patchTop:c,autoSave:t})}function _({settings:s,onSettingsChange:i,autoSave:t}){return e.jsxs("div",{style:{fontSize:13,color:"var(--text-dim)",padding:"8px 0"},children:[e.jsx("p",{style:{marginBottom:8},children:"Provider management is available on desktop."}),e.jsx("a",{href:"/?desktop=1#settings-providers",className:"mobile-btn mobile-btn-secondary",style:{display:"inline-block",fontSize:12,padding:"6px 12px"},children:"Open desktop to manage providers"})]})}function ee(){return e.jsx(V,{})}function se(){return e.jsx(X,{})}function ie({settings:s,onSettingsChange:i,autoSave:t}){const c=(a,o)=>{i==null||i(a,o),t==null||t(a,o)};return e.jsx(P,{settings:s,patchTop:c})}function te(){return e.jsx(A,{})}function ne({settings:s}){const[i,t]=r.useState(s),[c,a]=r.useState(!1);return e.jsx(C,{settings:i,setSettings:t,setDirty:a})}function ae(){return e.jsx($,{})}function oe({settings:s}){const i=s.about||{version:"—",homepage:"https://github.com/DrB0rk/BizarHarness",license:"MIT"};return e.jsx(H,{about:i})}function pe({settings:s,onSettingsChange:i,autoSave:t,snapshot:c}){var x,f,h,j;const[a,o]=r.useState(""),[d,u]=r.useState(null),p=[{id:"general",title:"General",icon:O,description:"Theme, accent, layout",component:e.jsx(Z,{settings:s,onSettingsChange:i,autoSave:t})},{id:"providers",title:"AI Providers",icon:N,description:`${((x=c==null?void 0:c.providers)==null?void 0:x.length)??0} configured`,component:e.jsx(_,{settings:s,onSettingsChange:i,autoSave:t})},{id:"env-vars",title:"Environment Variables",icon:W,description:"API keys, secrets",component:e.jsx(ee,{})},{id:"memory",title:"Memory Vault",icon:N,description:"Git remote, LightRAG config",component:e.jsx(se,{})},{id:"system-llm",title:"System LLM",icon:w,description:((f=s.systemLlm)==null?void 0:f.model)||"not set",component:e.jsx(ie,{settings:s,onSettingsChange:i,autoSave:t})},{id:"updates",title:"Updates",icon:Y,description:"Check for updates",component:e.jsx(te,{})},{id:"headroom",title:"Headroom",icon:w,description:(h=s.headroom)!=null&&h.enabled?"Enabled":"Disabled",component:e.jsx(ne,{settings:s})},{id:"tailscale",title:"Tailscale",icon:q,description:"Tailscale serve & auth",component:e.jsx(ae,{})},{id:"about",title:"About",icon:J,description:`Bizar v${((j=s.about)==null?void 0:j.version)||"—"}`,component:e.jsx(oe,{settings:s})}].filter(n=>!a||n.title.toLowerCase().includes(a.toLowerCase())||n.description.toLowerCase().includes(a.toLowerCase()));return e.jsxs("div",{className:"mobile-settings",children:[e.jsxs("div",{className:"mobile-settings-search",children:[e.jsx(le,{}),e.jsx("input",{value:a,onChange:n=>o(n.target.value),placeholder:"Search settings...","aria-label":"Search settings"})]}),e.jsxs("div",{className:"mobile-settings-list",children:[p.map(n=>{const b=n.icon,m=d===n.id;return e.jsxs("div",{className:R("mobile-settings-item",m&&"is-expanded"),children:[e.jsxs("button",{className:"mobile-settings-item-head",onClick:()=>u(m?null:n.id),"aria-expanded":m,"aria-controls":`mobile-settings-body-${n.id}`,children:[e.jsx("div",{className:"mobile-settings-item-icon",children:e.jsx(b,{size:18})}),e.jsxs("div",{className:"mobile-settings-item-text",children:[e.jsx("div",{className:"mobile-settings-item-title",children:n.title}),e.jsx("div",{className:"mobile-settings-item-desc",children:n.description})]}),e.jsx(Q,{size:16,className:R("mobile-settings-item-chevron",m&&"is-rotated")})]}),m&&e.jsx("div",{id:`mobile-settings-body-${n.id}`,className:"mobile-settings-item-body",children:n.component})]},n.id)}),p.length===0&&e.jsxs("div",{className:"mobile-settings-empty",children:['No settings match "',a,'"']})]})]})}function le(){return e.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[e.jsx("circle",{cx:"11",cy:"11",r:"8"}),e.jsx("path",{d:"m21 21-4.35-4.35"})]})}export{pe as MobileSettings};
|