@polderlabs/bizar 5.5.0 → 5.5.2

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 (71) hide show
  1. package/bizar-dash/dist/assets/{EnvVarsSection-L413CQEI.js → EnvVarsSection-DoIzqrlb.js} +3 -3
  2. package/bizar-dash/dist/assets/{EnvVarsSection-L413CQEI.js.map → EnvVarsSection-DoIzqrlb.js.map} +1 -1
  3. package/bizar-dash/dist/assets/{MobileChat-0kGQb1S6.js → MobileChat-CoUCUsbr.js} +1 -1
  4. package/bizar-dash/dist/assets/{MobileChat-0kGQb1S6.js.map → MobileChat-CoUCUsbr.js.map} +1 -1
  5. package/bizar-dash/dist/assets/MobileSettings-BeO04g52.js +1 -0
  6. package/bizar-dash/dist/assets/MobileSettings-BeO04g52.js.map +1 -0
  7. package/bizar-dash/dist/assets/{Toast-C6f1zFJ2.js → Toast-D9nv5N6m.js} +1 -1
  8. package/bizar-dash/dist/assets/{Toast-C6f1zFJ2.js.map → Toast-D9nv5N6m.js.map} +1 -1
  9. package/bizar-dash/dist/assets/{icons-BsWXWkEF.js → icons-Btipv2pp.js} +100 -90
  10. package/bizar-dash/dist/assets/icons-Btipv2pp.js.map +1 -0
  11. package/bizar-dash/dist/assets/main-DHXPuddY.js +18 -0
  12. package/bizar-dash/dist/assets/main-DHXPuddY.js.map +1 -0
  13. package/bizar-dash/dist/assets/{main-BklYy02e.css → main-UG4jKK-F.css} +1 -1
  14. package/bizar-dash/dist/assets/mobile-H5KH9cTL.js +1 -0
  15. package/bizar-dash/dist/assets/{mobile-CsaN4CxH.js.map → mobile-H5KH9cTL.js.map} +1 -1
  16. package/bizar-dash/dist/assets/{mobile-layout-iFBdjEE4.js → mobile-layout-BqHxVb6_.js} +2 -2
  17. package/bizar-dash/dist/assets/{mobile-layout-iFBdjEE4.js.map → mobile-layout-BqHxVb6_.js.map} +1 -1
  18. package/bizar-dash/dist/assets/{useSlashCommands-DGJcC9iQ.js → useSlashCommands-C24-O1e7.js} +2 -2
  19. package/bizar-dash/dist/assets/{useSlashCommands-DGJcC9iQ.js.map → useSlashCommands-C24-O1e7.js.map} +1 -1
  20. package/bizar-dash/dist/index.html +7 -7
  21. package/bizar-dash/dist/mobile.html +3 -3
  22. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  23. package/bizar-dash/src/server/bg-spawner.mjs +522 -305
  24. package/bizar-dash/src/server/headroom.mjs +3 -1
  25. package/bizar-dash/src/server/memory-lightrag.mjs +26 -2
  26. package/bizar-dash/src/server/memory-store.mjs +74 -28
  27. package/bizar-dash/src/server/opencode-sdk.mjs +63 -3
  28. package/bizar-dash/src/server/plugins/registry.mjs +1 -1
  29. package/bizar-dash/src/server/routes/activity.mjs +85 -0
  30. package/bizar-dash/src/server/routes/background.mjs +31 -13
  31. package/bizar-dash/src/server/routes/memory.mjs +91 -38
  32. package/bizar-dash/src/server/routes/opencode-session-detail.mjs +1 -1
  33. package/bizar-dash/src/server/server.mjs +4 -1
  34. package/bizar-dash/src/web/components/Sidebar.tsx +0 -1
  35. package/bizar-dash/src/web/styles/main.css +52 -13
  36. package/bizar-dash/src/web/styles/memory.css +17 -0
  37. package/bizar-dash/src/web/styles/settings.css +6 -56
  38. package/bizar-dash/src/web/views/Marketplace.tsx +192 -31
  39. package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +157 -7
  40. package/bizar-dash/src/web/views/memory/MemoryOverview.tsx +11 -0
  41. package/bizar-dash/src/web/views/settings/MemorySection.tsx +65 -11
  42. package/bizar-dash/tests/background-sdk-session.test.mjs +94 -0
  43. package/bizar-dash/tests/background-session-events.test.mjs +74 -0
  44. package/bizar-dash/tests/background-steer-sdk.test.mjs +71 -0
  45. package/bizar-dash/tests/background-steer.test.mjs +25 -7
  46. package/bizar-dash/tests/memory-namespace.test.mjs +2 -2
  47. package/bizar-dash/tests/memory-status-root.test.mjs +144 -0
  48. package/bizar-dash/tests/memory-store.test.mjs +5 -4
  49. package/bizar-dash/tests/memory-vault-config-endpoint.test.mjs +173 -0
  50. package/bizar-dash/tests/settings-mode-wiring.test.tsx +1 -1
  51. package/bizar-dash/tests/settings-nav.test.tsx +0 -1
  52. package/bizar-dash/tests/views/Marketplace.test.tsx +200 -0
  53. package/bizar-dash/tests/views/Memory.test.tsx +274 -0
  54. package/bizar-dash/tests/views/sidebar.test.tsx +116 -0
  55. package/bizar-dash/tests/views/topbar.test.tsx +87 -0
  56. package/cli/commands/marketplace.mjs +1 -1
  57. package/cli/memory.mjs +1 -1
  58. package/package.json +1 -1
  59. package/plugins/bizar/src/background-state.ts +11 -0
  60. package/plugins/bizar/src/background.ts +212 -34
  61. package/plugins/bizar/src/opencode-runner.ts +80 -353
  62. package/plugins/bizar/src/tools/bg-send-message.ts +160 -61
  63. package/plugins/bizar/src/tools/bg-spawn.ts +235 -156
  64. package/plugins/bizar/tests/tools/bg-send-message.test.ts +84 -11
  65. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +223 -0
  66. package/bizar-dash/dist/assets/MobileSettings-Cq1oFIdO.js +0 -1
  67. package/bizar-dash/dist/assets/MobileSettings-Cq1oFIdO.js.map +0 -1
  68. package/bizar-dash/dist/assets/icons-BsWXWkEF.js.map +0 -1
  69. package/bizar-dash/dist/assets/main-CBTgYSeG.js +0 -18
  70. package/bizar-dash/dist/assets/main-CBTgYSeG.js.map +0 -1
  71. package/bizar-dash/dist/assets/mobile-CsaN4CxH.js +0 -1
@@ -0,0 +1,223 @@
1
+ /**
2
+ * bg-spawn-http.test.ts
3
+ *
4
+ * v5.5.1 — Tests that `bizar_spawn_background` delegates to the dashboard
5
+ * via `POST /api/background` (instead of spawning `opencode run`
6
+ * subprocesses directly). The dashboard POST is mocked so we don't need
7
+ * a live server.
8
+ *
9
+ * The "input-validation" surface (Odin-only check, model parsing,
10
+ * timeoutMs clamping, delegation wrapper) is already covered by the
11
+ * pre-existing bg-spawn.test.ts and bg-spawn-delegation.test.ts. This
12
+ * test focuses on the NEW path: HTTP delegation.
13
+ */
14
+
15
+ import { describe, it, expect } from "bun:test";
16
+
17
+ import {
18
+ createBgSpawnTool,
19
+ PRIMARY_AGENTS,
20
+ buildDelegationPrompt,
21
+ needsDelegationWrapper,
22
+ } from "../../src/tools/bg-spawn";
23
+
24
+ import type { Logger } from "../../src/logger";
25
+
26
+ const silentLogger: Logger = {
27
+ debug() {},
28
+ info() {},
29
+ warn() {},
30
+ error() {},
31
+ log() {},
32
+ };
33
+
34
+ function decode(result: unknown): any {
35
+ if (typeof result === "string") return JSON.parse(result);
36
+ return JSON.parse((result as { output: string }).output);
37
+ }
38
+
39
+ /** Capture the dashboard POST so the test can assert its shape. */
40
+ function makeCapturingDashboard(returnValue: any) {
41
+ const calls: Array<{ url: string; body: any }> = [];
42
+ const post = async (
43
+ url: string,
44
+ init: { headers: Record<string, string>; body: string },
45
+ ) => {
46
+ calls.push({ url, body: JSON.parse(init.body) });
47
+ return {
48
+ ok: true,
49
+ status: 200,
50
+ json: async () => returnValue,
51
+ };
52
+ };
53
+ return { calls, post };
54
+ }
55
+
56
+ /** Minimal mock InstanceManager — just enough for add/get/update. */
57
+ function makeInstanceManager() {
58
+ const instances = new Map<string, any>();
59
+ return {
60
+ add: async (draft: any) => {
61
+ instances.set(draft.instanceId, { ...draft, status: "pending" });
62
+ return { ...draft, status: "pending" };
63
+ },
64
+ get: async (id: string) => instances.get(id) ?? null,
65
+ update: async (id: string, patch: any) => {
66
+ const cur = instances.get(id);
67
+ if (!cur) return;
68
+ const next = { ...cur, ...patch };
69
+ instances.set(id, next);
70
+ },
71
+ _instances: instances,
72
+ };
73
+ }
74
+
75
+ describe("bizar_spawn_background — HTTP delegation (v5.5.1)", () => {
76
+ it("rejects non-Odin callers", async () => {
77
+ const mgr = makeInstanceManager();
78
+ const tool = createBgSpawnTool({
79
+ instanceManager: mgr as any,
80
+ worktree: "/tmp",
81
+ logger: silentLogger,
82
+ });
83
+ const r = await tool.execute(
84
+ { agent: "mimir", prompt: "hi" } as any,
85
+ { agent: "frigg" } as any,
86
+ );
87
+ expect(decode(r).error).toContain("Only Odin");
88
+ });
89
+
90
+ it("POSTs to /api/background on the dashboard with the right shape", async () => {
91
+ const mgr = makeInstanceManager();
92
+ const { calls, post } = makeCapturingDashboard({
93
+ instanceId: "bgr_dash_xyz",
94
+ sessionId: "ses_xyz",
95
+ status: "running",
96
+ liveSession: true,
97
+ });
98
+ const tool = createBgSpawnTool({
99
+ instanceManager: mgr as any,
100
+ worktree: "/tmp/worktree",
101
+ logger: silentLogger,
102
+ _dashboardPost: post,
103
+ });
104
+ const r = await tool.execute(
105
+ {
106
+ agent: "mimir",
107
+ prompt: "research X",
108
+ model: "minimax/minimax-m3",
109
+ timeoutMs: 60_000,
110
+ } as any,
111
+ { agent: "odin", sessionID: "ses_parent" } as any,
112
+ );
113
+ expect(calls).toHaveLength(1);
114
+ const call = calls[0]!;
115
+ expect(call.url).toContain("/api/background");
116
+ // URL should NOT include "/api/background/:id" — it's the create endpoint.
117
+ expect(call.url).not.toMatch(/\/api\/background\/bgr_/);
118
+ expect(call.body.agent).toBe("mimir");
119
+ expect(call.body.worktree).toBe("/tmp/worktree");
120
+ expect(call.body.timeoutMs).toBe(60_000);
121
+ expect(call.body.model).toBe("minimax/minimax-m3");
122
+ // For subagents, the prompt is the delegation wrapper.
123
+ expect(call.body.prompt).toContain("Requested subagent: mimir");
124
+ expect(call.body.prompt).toContain("research X");
125
+ expect(call.body.tags).toContain("spawned-by:odin");
126
+ const out = decode(r);
127
+ expect(out.instanceId).toBeDefined();
128
+ expect(out.dashboardInstanceId).toBe("bgr_dash_xyz");
129
+ expect(out.sessionId).toBe("ses_xyz");
130
+ expect(out.processId).toBeNull();
131
+ expect(out.liveSession).toBe(true);
132
+ expect(out.status).toBe("running");
133
+ });
134
+
135
+ it("does NOT wrap the prompt for primary agents", async () => {
136
+ const mgr = makeInstanceManager();
137
+ const { calls, post } = makeCapturingDashboard({
138
+ instanceId: "bgr_odin_1",
139
+ sessionId: "ses_1",
140
+ });
141
+ const tool = createBgSpawnTool({
142
+ instanceManager: mgr as any,
143
+ worktree: "/tmp",
144
+ logger: silentLogger,
145
+ _dashboardPost: post,
146
+ });
147
+ await tool.execute(
148
+ { agent: "odin", prompt: "raw prompt here" } as any,
149
+ { agent: "odin", sessionID: "ses_parent" } as any,
150
+ );
151
+ const call = calls[0]!;
152
+ expect(call.body.agent).toBe("odin");
153
+ expect(call.body.prompt).toBe("raw prompt here"); // no wrapper
154
+ });
155
+
156
+ it("returns a clear error when the dashboard POST fails", async () => {
157
+ const mgr = makeInstanceManager();
158
+ const post = async () => {
159
+ throw new Error("ECONNREFUSED");
160
+ };
161
+ const tool = createBgSpawnTool({
162
+ instanceManager: mgr as any,
163
+ worktree: "/tmp",
164
+ logger: silentLogger,
165
+ _dashboardPost: post,
166
+ });
167
+ const r = await tool.execute(
168
+ { agent: "mimir", prompt: "hi" } as any,
169
+ { agent: "odin", sessionID: "ses_parent" } as any,
170
+ );
171
+ const out = decode(r);
172
+ expect(out.error).toContain("ECONNREFUSED");
173
+ expect(out.status).toBe("failed");
174
+ });
175
+
176
+ it("returns error for malformed model", async () => {
177
+ const mgr = makeInstanceManager();
178
+ const tool = createBgSpawnTool({
179
+ instanceManager: mgr as any,
180
+ worktree: "/tmp",
181
+ logger: silentLogger,
182
+ });
183
+ const r = await tool.execute(
184
+ { agent: "mimir", prompt: "hi", model: "no-slash" } as any,
185
+ { agent: "odin", sessionID: "ses_parent" } as any,
186
+ );
187
+ expect(decode(r).error).toContain("providerID/modelID");
188
+ });
189
+
190
+ it("returns error for out-of-range timeoutMs", async () => {
191
+ const mgr = makeInstanceManager();
192
+ const tool = createBgSpawnTool({
193
+ instanceManager: mgr as any,
194
+ worktree: "/tmp",
195
+ logger: silentLogger,
196
+ });
197
+ const r = await tool.execute(
198
+ { agent: "mimir", prompt: "hi", timeoutMs: 100 } as any,
199
+ { agent: "odin", sessionID: "ses_parent" } as any,
200
+ );
201
+ expect(decode(r).error).toContain("timeoutMs must be between");
202
+ });
203
+ });
204
+
205
+ // Re-pins for the delegation helpers so a refactor of bg-spawn.ts keeps
206
+ // the suite green (these are also covered by bg-spawn-delegation.test.ts,
207
+ // but pin them here for fast-failure in the same suite).
208
+ describe("bizar_spawn_background — delegation helpers (re-pinned)", () => {
209
+ it("PRIMARY_AGENTS is unchanged", () => {
210
+ expect(PRIMARY_AGENTS.has("odin")).toBe(true);
211
+ expect(PRIMARY_AGENTS.has("quick")).toBe(true);
212
+ expect(PRIMARY_AGENTS.has("browser-harness")).toBe(true);
213
+ expect(PRIMARY_AGENTS.has("mimir")).toBe(false);
214
+ });
215
+ it("needsDelegationWrapper mirrors PRIMARY_AGENTS", () => {
216
+ expect(needsDelegationWrapper("odin")).toBe(false);
217
+ expect(needsDelegationWrapper("mimir")).toBe(true);
218
+ });
219
+ it("buildDelegationPrompt names the requested subagent", () => {
220
+ const p = buildDelegationPrompt("mimir", "research X");
221
+ expect(p).toContain("Requested subagent: mimir");
222
+ });
223
+ });
@@ -1 +0,0 @@
1
- import{r as c,j as e}from"./react-vendor-Dn4wqh4Z.js";import{a as b,S,c as g}from"./mobile-layout-iFBdjEE4.js";import{C as L,a as z,b as T,B as k,G as R,E,S as M,U,H as w,T as B,c as G}from"./EnvVarsSection-L413CQEI.js";import{u as A}from"./Toast-C6f1zFJ2.js";import{j as f,K as I,aR as H,a7 as P,s as V,aA as $,w as v,R as C,aD as D,I as K,e as O}from"./icons-BsWXWkEF.js";function F(){const s=A(),[i,t]=c.useState(!0),[a,n]=c.useState(!1),[r,d]=c.useState(""),[j]=c.useState(""),[y,u]=c.useState(0);c.useEffect(()=>{b.get("/memory/config/global").then(l=>{var m,p;d(((p=(m=l.config)==null?void 0:m.git)==null?void 0:p.remoteUrl)||""),t(!1)}).catch(()=>t(!1))},[y]);const h=async()=>{n(!0);try{await b.put("/memory/config/global",{git:{remoteUrl:r}}),s.success("Memory config saved."),u(l=>l+1)}catch(l){s.error(`Save failed: ${l.message}`)}finally{n(!1)}};return e.jsxs(L,{id:"settings-memory","data-section":"memory",children:[e.jsxs(z,{children:[e.jsx(f,{size:14})," Memory vault"]}),e.jsx(T,{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(S,{size:"sm"})}):e.jsxs("div",{className:"settings-fields",children:[e.jsxs("div",{className:"field",children:[e.jsx("label",{className:"field-label",children:"Vault path"}),e.jsx("div",{className:"field-readonly mono muted",style:{fontSize:12,padding:"6px 0"},children:j||"~/.local/share/bizar/memory"})]}),e.jsxs("div",{className:"field",children:[e.jsxs("label",{className:"field-label",htmlFor:"set-memory-git-remote",children:[e.jsx(I,{size:12,style:{display:"inline",marginRight:4}}),"Git remote URL"]}),e.jsx("input",{id:"set-memory-git-remote",className:"input mono",type:"text",value:r,onChange:l=>d(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(k,{variant:"primary",size:"sm",onClick:h,disabled:a,children:[a?e.jsx(H,{size:12,className:"memory-spin"}):e.jsx(P,{size:12}),"Save memory config"]})})]})]})}function W({settings:s,onSettingsChange:i,autoSave:t}){const a=(r,d)=>{i==null||i(r,d),t==null||t(r,d)},n=r=>{i==null||i("ui",{...s.ui,...r}),t==null||t("ui",{...s.ui,...r})};return e.jsx(R,{settings:s,patchUi:n,patchTop:a,autoSave:t})}function q({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 J(){return e.jsx(E,{})}function Q(){return e.jsx(F,{})}function X({settings:s,onSettingsChange:i,autoSave:t}){const a=(n,r)=>{i==null||i(n,r),t==null||t(n,r)};return e.jsx(M,{settings:s,patchTop:a})}function Y(){return e.jsx(U,{})}function Z({settings:s}){const[i,t]=c.useState(s),[a,n]=c.useState(!1);return e.jsx(w,{settings:i,setSettings:t,setDirty:n})}function _(){return e.jsx(B,{})}function ee({settings:s}){const i=s.about||{version:"—",homepage:"https://github.com/DrB0rk/BizarHarness",license:"MIT"};return e.jsx(G,{about:i})}function ae({settings:s,onSettingsChange:i,autoSave:t,snapshot:a}){var h,l,m,p;const[n,r]=c.useState(""),[d,j]=c.useState(null),u=[{id:"general",title:"General",icon:V,description:"Theme, accent, layout",component:e.jsx(W,{settings:s,onSettingsChange:i,autoSave:t})},{id:"providers",title:"AI Providers",icon:f,description:`${((h=a==null?void 0:a.providers)==null?void 0:h.length)??0} configured`,component:e.jsx(q,{settings:s,onSettingsChange:i,autoSave:t})},{id:"env-vars",title:"Environment Variables",icon:$,description:"API keys, secrets",component:e.jsx(J,{})},{id:"memory",title:"Memory Vault",icon:f,description:"Git remote, LightRAG config",component:e.jsx(Q,{})},{id:"system-llm",title:"System LLM",icon:v,description:((l=s.systemLlm)==null?void 0:l.model)||"not set",component:e.jsx(X,{settings:s,onSettingsChange:i,autoSave:t})},{id:"updates",title:"Updates",icon:C,description:"Check for updates",component:e.jsx(Y,{})},{id:"headroom",title:"Headroom",icon:v,description:(m=s.headroom)!=null&&m.enabled?"Enabled":"Disabled",component:e.jsx(Z,{settings:s})},{id:"tailscale",title:"Tailscale",icon:D,description:"Tailscale serve & auth",component:e.jsx(_,{})},{id:"about",title:"About",icon:K,description:`Bizar v${((p=s.about)==null?void 0:p.version)||"—"}`,component:e.jsx(ee,{settings:s})}].filter(o=>!n||o.title.toLowerCase().includes(n.toLowerCase())||o.description.toLowerCase().includes(n.toLowerCase()));return e.jsxs("div",{className:"mobile-settings",children:[e.jsxs("div",{className:"mobile-settings-search",children:[e.jsx(se,{}),e.jsx("input",{value:n,onChange:o=>r(o.target.value),placeholder:"Search settings...","aria-label":"Search settings"})]}),e.jsxs("div",{className:"mobile-settings-list",children:[u.map(o=>{const N=o.icon,x=d===o.id;return e.jsxs("div",{className:g("mobile-settings-item",x&&"is-expanded"),children:[e.jsxs("button",{className:"mobile-settings-item-head",onClick:()=>j(x?null:o.id),"aria-expanded":x,"aria-controls":`mobile-settings-body-${o.id}`,children:[e.jsx("div",{className:"mobile-settings-item-icon",children:e.jsx(N,{size:18})}),e.jsxs("div",{className:"mobile-settings-item-text",children:[e.jsx("div",{className:"mobile-settings-item-title",children:o.title}),e.jsx("div",{className:"mobile-settings-item-desc",children:o.description})]}),e.jsx(O,{size:16,className:g("mobile-settings-item-chevron",x&&"is-rotated")})]}),x&&e.jsx("div",{id:`mobile-settings-body-${o.id}`,className:"mobile-settings-item-body",children:o.component})]},o.id)}),u.length===0&&e.jsxs("div",{className:"mobile-settings-empty",children:['No settings match "',n,'"']})]})]})}function se(){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{ae as MobileSettings};
@@ -1 +0,0 @@
1
- {"version":3,"file":"MobileSettings-Cq1oFIdO.js","sources":["../../src/web/views/settings/MemorySection.tsx","../../src/web/mobile/MobileSettings.tsx"],"sourcesContent":["// src/web/views/settings/MemorySection.tsx — memory vault + git config for Settings.\nimport React, { useEffect, useState } from 'react';\nimport { Brain, GitBranch, Loader2, Save } from 'lucide-react';\nimport { Button } from '../../components/Button';\nimport { Card, CardTitle, CardMeta } from '../../components/Card';\nimport { Spinner } from '../../components/Spinner';\nimport { useToast } from '../../components/Toast';\nimport { api } from '../../lib/api';\n\ntype GitConfig = {\n remoteUrl?: string;\n};\n\ntype GlobalConfig = {\n git?: GitConfig;\n};\n\nexport function MemorySection() {\n const toast = useToast();\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [remoteUrl, setRemoteUrl] = useState('');\n const [vaultPath] = useState<string>(''); // server-side default, not user-editable\n const [refreshKey, setRefreshKey] = useState(0);\n\n useEffect(() => {\n api.get<{ config: GlobalConfig; path?: string }>('/memory/config/global')\n .then((r) => {\n setRemoteUrl(r.config?.git?.remoteUrl || '');\n setLoading(false);\n })\n .catch(() => setLoading(false));\n }, [refreshKey]);\n\n const onSave = async () => {\n setSaving(true);\n try {\n await api.put('/memory/config/global', { git: { remoteUrl } });\n toast.success('Memory config saved.');\n setRefreshKey((k) => k + 1);\n } catch (err) {\n toast.error(`Save failed: ${(err as Error).message}`);\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Card id=\"settings-memory\" data-section=\"memory\">\n <CardTitle><Brain size={14} /> Memory vault</CardTitle>\n <CardMeta>\n The vault lives at a default location on disk. Only the git remote URL\n needs to be configured to enable sync across machines.\n </CardMeta>\n\n {loading ? (\n <div className=\"flex-center\" style={{ padding: 24 }}>\n <Spinner size=\"sm\" />\n </div>\n ) : (\n <div className=\"settings-fields\">\n <div className=\"field\">\n <label className=\"field-label\">Vault path</label>\n <div className=\"field-readonly mono muted\" style={{ fontSize: 12, padding: '6px 0' }}>\n {vaultPath || '~/.local/share/bizar/memory'}\n </div>\n </div>\n\n <div className=\"field\">\n <label className=\"field-label\" htmlFor=\"set-memory-git-remote\">\n <GitBranch size={12} style={{ display: 'inline', marginRight: 4 }} />\n Git remote URL\n </label>\n <input\n id=\"set-memory-git-remote\"\n className=\"input mono\"\n type=\"text\"\n value={remoteUrl}\n onChange={(e) => setRemoteUrl(e.target.value)}\n placeholder=\"git@github.com:org/repo.git\"\n />\n <span className=\"field-hint\">Leave empty to use local-only mode (no git sync).</span>\n </div>\n\n <div style={{ marginTop: 12 }}>\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={onSave}\n disabled={saving}\n >\n {saving ? <Loader2 size={12} className=\"memory-spin\" /> : <Save size={12} />}\n Save memory config\n </Button>\n </div>\n </div>\n )}\n </Card>\n );\n}\n","// src/web/mobile/MobileSettings.tsx — v5.4 mobile settings with full desktop parity.\n// All 9 sections in an accordion layout with search.\nimport { useState } from 'react';\nimport {\n Settings2, Brain, KeyRound, Cpu, RefreshCw, Globe, Info, ChevronRight,\n} from 'lucide-react';\nimport { cn } from '../lib/utils';\nimport type { Settings, Snapshot } from '../lib/types';\n\n// Sub-section components — each renders its section content inline.\nimport { GeneralSection } from '../views/settings/GeneralSection';\nimport { EnvVarsSection } from '../views/settings/EnvVarsSection';\nimport { MemorySection } from '../views/settings/MemorySection';\nimport { SystemLlmSection } from '../views/settings/SystemLlmSection';\nimport { UpdatesSection } from '../views/settings/UpdatesSection';\nimport { HeadroomSection } from '../views/settings/HeadroomSection';\nimport { TailscaleSettings } from '../components/TailscaleSettings';\nimport { ActivitySection } from '../views/settings/ActivitySection';\n\n// Lazy-load heavy sections that pull in large dependencies.\nimport React from 'react';\n\ntype Props = {\n settings: Settings;\n /** Called when the user changes any top-level setting */\n onSettingsChange?: <K extends keyof Settings>(key: K, value: Settings[K]) => void;\n /** Debounced auto-save to API (key, value) */\n autoSave?: (key: keyof Settings, value: Settings[keyof Settings]) => void;\n /** Optional snapshot for counts / agent list */\n snapshot?: Snapshot | null;\n /** v5.3 compatibility — called after settings are saved (MobileApp.tsx passes refreshSnapshot) */\n onRefresh?: () => Promise<void>;\n};\n\n// ─── Section definitions ─────────────────────────────────────────────────────\n\nfunction GeneralSettings({ settings, onSettingsChange, autoSave }: Props) {\n const patchTop = <K extends keyof Settings>(key: K, value: Settings[K]) => {\n onSettingsChange?.(key, value);\n autoSave?.(key, value);\n };\n const patchUi = (patch: Partial<Settings['ui']>) => {\n onSettingsChange?.('ui', { ...settings.ui, ...patch });\n autoSave?.('ui', { ...settings.ui, ...patch });\n };\n return (\n <GeneralSection\n settings={settings}\n patchUi={patchUi}\n patchTop={patchTop}\n autoSave={autoSave}\n />\n );\n}\n\nfunction ProvidersSettings({ settings, onSettingsChange, autoSave }: Props) {\n // Providers are managed server-side; show a link to the desktop providers view.\n // Mobile can't add/edit providers without more complex auth flow.\n void settings; void onSettingsChange; void autoSave;\n return (\n <div style={{ fontSize: 13, color: 'var(--text-dim)', padding: '8px 0' }}>\n <p style={{ marginBottom: 8 }}>\n Provider management is available on desktop.\n </p>\n <a href=\"/?desktop=1#settings-providers\" className=\"mobile-btn mobile-btn-secondary\" style={{ display: 'inline-block', fontSize: 12, padding: '6px 12px' }}>\n Open desktop to manage providers\n </a>\n </div>\n );\n}\n\nfunction EnvVarsSettings() {\n return <EnvVarsSection />;\n}\n\nfunction MemorySettings() {\n return <MemorySection />;\n}\n\nfunction SystemLlmSettings({ settings, onSettingsChange, autoSave }: Props) {\n const patchTop = <K extends keyof Settings>(key: K, value: Settings[K]) => {\n onSettingsChange?.(key, value);\n autoSave?.(key, value);\n };\n return <SystemLlmSection settings={settings} patchTop={patchTop} />;\n}\n\nfunction UpdatesSettings() {\n return <UpdatesSection />;\n}\n\nfunction HeadroomSettingsSection({ settings }: { settings: Settings }) {\n const [localSettings, setLocalSettings] = useState(settings);\n const [dirty, setDirty] = useState(false);\n return (\n <HeadroomSection\n settings={localSettings}\n setSettings={setLocalSettings as React.Dispatch<React.SetStateAction<Settings>>}\n setDirty={setDirty}\n />\n );\n}\n\nfunction TailscaleSettingsMobile() {\n return <TailscaleSettings />;\n}\n\nfunction AboutSection({ settings }: { settings: Settings }) {\n const about = settings.about || { version: '—', homepage: 'https://github.com/DrB0rk/BizarHarness', license: 'MIT' };\n return <ActivitySection about={about} />;\n}\n\n// ─── Main component ──────────────────────────────────────────────────────────\n\nexport function MobileSettings({ settings, onSettingsChange, autoSave, snapshot }: Props) {\n const [search, setSearch] = useState('');\n const [expandedSection, setExpandedSection] = useState<string | null>(null);\n\n const sections = [\n {\n id: 'general',\n title: 'General',\n icon: Settings2,\n description: 'Theme, accent, layout',\n component: <GeneralSettings settings={settings} onSettingsChange={onSettingsChange} autoSave={autoSave} />,\n },\n {\n id: 'providers',\n title: 'AI Providers',\n icon: Brain,\n description: `${snapshot?.providers?.length ?? 0} configured`,\n component: <ProvidersSettings settings={settings} onSettingsChange={onSettingsChange} autoSave={autoSave} />,\n },\n {\n id: 'env-vars',\n title: 'Environment Variables',\n icon: KeyRound,\n description: 'API keys, secrets',\n component: <EnvVarsSettings />,\n },\n {\n id: 'memory',\n title: 'Memory Vault',\n icon: Brain,\n description: 'Git remote, LightRAG config',\n component: <MemorySettings />,\n },\n {\n id: 'system-llm',\n title: 'System LLM',\n icon: Cpu,\n description: settings.systemLlm?.model || 'not set',\n component: <SystemLlmSettings settings={settings} onSettingsChange={onSettingsChange} autoSave={autoSave} />,\n },\n {\n id: 'updates',\n title: 'Updates',\n icon: RefreshCw,\n description: 'Check for updates',\n component: <UpdatesSettings />,\n },\n {\n id: 'headroom',\n title: 'Headroom',\n icon: Cpu,\n description: settings.headroom?.enabled ? 'Enabled' : 'Disabled',\n component: <HeadroomSettingsSection settings={settings} />,\n },\n {\n id: 'tailscale',\n title: 'Tailscale',\n icon: Globe,\n description: 'Tailscale serve & auth',\n component: <TailscaleSettingsMobile />,\n },\n {\n id: 'about',\n title: 'About',\n icon: Info,\n description: `Bizar v${settings.about?.version || '—'}`,\n component: <AboutSection settings={settings} />,\n },\n ];\n\n const filtered = sections.filter(\n (s) =>\n !search ||\n s.title.toLowerCase().includes(search.toLowerCase()) ||\n s.description.toLowerCase().includes(search.toLowerCase()),\n );\n\n return (\n <div className=\"mobile-settings\">\n <div className=\"mobile-settings-search\">\n <SearchIcon />\n <input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search settings...\"\n aria-label=\"Search settings\"\n />\n </div>\n\n <div className=\"mobile-settings-list\">\n {filtered.map((s) => {\n const Icon = s.icon;\n const isExpanded = expandedSection === s.id;\n return (\n <div key={s.id} className={cn('mobile-settings-item', isExpanded && 'is-expanded')}>\n <button\n className=\"mobile-settings-item-head\"\n onClick={() => setExpandedSection(isExpanded ? null : s.id)}\n aria-expanded={isExpanded}\n aria-controls={`mobile-settings-body-${s.id}`}\n >\n <div className=\"mobile-settings-item-icon\">\n <Icon size={18} />\n </div>\n <div className=\"mobile-settings-item-text\">\n <div className=\"mobile-settings-item-title\">{s.title}</div>\n <div className=\"mobile-settings-item-desc\">{s.description}</div>\n </div>\n <ChevronRight\n size={16}\n className={cn('mobile-settings-item-chevron', isExpanded && 'is-rotated')}\n />\n </button>\n {isExpanded && (\n <div id={`mobile-settings-body-${s.id}`} className=\"mobile-settings-item-body\">\n {s.component}\n </div>\n )}\n </div>\n );\n })}\n {filtered.length === 0 && (\n <div className=\"mobile-settings-empty\">No settings match \"{search}\"</div>\n )}\n </div>\n </div>\n );\n}\n\nfunction SearchIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.35-4.35\" />\n </svg>\n );\n}\n"],"names":["MemorySection","toast","useToast","loading","setLoading","useState","saving","setSaving","remoteUrl","setRemoteUrl","vaultPath","refreshKey","setRefreshKey","useEffect","api","r","_b","_a","onSave","k","err","jsxs","Card","CardTitle","jsx","Brain","CardMeta","Spinner","GitBranch","e","Button","Loader2","Save","GeneralSettings","settings","onSettingsChange","autoSave","patchTop","key","value","patchUi","patch","GeneralSection","ProvidersSettings","EnvVarsSettings","EnvVarsSection","MemorySettings","SystemLlmSettings","SystemLlmSection","UpdatesSettings","UpdatesSection","HeadroomSettingsSection","localSettings","setLocalSettings","dirty","setDirty","HeadroomSection","TailscaleSettingsMobile","TailscaleSettings","AboutSection","about","ActivitySection","MobileSettings","snapshot","search","setSearch","expandedSection","setExpandedSection","filtered","Settings2","KeyRound","Cpu","RefreshCw","_c","Globe","Info","_d","s","SearchIcon","Icon","isExpanded","cn","ChevronRight"],"mappings":"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"}