@polderlabs/bizar 7.0.0 → 7.0.1
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/README.md +125 -47
- package/bizar-dash/dist/assets/{EnvVarsSection-CW6fWKds.js → EnvVarsSection-weVnLz3Z.js} +3 -3
- package/bizar-dash/dist/assets/EnvVarsSection-weVnLz3Z.js.map +1 -0
- package/bizar-dash/dist/assets/{MobileChat-D7zRhU9K.js → MobileChat-BRFjer8p.js} +1 -1
- package/bizar-dash/dist/assets/{MobileChat-D7zRhU9K.js.map → MobileChat-BRFjer8p.js.map} +1 -1
- package/bizar-dash/dist/assets/MobileSettings-Dw5jyJWi.js +1 -0
- package/bizar-dash/dist/assets/MobileSettings-Dw5jyJWi.js.map +1 -0
- package/bizar-dash/dist/assets/flow-BpU0-gK2.js.map +1 -1
- package/bizar-dash/dist/assets/icons-B0AKnYI3.js.map +1 -1
- package/bizar-dash/dist/assets/main-BE4Uh9im.css +1 -0
- package/bizar-dash/dist/assets/{main-CO8fIxQK.js → main-DqC58FEZ.js} +11 -11
- package/bizar-dash/dist/assets/main-DqC58FEZ.js.map +1 -0
- package/bizar-dash/dist/assets/markdown-w2bDDkAH.js.map +1 -1
- package/bizar-dash/dist/assets/{mobile-DXYCA0hC.js → mobile-DRZsK3ic.js} +1 -1
- package/bizar-dash/dist/assets/{mobile-DXYCA0hC.js.map → mobile-DRZsK3ic.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-layout-BWLtwtfQ.css +1 -0
- package/bizar-dash/dist/assets/{mobile-layout-DSmtNPja.js → mobile-layout-Ckru3HKJ.js} +2 -2
- package/bizar-dash/dist/assets/{mobile-layout-DSmtNPja.js.map → mobile-layout-Ckru3HKJ.js.map} +1 -1
- package/bizar-dash/dist/assets/react-vendor-D3pra6w-.js.map +1 -1
- package/bizar-dash/dist/assets/{useSlashCommands-3DFLOfpk.js → useSlashCommands-BAxVOU_a.js} +2 -2
- package/bizar-dash/dist/assets/{useSlashCommands-3DFLOfpk.js.map → useSlashCommands-BAxVOU_a.js.map} +1 -1
- package/bizar-dash/dist/assets/vendor-Di7Cp-rw.js.map +1 -1
- package/bizar-dash/dist/index.html +6 -6
- package/bizar-dash/dist/mobile.html +3 -3
- package/bizar-dash/src/server/memory-consolidator.mjs +8 -1
- package/bizar-dash/src/web/mobile/MobileApp.tsx +33 -2
- package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +2 -2
- package/bizar-dash/src/web/mobile/MobileEval.tsx +4 -4
- package/bizar-dash/src/web/mobile/MobileMemory.tsx +2 -2
- package/bizar-dash/src/web/mobile/MobileSettings.tsx +3 -3
- package/bizar-dash/src/web/mobile/MobileTasks.tsx +2 -2
- package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +3 -3
- package/bizar-dash/src/web/styles/mobile.css +41 -0
- package/bizar-dash/src/web/styles/tasks-redesign.css +34 -12
- package/bizar-dash/src/web/ui/controls/Textarea.tsx +56 -0
- package/bizar-dash/src/web/ui/controls/controls.css +22 -0
- package/bizar-dash/src/web/ui/controls/index.ts +2 -0
- package/bizar-dash/src/web/ui/layout/ViewHeader.tsx +48 -0
- package/bizar-dash/src/web/ui/layout/index.ts +1 -0
- package/bizar-dash/src/web/ui/layout/layout.css +51 -0
- package/bizar-dash/src/web/ui/styles/tokens.css +13 -0
- package/bizar-dash/src/web/views/Agents.tsx +10 -2
- package/bizar-dash/src/web/views/Overview.tsx +2 -13
- package/bizar-dash/src/web/views/Tasks.tsx +1 -7
- package/bizar-dash/tests/ui/controls/Textarea.test.tsx +56 -0
- package/bizar-dash/tests/ui/layout/ViewHeader.test.tsx +47 -0
- package/cli/provision-claude.mjs +94 -0
- package/package.json +1 -1
- package/bizar-dash/dist/assets/EnvVarsSection-CW6fWKds.js.map +0 -1
- package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js +0 -1
- package/bizar-dash/dist/assets/MobileSettings-K-sNsn_r.js.map +0 -1
- package/bizar-dash/dist/assets/main-C-Md3DaY.css +0 -1
- package/bizar-dash/dist/assets/main-CO8fIxQK.js.map +0 -1
- package/bizar-dash/dist/assets/mobile-layout-CJnZNLy3.css +0 -1
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
Claude Code Agent SDK in-process — no subprocess, no port, no serve-info file.
|
|
9
9
|
|
|
10
10
|
[](https://www.npmjs.com/package/@polderlabs/bizar)
|
|
11
|
-
[](https://github.com/DrB0rk/BizarHarness)
|
|
12
12
|
[](https://docs.claude.com/claude-code)
|
|
13
13
|
[](https://github.com/DrB0rk/BizarHarness)
|
|
14
14
|
[](docs/INDEX.md)
|
|
@@ -26,50 +26,58 @@ Claude Code Agent SDK in-process — no subprocess, no port, no serve-info file.
|
|
|
26
26
|
|
|
27
27
|
## Table of Contents
|
|
28
28
|
|
|
29
|
-
- [What's new in
|
|
29
|
+
- [What's new in v7.0.0](#-whats-new-in-v700)
|
|
30
30
|
- [Quick start](#-quick-start)
|
|
31
31
|
- [The Pantheon](#-the-pantheon)
|
|
32
32
|
- [Architecture](#-architecture)
|
|
33
|
-
- [Tools (
|
|
34
|
-
- [Hooks (
|
|
33
|
+
- [Tools (23 total)](#-tools-23-total)
|
|
34
|
+
- [Hooks (7 total)](#-hooks-7-total)
|
|
35
35
|
- [Safety — DANGEROUS_PATTERNS](#-safety--dangerous-patterns)
|
|
36
36
|
- [Skill Curator — closed learning loop](#-skill-curator--closed-learning-loop)
|
|
37
37
|
- [Knowledge Graph Tools](#-knowledge-graph-tools)
|
|
38
|
+
- [Agents and history dashboard](#-agents-and-history-dashboard)
|
|
38
39
|
- [Harness engineering audit (73/73)](#-harness-engineering-audit-7373)
|
|
39
40
|
- [Documentation](#-documentation)
|
|
40
|
-
- [Migration from v6.
|
|
41
|
+
- [Migration from v6.3.x](#-migration-from-v63x)
|
|
41
42
|
- [Historical: OpenCode → Cline (v5.6/v6.0)](#-historical-opencode--cline-v56v60)
|
|
42
43
|
- [Contributing](#-contributing)
|
|
43
44
|
- [License](#-license)
|
|
44
45
|
|
|
45
46
|
---
|
|
46
47
|
|
|
47
|
-
## ✨ What's new in
|
|
48
|
+
## ✨ What's new in v7.0.0
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
v7.0.0 lands **F-040 — the dashboard redesign** — on top of the
|
|
51
|
+
v6.3.0 Claude Code migration. The dashboard ships a custom `ui/`
|
|
52
|
+
design system (42 components across controls, data, feedback,
|
|
53
|
+
layout, navigation, primitives, theme + tokens) and rewrites
|
|
54
|
+
the Overview, Agents, and Tasks views on top of it. v7.0.0 also
|
|
55
|
+
carries the v6.5.0 work (F-037 migration cleanup, F-038
|
|
56
|
+
federation skeleton, F-039 Byzantine consensus) that had been
|
|
57
|
+
prepared but not published.
|
|
57
58
|
|
|
58
59
|
| Feature | Description |
|
|
59
60
|
| --- | --- |
|
|
60
|
-
|
|
|
61
|
-
| **
|
|
62
|
-
| **
|
|
63
|
-
| **
|
|
64
|
-
| **
|
|
65
|
-
| **
|
|
66
|
-
| **
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
61
|
+
| **`bizar-dash/src/web/ui/` design system** | 42 components (Button, Checkbox, Select, Slider, Toggle, DataTable, BarChart, Sparkline, StatTile, Tooltip, Toast, Dialog, AppShell, Sidebar, Topbar, CommandPalette, Box, Stack, Grid, + 23 more), tokenized via `ui/styles/tokens.css`, themeable via `ui/theme/ThemeProvider.tsx`. |
|
|
62
|
+
| **Three view rewrites** | `Overview`, `Agents`, `Tasks` rebuilt on the design system. 123 dashboard test files (41 component tests + 82 view/integration tests). |
|
|
63
|
+
| **18 dashboard tabs** | Overview, Chat, Agents, Glyphs, Tasks, Activity, Active, Skills, Memory, Mods, Schedules, History, Usage, Eval, Doctor, Harness, Goals, Settings. |
|
|
64
|
+
| **Federation skeleton (F-038)** | 8 modules under `packages/sdk/src/federation/` — HMAC+nonce envelopes, PII pipeline, TrustEvaluator, PolicyEngine, AuditService, FederationBudget. Exposed as the `federation_status` MCP tool. |
|
|
65
|
+
| **Byzantine consensus (F-039)** | 4 modules under `packages/sdk/src/consensus/` — 3-of-5 majority for review/decision steps; PBFT pre-prepare/prepare/commit/reply. Exposed as the `consensus_propose` MCP tool. |
|
|
66
|
+
| **23 MCP tools, 7 hooks** | All Claude Code `MCP tool registration`; hooks cover bash + edit/write pre+post, session lifecycle, prompt tagging, and worker suggestion. |
|
|
67
|
+
| **Agents + History dashboard** | 11 `/api/agents/*` endpoints with on-disk status persistence; `/api/history` aggregator over activity log + tasks + plans + projects. See the [honest scope note](#-agents--history-dashboard) below. |
|
|
68
|
+
|
|
69
|
+
> **Honest scope note.** The Agents and History *infrastructure*
|
|
70
|
+
> is fully wired (REST, store, WebSocket broadcast, 11 endpoints).
|
|
71
|
+
> The *hook-driven auto-feed* — hooks that POST to
|
|
72
|
+
> `/api/agents/:name/status` as Claude Code tools fire — is **not**
|
|
73
|
+
> wired in v7.0.0. That was in PR #2, deferred to a follow-up.
|
|
74
|
+
> Today the Agents view surfaces data from manual `status` POSTs
|
|
75
|
+
> and CLI operations; running-agent detection lights up once the
|
|
76
|
+
> hook layer lands (target v7.1).
|
|
77
|
+
|
|
78
|
+
See the full [CHANGELOG.md](CHANGELOG.md) and
|
|
79
|
+
[docs/releases/v7.0.0.md](docs/releases/v7.0.0.md) for what
|
|
80
|
+
landed, what's wired, and what's still to come.
|
|
73
81
|
|
|
74
82
|
---
|
|
75
83
|
|
|
@@ -80,7 +88,7 @@ Prerequisites: **Claude Code CLI** (`claude` on `PATH`; install via
|
|
|
80
88
|
[the Claude Code install docs](https://docs.claude.com/claude-code/getting-started)).
|
|
81
89
|
|
|
82
90
|
```bash
|
|
83
|
-
# Install (stable
|
|
91
|
+
# Install (stable v7.0.0)
|
|
84
92
|
npm install @polderlabs/bizar
|
|
85
93
|
|
|
86
94
|
# Or try the latest beta
|
|
@@ -137,19 +145,20 @@ the full agent roster and routing rules.
|
|
|
137
145
|
```
|
|
138
146
|
┌────────────────────────────────────────────────────────────────────┐
|
|
139
147
|
│ Layer 1: UI (bizar-dash/) │
|
|
140
|
-
│ - React + TypeScript dashboard (
|
|
148
|
+
│ - React + TypeScript dashboard (18 tabs) │
|
|
141
149
|
│ - Express server (HTTP + WS) │
|
|
142
150
|
│ - In-process Claude Code Agent SDK (no daemon / no subprocess) │
|
|
143
151
|
│ - Harness engineering dashboard view │
|
|
144
152
|
│ - Kanban board (5 columns + backlog) │
|
|
153
|
+
│ - Custom `ui/` design system (42 components, F-040) │
|
|
145
154
|
└────────────────────────────────────────────────────────────────────┘
|
|
146
155
|
↕ HTTP REST + WebSocket
|
|
147
156
|
┌────────────────────────────────────────────────────────────────────┐
|
|
148
157
|
│ Layer 0: Core (.claude/skills + .claude/agents + plugins/bizar/) │
|
|
149
158
|
│ - Skills (SKILL.md + bundled scripts) │
|
|
150
159
|
│ - Agents (Odin, Frigg, Vör, Mimir, Heimdall, ...) │
|
|
151
|
-
│ - Bizar MCP server (plugins/bizar/,
|
|
152
|
-
│ -
|
|
160
|
+
│ - Bizar MCP server (plugins/bizar/, 23 tools) │
|
|
161
|
+
│ - 7 hooks (PreToolUse × 2, PostToolUse, SessionStart/End, ...) │
|
|
153
162
|
│ - In-process memory vault │
|
|
154
163
|
│ - DANGEROUS_PATTERNS approval gate │
|
|
155
164
|
│ - Skill curator (closed learning loop) │
|
|
@@ -171,33 +180,39 @@ model, module map, and inter-component contracts.
|
|
|
171
180
|
|
|
172
181
|
---
|
|
173
182
|
|
|
174
|
-
## 🛠 Tools (
|
|
183
|
+
## 🛠 Tools (23 total)
|
|
175
184
|
|
|
176
|
-
Bizar's
|
|
185
|
+
Bizar's 23 tools are exposed as a Claude Code MCP server (replacing
|
|
177
186
|
Cline's `createTool` shape with the Claude Code MCP `tool`
|
|
178
187
|
registration shape):
|
|
179
188
|
|
|
180
189
|
| Category | Count | Tools |
|
|
181
190
|
| --- | --- | --- |
|
|
182
|
-
| **
|
|
183
|
-
| **
|
|
184
|
-
| **
|
|
185
|
-
| **
|
|
186
|
-
| **
|
|
187
|
-
| **
|
|
191
|
+
| **Memory** | 4 | `memory_read`, `memory_write`, `memory_list`, `memory_search` |
|
|
192
|
+
| **Plan / Glyphs** | 2 | `plan_action`, `open_kb` |
|
|
193
|
+
| **Loop control** | 4 | `loop_list`, `loop_status`, `loop_start`, `loop_stop` |
|
|
194
|
+
| **Graph / Knowledge** | 3 | `graph_query`, `graph_path`, `graph_explain` |
|
|
195
|
+
| **Agents** | 3 | `agent_spawn`, `agent_list`, `agent_terminate` |
|
|
196
|
+
| **Swarm + routing** | 3 | `swarm_init`, `model_route`, `agent_route` |
|
|
197
|
+
| **Hooks + safety** | 2 | `hooks_route`, `danger_check` |
|
|
198
|
+
| **Distill + consensus + federation** | 2 | `memory_distill`, `consensus_propose`, `federation_status` |
|
|
199
|
+
| **Total** | **23** | All registered as MCP tools via the Claude Code MCP SDK |
|
|
188
200
|
|
|
189
201
|
---
|
|
190
202
|
|
|
191
|
-
## 🪝 Hooks (
|
|
203
|
+
## 🪝 Hooks (7 total)
|
|
192
204
|
|
|
193
205
|
Claude Code-native hooks (typed event payloads, idiomatic shape):
|
|
194
206
|
|
|
195
207
|
| Hook | Purpose |
|
|
196
208
|
| --- | --- |
|
|
197
|
-
| `
|
|
198
|
-
| `
|
|
199
|
-
| `
|
|
200
|
-
| `
|
|
209
|
+
| `pretooluse-bash` | Loop guard + **DANGEROUS_PATTERNS gate** (36 patterns) |
|
|
210
|
+
| `pretooluse-editwrite` | Edit/write pre-flight checks (loop guard, paths) |
|
|
211
|
+
| `posttooluse-editwrite` | Per-edit/write audit log entry |
|
|
212
|
+
| `sessionstart-prime` | Slash command interception + memory prime |
|
|
213
|
+
| `sessionend-recall` | Session-end memory write |
|
|
214
|
+
| `userpromptsubmit-tag` | Prompt tagging + worker suggestion trigger |
|
|
215
|
+
| `worker-suggest` (F-034) | Bizar background-worker dispatch based on prompt text |
|
|
201
216
|
|
|
202
217
|
| Safety component | Purpose |
|
|
203
218
|
| --- | --- |
|
|
@@ -280,9 +295,61 @@ See [docs/graph-tools.md](docs/graph-tools.md) for the full reference.
|
|
|
280
295
|
|
|
281
296
|
---
|
|
282
297
|
|
|
298
|
+
## 🤖 Agents and history dashboard
|
|
299
|
+
|
|
300
|
+
v7.0.0 ships the Agents and History surfaces on the new design
|
|
301
|
+
system. The full data plane:
|
|
302
|
+
|
|
303
|
+
**Server side (fully wired in v7.0.0):**
|
|
304
|
+
|
|
305
|
+
- **11 `/api/agents/*` endpoints** under `bizar-dash/src/server/routes/agents.mjs` —
|
|
306
|
+
list, get, create, update, delete, plus `stuck`, `hierarchy`,
|
|
307
|
+
`invoke`, `status`, `heartbeat`, `restart`.
|
|
308
|
+
- **On-disk status persistence** in `agents-store.mjs` —
|
|
309
|
+
`~/.config/bizar/agent-status.json` survives restarts.
|
|
310
|
+
- **WebSocket broadcast** on every agent mutation
|
|
311
|
+
(`agents:change`).
|
|
312
|
+
- **Stuck detection** + **13-agent hierarchy** (Odin →
|
|
313
|
+
Tyr/Thor/Hermod/Baldr/Mimir → Heimdall/Frigg/Vor; Forseti as
|
|
314
|
+
auditor peer; Vidarr fallback; Quick standalone).
|
|
315
|
+
- **`/api/history`** aggregator — joins `activity-log` + tasks +
|
|
316
|
+
plans + projects with `?since=<iso>` filtering and a 2,000-event
|
|
317
|
+
cap.
|
|
318
|
+
|
|
319
|
+
**UI side (fully wired in v7.0.0):**
|
|
320
|
+
|
|
321
|
+
- **`Agents.tsx`** view (rewritten on F-040 design system) reads
|
|
322
|
+
from `/api/agents`, shows status, tags, category, hierarchy,
|
|
323
|
+
stuck indicators, modals for invoke/restart/delete.
|
|
324
|
+
- **`History.tsx`** view reads `/api/history` with timeline
|
|
325
|
+
rendering.
|
|
326
|
+
|
|
327
|
+
**Live data feed (deferred to v7.1 — was in PR #2):**
|
|
328
|
+
|
|
329
|
+
- Hook-driven status updates as Claude Code tools fire — no hook
|
|
330
|
+
currently POSTs to `/api/agents/:name/status`. Agents show
|
|
331
|
+
"idle" until manually updated.
|
|
332
|
+
- Session-end cleanup of stuck states — no hook flips
|
|
333
|
+
stuck→idle on session end.
|
|
334
|
+
|
|
335
|
+
To push status updates from anywhere today (CLI, scripts, other
|
|
336
|
+
hooks), POST to `/api/agents/:name/status`:
|
|
337
|
+
|
|
338
|
+
```sh
|
|
339
|
+
curl -X POST http://localhost:7842/api/agents/odin/status \
|
|
340
|
+
-H 'content-type: application/json' \
|
|
341
|
+
-d '{"status":"working","currentTaskId":"F-040"}'
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
See [docs/releases/v7.0.0.md](docs/releases/v7.0.0.md) for the
|
|
345
|
+
release notes and [docs/dashboard-ui-migration.md](docs/dashboard-ui-migration.md)
|
|
346
|
+
for the F-040 design-system migration guide.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
283
350
|
## 🛡 Harness engineering audit (73/73)
|
|
284
351
|
|
|
285
|
-
|
|
352
|
+
v7.0.0 passes the full L01–L12 audit at **73/73 = 100%**:
|
|
286
353
|
|
|
287
354
|
| Subsystem | Score |
|
|
288
355
|
| --- | --- |
|
|
@@ -293,7 +360,7 @@ v6.3.0 passes the full L01–L12 audit at **73/73 = 100%**:
|
|
|
293
360
|
| 5. Feedback | 7/7 (`make check/test/e2e/clean-check/arch/vcr/session-*`) |
|
|
294
361
|
| 6. L05 Cross-session | 6/6 (Current State + clock-in/out + context anxiety) |
|
|
295
362
|
| 7. L03 System of record | 4/4 (ACID: Durability, Consistency, Atomicity, Proximity) |
|
|
296
|
-
| 8. L07 WIP=1 + VCR | 3/3 (WIP=1 + `make vcr` + VCR
|
|
363
|
+
| 8. L07 WIP=1 + VCR | 3/3 (WIP=1 + `make vcr` + VCR 39/39 = 1.0) |
|
|
297
364
|
| 9. L08 Feature list | 6/6 (evidence + verify-feature + granularity + state machine) |
|
|
298
365
|
| 10. L09 DoD | 5/5 (3-layer verification + runtime signals + repair instructions) |
|
|
299
366
|
| 11. L10 E2E + Arch | 8/8 (`make e2e` + `make check-arch` + 7 arch rules + E2E requirement) |
|
|
@@ -334,7 +401,18 @@ See [PROGRESS.md](PROGRESS.md) § Current State and the
|
|
|
334
401
|
|
|
335
402
|
---
|
|
336
403
|
|
|
337
|
-
## 🔄 Migration from v6.
|
|
404
|
+
## 🔄 Migration from v6.3.x
|
|
405
|
+
|
|
406
|
+
Upgrading from v6.3.x? The Claude Code migration story is unchanged
|
|
407
|
+
(in-process Agent SDK, MCP tool surface, hook event bag). v7.0.0
|
|
408
|
+
adds the dashboard redesign without changing any plugin surface,
|
|
409
|
+
so existing installations work — the installer just needs
|
|
410
|
+
re-running to pick up the new dashboard assets:
|
|
411
|
+
|
|
412
|
+
```sh
|
|
413
|
+
npm install -g @polderlabs/bizar@latest
|
|
414
|
+
./install.sh
|
|
415
|
+
```
|
|
338
416
|
|
|
339
417
|
Upgrading from a Cline-era BizarHarness (v6.0.0 → v6.2.x)? See
|
|
340
418
|
[docs/migration-guide.md](docs/migration-guide.md) for:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as
|
|
2
|
-
`)})]}),n.status==="error"&&n.error&&e.jsxs("div",{className:"updates-pkg-error",children:[e.jsx(ie,{size:12})," ",n.error]})]},r.id)})}),e.jsxs("div",{className:"updates-actions",children:[e.jsxs(b,{onClick:d,disabled:x,children:[s.checking?e.jsx("span",{className:"btn-spinner"}):e.jsx(O,{size:14}),"Check for updates"]}),e.jsxs(b,{variant:"primary",onClick:i,disabled:!s.hasUpdates||s.updating,children:[s.updating?e.jsx("span",{className:"btn-spinner"}):e.jsx(G,{size:14}),s.updating?"Updating…":s.hasUpdates?"Update now":"Up to date"]}),s.requiresRestart&&e.jsxs(b,{variant:"danger",onClick:p,children:[e.jsx(O,{size:14})," Restart Dashboard"]})]}),s.error&&e.jsxs("div",{className:"updates-error",children:[e.jsx(ie,{size:14}),e.jsx("span",{children:s.error})]})]})}function _e(a,s,{delay:l=800,onSaved:d,onError:i}={}){const[p,x]=c.useState(a),[r,n]=c.useState("idle"),u=c.useRef(null),g=c.useRef(null),j=c.useRef(a),y=c.useRef(!1),S=c.useCallback(async m=>{n("saving");try{await s(m),j.current=m,g.current=null,n("saved"),d==null||d(),setTimeout(()=>n("idle"),2e3)}catch(v){n("error"),i==null||i(v)}},[s,d,i]),L=c.useCallback(m=>{x(m),g.current=m,y.current=!0,u.current&&clearTimeout(u.current),u.current=setTimeout(()=>{u.current=null,y.current=!1;const v=g.current;g.current=null,v!==null&&S(v)},l)},[l,S]),C=c.useCallback(()=>{u.current&&(clearTimeout(u.current),u.current=null,y.current=!1)},[]),h=c.useCallback(async()=>{if(u.current){clearTimeout(u.current),u.current=null,y.current=!1;const m=g.current;g.current=null,m!==null&&await S(m)}},[S]);return c.useEffect(()=>()=>{if(u.current){clearTimeout(u.current),u.current=null;const m=g.current;g.current=null,m!==null&&(n("saving"),s(m).then(()=>{j.current=m,n("saved"),d==null||d()}).catch(v=>{n("error"),i==null||i(v)}).finally(()=>{setTimeout(()=>n("idle"),2e3)}))}},[s,d,i]),{value:p,setValue:L,status:r,save:S,flush:h,clearDebounce:C,hasPendingDebounceRef:y,pendingValueRef:g}}function de({initialValue:a,saveFn:s,delay:l=800,render:d,className:i}){const{value:p,setValue:x,status:r,save:n,clearDebounce:u,hasPendingDebounceRef:g,pendingValueRef:j}=_e(a,s,{delay:l}),y=ye.useCallback(()=>{g.current&&(u(),j.current!==null&&n(j.current))},[u,g,n,j]);return e.jsxs("div",{className:`autosave-field ${i||""} ${r}`,children:[d({value:p,onChange:x,onBlur:y}),e.jsxs("span",{className:"autosave-status",role:"status","aria-live":"polite",children:[r==="saving"&&e.jsx(we,{className:"spinning",size:12}),r==="saved"&&e.jsx(Ne,{size:12}),r==="error"&&e.jsx(me,{size:12})]})]})}const He=[{id:"topnav",label:"Top nav"},{id:"sidebar",label:"Sidebar"},{id:"both",label:"Both"}];function Je({settings:a,patchUi:s,patchTop:l,autoSave:d}){return e.jsxs(e.Fragment,{children:[e.jsxs(E,{id:"settings-layout","data-section":"layout",children:[e.jsxs(B,{children:[e.jsx(Ce,{size:14})," UI layout"]}),e.jsx(P,{children:"Choose how the dashboard's navigation is presented."}),e.jsx("div",{className:"layout-row","data-setting-id":"ui.layout",children:He.map(i=>e.jsx("button",{type:"button",className:T("layout-card",a.ui.layout===i.id&&"layout-card-active"),onClick:()=>s({layout:i.id}),children:e.jsx("span",{className:"layout-card-label",children:i.label})},i.id))}),e.jsxs("label",{className:"checkbox-row","data-setting-id":"ui.showHeader",children:[e.jsx("input",{type:"checkbox",checked:a.ui.showHeader,onChange:i=>s({showHeader:i.target.checked})}),e.jsx("span",{children:"Show header"})]}),e.jsxs("label",{className:"checkbox-row","data-setting-id":"ui.showStatusBar",children:[e.jsx("input",{type:"checkbox",checked:a.ui.showStatusBar,onChange:i=>s({showStatusBar:i.target.checked})}),e.jsx("span",{children:"Show status bar"})]}),e.jsxs("div",{className:"field","data-setting-id":"ui.defaultTab",children:[e.jsx("label",{className:"field-label",children:"Default tab"}),e.jsxs("select",{className:"select",value:a.ui.defaultTab,onChange:i=>s({defaultTab:i.target.value}),children:[e.jsx("option",{value:"overview",children:"Overview"}),e.jsx("option",{value:"chat",children:"Chat"}),e.jsx("option",{value:"agents",children:"Agents"}),e.jsx("option",{value:"artifacts",children:"Plans"}),e.jsx("option",{value:"projects",children:"Projects"}),e.jsx("option",{value:"tasks",children:"Tasks"}),e.jsx("option",{value:"config",children:"Config"}),e.jsx("option",{value:"settings",children:"Settings"}),e.jsx("option",{value:"mods",children:"Mods"}),e.jsx("option",{value:"schedules",children:"Schedules"})]})]})]}),e.jsxs(E,{id:"settings-general","data-section":"general",children:[e.jsx(B,{children:"General"}),e.jsx(P,{children:"Default agent + model override."}),e.jsxs("div",{className:"field","data-setting-id":"defaultAgent",children:[e.jsx("label",{className:"field-label",htmlFor:"set-default-agent",children:"Default agent"}),e.jsx(de,{initialValue:a.defaultAgent||"",saveFn:async i=>{l("defaultAgent",i),d==null||d("defaultAgent",i)},render:({value:i,onChange:p,onBlur:x})=>e.jsx("input",{id:"set-default-agent",className:"input",type:"text",placeholder:"e.g. odin",value:i,onChange:r=>p(r.target.value),onBlur:x})})]}),e.jsxs("div",{className:"field","data-setting-id":"defaultModel",children:[e.jsx("label",{className:"field-label",htmlFor:"set-default-model",children:"Model override"}),e.jsx(de,{initialValue:a.defaultModel||"",saveFn:async i=>{l("defaultModel",i),d==null||d("defaultModel",i)},render:({value:i,onChange:p,onBlur:x})=>e.jsx("input",{id:"set-default-model",className:"input",type:"text",placeholder:"(leave empty for provider default)",value:i,onChange:r=>p(r.target.value),onBlur:x})})]})]})]})}function es({initialStatus:a}){var m;const[s,l]=c.useState(a??null),[d,i]=c.useState(""),[p,x]=c.useState(!1),[r,n]=c.useState(null);c.useEffect(()=>{s===null&&k.get("/tailscale/status").then(v=>l(v)).catch(()=>l(null))},[]);const u=async()=>{try{const v=await k.get("/tailscale/status");l(v)}catch{n("Failed to load Tailscale status")}},g=async()=>{if(d.trim()){x(!0),n(null);try{await k.post("/tailscale/setup",{authKey:d.trim()}),await u(),i("")}catch(v){n(v.message||"Authentication failed")}finally{x(!1)}}},j=async()=>{var v,w,z;if(s){x(!0),n(null);try{await k.post("/tailscale/setup",{port:((v=s.settings)==null?void 0:v.port)||4321,https:((w=s.settings)==null?void 0:w.https)!==!1,hostname:((z=s.settings)==null?void 0:z.hostname)||""}),await u()}catch($){n($.message||"Setup failed")}finally{x(!1)}}},y=async()=>{x(!0),n(null);try{await k.post("/tailscale/unserve"),await u()}catch(v){n(v.message||"Remove failed")}finally{x(!1)}},S=(s==null?void 0:s.installed)??!1,L=(s==null?void 0:s.authenticated)??!1,C=((m=s==null?void 0:s.settings)==null?void 0:m.enabled)??!1,h=C?`https://${(s==null?void 0:s.hostname)||"bizar-dash"}`:null;return S?e.jsxs(E,{id:"settings-tailscale-auth","data-section":"tailscale",children:[e.jsxs(B,{children:[e.jsx(ce,{size:14})," Tailscale Integration"]}),e.jsx(P,{children:"Expose the dashboard over your Tailscale network using an auth key."}),r&&e.jsx("p",{style:{color:"var(--color-error, #f85149)",fontSize:"0.85rem"},children:r}),L?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"status-row",style:{display:"flex",alignItems:"center",gap:"0.5rem",marginBottom:"0.75rem"},children:[e.jsx(V,{size:16,style:{color:"var(--color-success, #3fb950)"}}),e.jsxs("span",{children:["Authenticated as ",e.jsx("strong",{children:(s==null?void 0:s.hostname)||"unknown"})]})]}),C&&h?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"status-row",style:{display:"flex",alignItems:"center",gap:"0.5rem",marginBottom:"0.75rem"},children:[e.jsx(Se,{size:16}),e.jsx("a",{href:h,target:"_blank",rel:"noreferrer",children:h})]}),e.jsx(b,{variant:"secondary",size:"sm",onClick:y,disabled:p,children:"Remove serve"})]}):e.jsx(b,{variant:"primary",size:"sm",onClick:j,disabled:p,children:"Set up Tailscale serve"})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"muted",style:{marginBottom:"0.75rem"},children:"Not authenticated with Tailscale."}),e.jsxs("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap"},children:[e.jsx("input",{type:"text",className:"input",placeholder:"tskey-...",value:d,onChange:v=>i(v.target.value),style:{flex:1,minWidth:"200px"},disabled:p}),e.jsx(b,{variant:"primary",size:"sm",onClick:g,disabled:p||!d.trim(),children:"Authenticate"})]})]})]}):e.jsxs(E,{id:"settings-tailscale-auth","data-section":"tailscale",children:[e.jsxs(B,{children:[e.jsx(ce,{size:14})," Tailscale Integration"]}),e.jsx(P,{children:"Tailscale is not installed on this machine."}),e.jsxs("p",{className:"muted",children:["Install from"," ",e.jsx("a",{href:"https://tailscale.com/download",target:"_blank",rel:"noreferrer",children:"tailscale.com/download"})]})]})}function ss({settings:a,patchTop:s}){var l,d,i;return e.jsxs(E,{id:"settings-system-llm","data-section":"system-llm",children:[e.jsxs(B,{children:[e.jsx(ze,{size:14})," System LLM API"]}),e.jsx(P,{children:"Configures the LLM used for automatic title generation, prompt enhancement, summarization, and other system-level calls."}),e.jsxs("label",{className:"checkbox-row","data-setting-id":"systemLlm.enabled",children:[e.jsx("input",{type:"checkbox",checked:!!((l=a.systemLlm)!=null&&l.enabled),onChange:p=>{const x=a.systemLlm||{enabled:!0,provider:"cline",model:"cline/deepseek-v4-flash-free"};s("systemLlm",{...x,enabled:p.target.checked})}}),e.jsx("span",{children:"Enable system LLM calls"})]}),e.jsxs("div",{className:"field","data-setting-id":"systemLlm.provider",style:{marginTop:"var(--space-3)"},children:[e.jsx("label",{className:"field-label",htmlFor:"set-system-llm-provider",children:"Provider"}),e.jsxs("select",{id:"set-system-llm-provider",className:"select",value:((d=a.systemLlm)==null?void 0:d.provider)||"cline",onChange:p=>{const x=a.systemLlm||{enabled:!0,provider:"cline",model:"cline/deepseek-v4-flash-free"};s("systemLlm",{...x,provider:p.target.value})},children:[e.jsx("option",{value:"cline",children:"Cline"}),e.jsx("option",{value:"openrouter",children:"OpenRouter"}),e.jsx("option",{value:"minimax",children:"MiniMax"})]})]}),e.jsxs("div",{className:"field","data-setting-id":"systemLlm.model",children:[e.jsx("label",{className:"field-label",htmlFor:"set-system-llm-model",children:"Model"}),e.jsx("input",{id:"set-system-llm-model",className:"input mono",type:"text",placeholder:"cline/deepseek-v4-flash-free",value:((i=a.systemLlm)==null?void 0:i.model)||"cline/deepseek-v4-flash-free",onChange:p=>{const x=a.systemLlm||{enabled:!0,provider:"cline",model:"cline/deepseek-v4-flash-free"};s("systemLlm",{...x,model:p.target.value})}}),e.jsxs("p",{className:"field-help",children:["The API key is read from ",e.jsx("code",{children:"auth.json"})," for the selected provider. Leave the default model for best results."]})]}),e.jsxs("div",{style:{marginTop:"var(--space-4)"},children:[e.jsx("h4",{style:{margin:"0 0 var(--space-2)"},children:"Features using this API"}),e.jsxs("ul",{className:"settings-feature-list",style:{margin:0,paddingLeft:"var(--space-4)",lineHeight:1.8},children:[e.jsx("li",{children:"Auto-title generation for new chat sessions"}),e.jsx("li",{children:"Auto-title generation for new tasks"}),e.jsx("li",{children:'"Enhance prompt" button in the task input'}),e.jsx("li",{children:'"Enhance prompt" button in the chat composer'}),e.jsx("li",{className:"muted",style:{fontSize:12},children:"Future: summarization, name generation, and more"})]})]})]})}const Ve=[{value:"anthropic",label:"Anthropic"},{value:"anyllm",label:"AnyLLM"},{value:"litellm-anthropic",label:"LiteLLM (Anthropic)"},{value:"litellm-openai",label:"LiteLLM (OpenAI)"}];function Oe({settings:a,onPatch:s}){const l=Y(),[d,i]=c.useState(null),[p,x]=c.useState(null),[r,n]=c.useState(!1),[u,g]=c.useState(!1),[j,y]=c.useState(!1),[S,L]=c.useState(!1),[C,h]=c.useState(!1),[m,v]=c.useState(!1),w=c.useCallback(async()=>{n(!0);try{const[o,U]=await Promise.all([k.get("/headroom/status"),k.get("/headroom/stats?hours=24").catch(()=>({error:"no stats"}))]);i(o),U.error||x(U)}catch(o){l.error(`Failed to load Headroom status: ${o.message}`)}finally{n(!1)}},[l]);c.useEffect(()=>{w()},[w]);const z=async()=>{g(!0);try{const o=await k.post("/headroom/install",{force:!0});o.installed?(l.success(`Headroom installed via ${o.method}.`),await w()):l.error('Headroom install failed. Try: pip install "headroom-ai[all]"')}catch(o){l.error(`Install failed: ${o.message}`)}finally{g(!1)}},$=async()=>{y(!0);try{(await k.post("/headroom/wrap",{port:a.port})).ok?(l.success("cline wrapped with Headroom."),await w()):l.error("Wrap failed.")}catch(o){l.error(`Wrap failed: ${o.message}`)}finally{y(!1)}},_=async()=>{L(!0);try{(await k.post("/headroom/unwrap")).ok?(l.success("cline unwrapped from Headroom."),await w()):l.error("Unwrap failed.")}catch(o){l.error(`Unwrap failed: ${o.message}`)}finally{L(!1)}},W=async()=>{h(!0);try{(await k.post("/headroom/proxy/start",{port:a.port,host:a.host})).ok?(l.success(`Headroom proxy started on ${a.host}:${a.port}.`),await w()):l.error("Proxy start failed.")}catch(o){l.error(`Proxy start failed: ${o.message}`)}finally{h(!1)}},K=async()=>{v(!0);try{(await k.post("/headroom/proxy/stop")).ok?(l.success("Headroom proxy stopped."),await w()):l.error("Proxy stop failed.")}catch(o){l.error(`Proxy stop failed: ${o.message}`)}finally{v(!1)}},Z=async()=>{try{const{spawn:o}=await ke(async()=>{const{spawn:U}=await import("./__vite-browser-external-BIHI7g3E.js");return{spawn:U}},[]);o("headroom",["dashboard"],{detached:!0,stdio:"ignore"})}catch{l.error("Could not open Headroom dashboard. Run `headroom dashboard` manually.")}},{installed:R,version:q,proxyRunning:M,proxyPort:X,wrapped:A}=d||{},H=(p==null?void 0:p.compressionRatio)??0,D=(p==null?void 0:p.tokensSaved)??0;return e.jsx("div",{id:"settings-headroom","data-section":"headroom",children:e.jsxs(E,{children:[e.jsxs(B,{children:[e.jsx(pe,{size:14,style:{color:M?"var(--success)":"var(--text-dim)"}}),"Headroom",R&&q&&e.jsxs("span",{style:{fontSize:11,color:"var(--text-dim)",marginLeft:6},children:["v",q," ",M?"✓":"✗"]}),!R&&e.jsx("span",{style:{fontSize:11,color:"var(--error)",marginLeft:6},children:"not installed"})]}),e.jsx(P,{children:"Context compression for token efficiency. Compresses tool outputs, logs, and conversation history by 60–95% before they reach the model."}),e.jsxs("div",{style:{display:"flex",gap:16,flexWrap:"wrap",marginTop:12,marginBottom:12},children:[e.jsxs("div",{className:"headroom-status-item",children:[R?e.jsx(V,{size:12,style:{color:"var(--success)"}}):e.jsx(se,{size:12,style:{color:"var(--error)"}}),e.jsx("span",{children:R?"Installed":"Not installed"})]}),e.jsxs("div",{className:"headroom-status-item",children:[M?e.jsx(V,{size:12,style:{color:"var(--success)"}}):e.jsx(se,{size:12,style:{color:"var(--text-dim)"}}),e.jsxs("span",{children:["Proxy ",M?`${X} ✓`:"stopped"]})]}),e.jsxs("div",{className:"headroom-status-item",children:[A?e.jsx(V,{size:12,style:{color:"var(--success)"}}):e.jsx(se,{size:12,style:{color:"var(--text-dim)"}}),e.jsxs("span",{children:["cline ",A?"wrapped":"not wrapped"]})]})]}),(D>0||H>0)&&e.jsxs("div",{style:{display:"flex",gap:24,marginBottom:12},children:[e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:20,fontWeight:700,color:"var(--success)"},children:H>0?`${Math.round(H*100)}%`:"—"}),e.jsx("div",{className:"muted",style:{fontSize:11},children:"Compression ratio"})]}),e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:20,fontWeight:700,color:"var(--accent)"},children:D>0?D.toLocaleString():"—"}),e.jsx("div",{className:"muted",style:{fontSize:11},children:"Tokens saved (24h)"})]})]}),e.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:8},children:[R?e.jsxs(e.Fragment,{children:[e.jsxs(b,{variant:"secondary",size:"sm",onClick:$,disabled:j||A,title:A?"cline is already wrapped":"Wrap cline to route through Headroom proxy",children:[j?e.jsx("span",{className:"btn-spinner"}):e.jsx(Ae,{size:13}),j?"Wrapping…":A?"Wrapped ✓":"Wrap cline"]}),A&&e.jsxs(b,{variant:"ghost",size:"sm",onClick:_,disabled:S,children:[S?e.jsx("span",{className:"btn-spinner"}):e.jsx(O,{size:13}),S?"Unwrapping…":"Unwrap"]})]}):e.jsxs(b,{variant:"primary",size:"sm",onClick:z,disabled:u,children:[u?e.jsx("span",{className:"btn-spinner"}):e.jsx(G,{size:13}),u?"Installing…":"Install Headroom"]}),R&&e.jsxs(e.Fragment,{children:[M?e.jsxs(b,{variant:"secondary",size:"sm",onClick:K,disabled:m,children:[m?e.jsx("span",{className:"btn-spinner"}):e.jsx(Re,{size:13}),m?"Stopping…":"Stop proxy"]}):e.jsxs(b,{variant:"secondary",size:"sm",onClick:W,disabled:C,children:[C?e.jsx("span",{className:"btn-spinner"}):e.jsx(Le,{size:13}),C?"Starting…":"Start proxy"]}),e.jsxs(b,{variant:"ghost",size:"sm",onClick:Z,children:[e.jsx(Ie,{size:13}),"Dashboard"]})]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:w,disabled:r,children:e.jsx(O,{size:13,className:r?"spin":""})})]}),e.jsxs("div",{style:{marginTop:16},children:[e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.enabled,onChange:o=>s({enabled:o.target.checked})}),e.jsx("span",{children:"Enable Headroom"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.autoInstall,onChange:o=>s({autoInstall:o.target.checked})}),e.jsx("span",{children:"Auto-install if missing on dashboard startup"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.autoStart,onChange:o=>s({autoStart:o.target.checked})}),e.jsx("span",{children:"Auto-start proxy on dashboard startup"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.autoWrap,onChange:o=>s({autoWrap:o.target.checked})}),e.jsx("span",{children:"Auto-wrap cline on dashboard startup"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.routeAllProviders,onChange:o=>s({routeAllProviders:o.target.checked})}),e.jsx("span",{children:"Route all providers through Headroom proxy"})]}),e.jsxs("div",{className:"task-form-row",style:{marginTop:12},children:[e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Proxy port"}),e.jsx("input",{type:"number",className:"input",value:a.port,min:1,max:65535,onChange:o=>s({port:Math.max(1,Math.min(65535,parseInt(o.target.value,10)||8787))})})]}),e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Proxy host"}),e.jsx("input",{type:"text",className:"input",value:a.host,onChange:o=>s({host:o.target.value})})]})]}),e.jsxs("div",{className:"task-form-row",children:[e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Backend"}),e.jsx("select",{className:"select",value:a.backend,onChange:o=>s({backend:o.target.value}),children:Ve.map(o=>e.jsx("option",{value:o.value,children:o.label},o.value))})]}),e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Monthly budget (USD)"}),e.jsx("input",{type:"number",className:"input",value:a.budget,min:0,step:1,onChange:o=>s({budget:Math.max(0,parseFloat(o.target.value)||0)})}),e.jsx("span",{className:"field-help",children:"0 = unlimited"})]})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.outputShaper,onChange:o=>s({outputShaper:o.target.checked})}),e.jsx("span",{children:"Enable output shaper"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.telemetry,onChange:o=>s({telemetry:o.target.checked})}),e.jsx("span",{children:"Enable telemetry"})]})]})]})})}const ue={enabled:!0,autoInstall:!0,port:8787,host:"127.0.0.1",outputShaper:!1,telemetry:!1,budget:0,backend:"anthropic",autoStart:!0,autoWrap:!0,routeAllProviders:!0};function as({settings:a,setSettings:s,setDirty:l}){return e.jsx(Oe,{settings:a.headroom||ue,onPatch:d=>{s(i=>({...i,headroom:{...i.headroom||ue,...d}})),l(!0)}})}function Fe(){const a=Y(),[s,l]=c.useState([]),[d,i]=c.useState(new Set),[p,x]=c.useState(!0),[r,n]=c.useState(""),[u,g]=c.useState(!0),j=c.useCallback(async()=>{x(!0);try{const[h,m]=await Promise.all([k.get("/activity"),k.get("/activity/hidden")]);l(Array.isArray(h.items)?h.items:[]),i(new Set(m.hidden||[]))}catch(h){a.error(`Load failed: ${h.message}`)}finally{x(!1)}},[a]);c.useEffect(()=>{j()},[j]);const y=(h,m)=>{const v=`${h.kind||""}|${h.ts||""}|${h.slug||""}|${m}`;let w=0;for(let z=0;z<v.length;z++)w=(w<<5)-w+v.charCodeAt(z)|0;return Math.abs(w).toString(16).padStart(8,"0").slice(0,16)},S=async()=>{try{await k.del("/activity/hide"),i(new Set),a.success("All hidden activity restored.")}catch(h){a.error(`Restore failed: ${h.message}`)}},L=async h=>{try{await k.del(`/activity/hide/${encodeURIComponent(h)}`);const m=new Set(d);m.delete(h),i(m)}catch(m){a.error(`Restore failed: ${m.message}`)}},C=s.filter((h,m)=>{const v=y(h,m);if(!u&&d.has(v))return!1;if(!r)return!0;const w=r.toLowerCase();return[h.kind,h.slug,h.message].some(z=>typeof z=="string"&&z.toLowerCase().includes(w))});return e.jsxs(E,{id:"settings-activity-log","data-section":"activity-log",children:[e.jsxs(B,{children:[e.jsx(pe,{size:14})," Activity log",e.jsxs("span",{className:"muted",style:{fontWeight:400,marginLeft:8,fontSize:12},children:[s.length," total · ",d.size," hidden"]}),e.jsx(b,{variant:"ghost",size:"sm",style:{marginLeft:"auto"},onClick:j,title:"Reload",children:e.jsx(O,{size:12})})]}),e.jsxs(P,{children:["Full history from ",e.jsx("code",{children:"~/.bizar/activity.log"}),". Hiding an item in the Overview only hides it there — the entry stays here."]}),e.jsxs("div",{className:"activity-log-toolbar",children:[e.jsxs("div",{className:"activity-log-search",children:[e.jsx(te,{size:12}),e.jsx("input",{type:"text",className:"input",placeholder:"Filter by kind, slug, or message…",value:r,onChange:h=>n(h.target.value)})]}),e.jsxs("label",{className:"activity-log-toggle",children:[e.jsx("input",{type:"checkbox",checked:u,onChange:h=>g(h.target.checked)}),"Show hidden"]}),e.jsxs(b,{variant:"ghost",size:"sm",disabled:d.size===0,onClick:S,title:"Restore all hidden items to the Overview",children:[e.jsx(ne,{size:12})," Restore all"]})]}),p?e.jsx("div",{className:"muted",style:{padding:"12px 0",fontSize:12},children:"Loading…"}):C.length===0?e.jsx("div",{className:"muted",style:{padding:"12px 0",fontSize:12},children:s.length===0?"No activity yet.":"No items match the current filter."}):e.jsxs("div",{className:"activity-log-table-wrap",children:[e.jsxs("table",{className:"activity-log-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Kind"}),e.jsx("th",{children:"Detail"}),e.jsx("th",{children:"Time"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:C.slice(0,200).map((h,m)=>{const v=y(h,m),w=d.has(v);return e.jsxs("tr",{className:T(w&&"activity-log-row-hidden"),children:[e.jsx("td",{className:"activity-log-kind",children:h.kind||"activity"}),e.jsx("td",{className:"activity-log-detail",children:h.message||h.slug||"—"}),e.jsx("td",{className:"activity-log-time mono",children:h.ts?new Date(h.ts).toLocaleString():"—"}),e.jsx("td",{children:w?e.jsx(b,{variant:"ghost",size:"sm",onClick:()=>L(v),title:"Restore to Overview",children:e.jsx(ne,{size:12})}):e.jsx("span",{className:"activity-log-state-tag",children:"shown"})})]},`${h.ts}-${m}`)})})]}),C.length>200&&e.jsxs("div",{className:"muted",style:{fontSize:11,padding:"8px 0"},children:["Showing first 200 of ",C.length,"."]})]})]})}function We({about:a}){return e.jsxs(E,{id:"settings-about","data-section":"about",children:[e.jsxs(B,{children:[e.jsx(Ee,{size:14})," About"]}),e.jsx(P,{children:"Build metadata."}),e.jsxs("dl",{className:"about-table",children:[e.jsx("dt",{children:"Version"}),e.jsx("dd",{className:"mono",children:(a==null?void 0:a.version)||"—"}),e.jsx("dt",{children:"Homepage"}),e.jsx("dd",{children:e.jsx("a",{href:(a==null?void 0:a.homepage)||"https://github.com/DrB0rk/BizarHarness",target:"_blank",rel:"noopener noreferrer",children:(a==null?void 0:a.homepage)||"https://github.com/DrB0rk/BizarHarness"})}),e.jsx("dt",{children:"License"}),e.jsx("dd",{children:(a==null?void 0:a.license)||"MIT"})]})]})}function ts({about:a}){return e.jsxs(e.Fragment,{children:[e.jsx(Fe,{}),e.jsx(We,{about:a})]})}function Ke({onError:a}){const s=Y(),[l,d]=c.useState([]),[i,p]=c.useState(!1),[x,r]=c.useState(!1),[n,u]=c.useState(new Set),[g,j]=c.useState(null),[y,S]=c.useState(""),[L,C]=c.useState(!1),[h,m]=c.useState(""),[v,w]=c.useState(""),[z,$]=c.useState(!1),[_,W]=c.useState(""),[K,Z]=c.useState(!1),[R,q]=c.useState(""),[M,X]=c.useState(new Set),A=c.useCallback(async()=>{p(!0);try{const t=await k.get("/env-vars");d(t)}catch(t){s.error(`Load failed: ${t.message}`),a==null||a(t.message)}finally{p(!1)}},[s,a]);c.useEffect(()=>{A()},[A]);const H=t=>{u(N=>{const f=new Set(N);return f.has(t)?f.delete(t):f.add(t),f})},D=async()=>{const t=h.trim().toUpperCase(),N=v.trim();if(!t||!/^BIZAR_[A-Z0-9_]+$/.test(t)){s.warning("Name must match BIZAR_<NAME> (e.g. BIZAR_MINIMAX_KEY)");return}if(!N){s.warning("Value is required.");return}if(l.some(f=>f.name===t)){s.warning(`${t} already exists.`);return}r(!0);try{await k.post("/env-vars",{name:t,value:N}),s.success(`${t} created.`),C(!1),m(""),w(""),await A()}catch(f){s.error(`Create failed: ${f.message}`)}finally{r(!1)}},o=t=>{j(t.name),S(t.value===t.value.replace(/\*/g,"")?t.value:""),u(N=>{const f=new Set(N);return f.add(t.name),f})},U=async t=>{if(!y.trim()){s.warning("Value cannot be empty.");return}r(!0);try{await k.put(`/env-vars/${encodeURIComponent(t)}`,{value:y.trim()}),s.success(`${t} updated.`),j(null),await A()}catch(N){s.error(`Update failed: ${N.message}`)}finally{r(!1)}},re=async t=>{if(confirm(`Delete ${t}? This cannot be undone.`))try{await k.del(`/env-vars/${encodeURIComponent(t)}`),s.success(`${t} deleted.`),await A()}catch(N){s.error(`Delete failed: ${N.message}`)}},ge=async()=>{if(!_.trim()){s.warning("Nothing to import.");return}Z(!0);try{const t=await k.post("/env-vars/bulk-import",{envContent:_});s.success(`Imported ${t.imported}, skipped ${t.skipped}.`),t.errors.length>0&&s.warning(`${t.errors.length} lines had errors: ${t.errors.slice(0,3).join("; ")}${t.errors.length>3?"…":""}`),W(""),$(!1),await A()}catch(t){s.error(`Bulk import failed: ${t.message}`)}finally{Z(!1)}},je=async()=>{try{const t=await k.get("/env-vars/export"),N=new Blob([t],{type:"text/plain"}),f=URL.createObjectURL(N),I=document.createElement("a");I.href=f,I.download=".env",I.click(),URL.revokeObjectURL(f),s.success("Exported .env file.")}catch(t){s.error(`Export failed: ${t.message}`)}},F=c.useMemo(()=>{if(!R.trim())return l;const t=R.toLowerCase();return l.filter(N=>N.name.toLowerCase().includes(t))},[l,R]),Q=c.useMemo(()=>{const t={};for(const N of F){const f=N.name.split("_")[0]+"_";(t[f]??(t[f]=[])).push(N)}return t},[F]),ve=t=>{X(N=>{const f=new Set(N);return f.has(t)?f.delete(t):f.add(t),f})},le=c.useMemo(()=>{const t=["BIZAR_","PROVIDER_","MODEL_","API_"];return Object.keys(Q).sort((f,I)=>{const J=t.indexOf(f),ee=t.indexOf(I);return J===-1&&ee===-1?f.localeCompare(I):J===-1?1:ee===-1?-1:J-ee})},[Q]);if(i)return e.jsx("div",{className:"muted",style:{padding:"16px 0",fontSize:13},children:"Loading env vars…"});const fe=le.length>1;return e.jsxs("div",{className:"env-var-manager",children:[e.jsxs("div",{className:"env-var-toolbar",children:[e.jsxs(b,{variant:"primary",size:"sm",onClick:()=>C(!0),children:[e.jsx(Be,{size:12})," New variable"]}),e.jsxs(b,{variant:"secondary",size:"sm",onClick:()=>$(t=>!t),className:z?"active":"",children:[e.jsx(Pe,{size:12})," Bulk import"]}),e.jsxs(b,{variant:"ghost",size:"sm",onClick:je,title:"Export as .env",children:[e.jsx(G,{size:12})," Export"]}),e.jsxs("div",{className:"env-var-search-wrap",children:[e.jsx(te,{size:12,className:"env-var-search-icon"}),e.jsx("input",{className:"env-var-search input",placeholder:"Filter…",value:R,onChange:t=>q(t.target.value)})]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:A,title:"Reload",children:e.jsx(O,{size:12})})]}),z&&e.jsxs("div",{className:"env-var-bulk-panel",children:[e.jsxs("div",{className:"env-var-bulk-header",children:[e.jsxs("span",{children:["Paste ",e.jsx("code",{children:"KEY=value"})," lines (one per line):"]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:()=>$(!1),children:e.jsx(oe,{size:12})})]}),e.jsx("textarea",{className:"input mono env-var-bulk-textarea",placeholder:`BIZAR_API_KEY=your-key-here
|
|
1
|
+
import{r as o,j as e,R as ye}from"./react-vendor-D3pra6w-.js";import{u as Y}from"./Toast-WTxc3m2g.js";import{c as T,W as be,a as k,_ as ke}from"./mobile-layout-Ckru3HKJ.js";import{ae as G,bf as V,C as me,E as ie,R as O,bg as we,D as Ne,bh as Ce,aB as ce,bi as Se,i as ze,g as pe,aj as se,a6 as Ae,b1 as Re,ag as Le,Z as Ie,r as te,a4 as ne,J as Ee,t as Be,aY as Pe,X as oe,aC as xe,e as Te,d as $e,a3 as Me,ad as De,a9 as Ue}from"./icons-B0AKnYI3.js";const b=o.forwardRef(function({variant:s="secondary",size:l="md",iconOnly:c=!1,loading:r=!1,disabled:p,className:x,children:i,...n},u){return e.jsxs("button",{ref:u,type:n.type??"button",disabled:p||r,className:T("btn",`btn-${s}`,`btn-size-${l}`,c&&"btn-icon",r&&"btn-loading",x),...n,children:[r?e.jsx("span",{className:"btn-spinner","aria-hidden":!0}):null,i]})});function Qe(...a){const s=[],l=c=>{if(c){if(typeof c=="string"||typeof c=="number"){s.push(String(c));return}if(Array.isArray(c)){for(const r of c)l(r);return}if(typeof c=="object")for(const r in c)c[r]&&s.push(r)}};for(const c of a)l(c);return s.join(" ")}function E({variant:a="elevated",interactive:s=!1,className:l,children:c,...r}){return e.jsx("div",{className:T("card",`card-${a}`,s&&"card-interactive",l),...r,children:c})}function B({children:a,className:s}){return e.jsx("h3",{className:T("card-title",s),children:a})}function P({children:a,className:s}){return e.jsx("div",{className:T("card-meta",s),children:a})}const ae=[{id:"bizar",name:"Bizar CLI"},{id:"bizar-dash",name:"Dashboard"},{id:"bizar-plugin",name:"Opencode Plugin"}];function Je(){const a=Y(),[s,l]=o.useState({current:{},latest:null,checking:!1,updating:!1,hasUpdates:!1,requiresRestart:!1,perPackage:{}});o.useEffect(()=>{const i=new be;return i.on(n=>{(n.type==="update:progress"||n.type==="update:log"||n.type==="update:complete")&&l(u=>{if(n.type==="update:complete")return{...u,updating:!1,requiresRestart:!!n.requiresRestart};if(n.type==="update:log"){const j=n,y=u.perPackage[j.pkg]||{logs:[]};return{...u,perPackage:{...u.perPackage,[j.pkg]:{...y,logs:[...(y.logs||[]).slice(-50),j.line]}}}}const g=n;return{...u,perPackage:{...u.perPackage,[g.pkg]:{...u.perPackage[g.pkg],status:g.status,error:g.error,newVersion:g.newVersion}}}})}),()=>i.close()},[]),o.useEffect(()=>{k.get("/updates/status").then(i=>l(n=>({...n,current:i.current}))).catch(i=>l(n=>({...n,error:i.message})))},[]);const c=async()=>{l(i=>({...i,checking:!0,error:void 0}));try{const i=await k.get("/updates/check");l(n=>({...n,checking:!1,current:i.current,latest:i.latest,hasUpdates:i.hasUpdates}))}catch(i){l(n=>({...n,checking:!1,error:i.message}))}},r=async()=>{if(confirm("Update Bizar packages? The dashboard will restart automatically.")){l(i=>({...i,updating:!0,requiresRestart:!1,perPackage:{},error:void 0}));try{await k.post("/updates/apply",{packages:["bizar","bizar-dash","bizar-plugin"]})}catch(i){l(n=>({...n,updating:!1,error:i.message}))}}},p=async()=>{if(confirm("Restart the dashboard? You will be disconnected briefly."))try{await k.post("/restart"),a.info("Restarting…",3e3),setTimeout(()=>window.location.reload(),3e3)}catch{a.error("Restart failed")}},x=s.checking||s.updating;return e.jsxs(E,{id:"settings-updates","data-section":"updates",children:[e.jsxs(B,{children:[e.jsx(G,{size:14})," Updates"]}),e.jsx(P,{children:"Check installed Bizar packages and apply dashboard updates."}),e.jsxs("div",{className:"updates-current",children:[e.jsx("h4",{children:"Installed versions"}),e.jsx("ul",{children:ae.map(i=>e.jsxs("li",{children:[e.jsx("span",{children:i.name}),e.jsx("code",{className:"mono",children:s.current[i.id]||"—"})]},i.id))})]}),s.latest&&e.jsxs("div",{className:"updates-latest",children:[e.jsx("h4",{children:"Latest available"}),e.jsx("ul",{children:ae.map(i=>{var j;const n=s.current[i.id],u=(j=s.latest)==null?void 0:j[i.id],g=n&&u&&n!==u;return e.jsxs("li",{className:g?"updates-outdated":"updates-current-version",children:[e.jsx("span",{children:i.name}),e.jsxs("code",{className:"mono",children:[u||"—",g&&e.jsx("span",{className:"updates-badge",children:"update available"})]})]},i.id)})})]}),s.updating&&e.jsx("div",{className:"updates-progress-rows",children:ae.map(i=>{const n=s.perPackage[i.id]||{status:"idle",logs:[]};return e.jsxs("div",{className:"updates-pkg-row",children:[e.jsxs("div",{className:"updates-pkg-row-header",children:[e.jsx("span",{className:"updates-pkg-name",children:i.name}),e.jsxs("div",{className:"updates-pkg-status",children:[n.status==="starting"&&e.jsx("span",{className:"btn-spinner"}),n.status==="installing"&&e.jsx("span",{className:"btn-spinner"}),n.status==="done"&&e.jsx(V,{size:14,className:"icon-success"}),n.status==="error"&&e.jsx(me,{size:14,className:"icon-error"}),e.jsx("span",{children:n.status}),n.newVersion&&e.jsxs("code",{className:"mono",style:{fontSize:11},children:["→ ",n.newVersion]})]})]}),n.logs.length>0&&e.jsxs("details",{className:"updates-pkg-logs",children:[e.jsxs("summary",{children:["npm output (",n.logs.length," lines)"]}),e.jsx("pre",{children:n.logs.join(`
|
|
2
|
+
`)})]}),n.status==="error"&&n.error&&e.jsxs("div",{className:"updates-pkg-error",children:[e.jsx(ie,{size:12})," ",n.error]})]},i.id)})}),e.jsxs("div",{className:"updates-actions",children:[e.jsxs(b,{onClick:c,disabled:x,children:[s.checking?e.jsx("span",{className:"btn-spinner"}):e.jsx(O,{size:14}),"Check for updates"]}),e.jsxs(b,{variant:"primary",onClick:r,disabled:!s.hasUpdates||s.updating,children:[s.updating?e.jsx("span",{className:"btn-spinner"}):e.jsx(G,{size:14}),s.updating?"Updating…":s.hasUpdates?"Update now":"Up to date"]}),s.requiresRestart&&e.jsxs(b,{variant:"danger",onClick:p,children:[e.jsx(O,{size:14})," Restart Dashboard"]})]}),s.error&&e.jsxs("div",{className:"updates-error",children:[e.jsx(ie,{size:14}),e.jsx("span",{children:s.error})]})]})}function _e(a,s,{delay:l=800,onSaved:c,onError:r}={}){const[p,x]=o.useState(a),[i,n]=o.useState("idle"),u=o.useRef(null),g=o.useRef(null),j=o.useRef(a),y=o.useRef(!1),S=o.useCallback(async m=>{n("saving");try{await s(m),j.current=m,g.current=null,n("saved"),c==null||c(),setTimeout(()=>n("idle"),2e3)}catch(f){n("error"),r==null||r(f)}},[s,c,r]),L=o.useCallback(m=>{x(m),g.current=m,y.current=!0,u.current&&clearTimeout(u.current),u.current=setTimeout(()=>{u.current=null,y.current=!1;const f=g.current;g.current=null,f!==null&&S(f)},l)},[l,S]),C=o.useCallback(()=>{u.current&&(clearTimeout(u.current),u.current=null,y.current=!1)},[]),h=o.useCallback(async()=>{if(u.current){clearTimeout(u.current),u.current=null,y.current=!1;const m=g.current;g.current=null,m!==null&&await S(m)}},[S]);return o.useEffect(()=>()=>{if(u.current){clearTimeout(u.current),u.current=null;const m=g.current;g.current=null,m!==null&&(n("saving"),s(m).then(()=>{j.current=m,n("saved"),c==null||c()}).catch(f=>{n("error"),r==null||r(f)}).finally(()=>{setTimeout(()=>n("idle"),2e3)}))}},[s,c,r]),{value:p,setValue:L,status:i,save:S,flush:h,clearDebounce:C,hasPendingDebounceRef:y,pendingValueRef:g}}function de({initialValue:a,saveFn:s,delay:l=800,render:c,className:r}){const{value:p,setValue:x,status:i,save:n,clearDebounce:u,hasPendingDebounceRef:g,pendingValueRef:j}=_e(a,s,{delay:l}),y=ye.useCallback(()=>{g.current&&(u(),j.current!==null&&n(j.current))},[u,g,n,j]);return e.jsxs("div",{className:`autosave-field ${r||""} ${i}`,children:[c({value:p,onChange:x,onBlur:y}),e.jsxs("span",{className:"autosave-status",role:"status","aria-live":"polite",children:[i==="saving"&&e.jsx(we,{className:"spinning",size:12}),i==="saved"&&e.jsx(Ne,{size:12}),i==="error"&&e.jsx(me,{size:12})]})]})}const He=[{id:"topnav",label:"Top nav"},{id:"sidebar",label:"Sidebar"},{id:"both",label:"Both"}];function es({settings:a,patchUi:s,patchTop:l,autoSave:c}){return e.jsxs(e.Fragment,{children:[e.jsxs(E,{id:"settings-layout","data-section":"layout",children:[e.jsxs(B,{children:[e.jsx(Ce,{size:14})," UI layout"]}),e.jsx(P,{children:"Choose how the dashboard's navigation is presented."}),e.jsx("div",{className:"layout-row","data-setting-id":"ui.layout",children:He.map(r=>e.jsx("button",{type:"button",className:T("layout-card",a.ui.layout===r.id&&"layout-card-active"),onClick:()=>s({layout:r.id}),children:e.jsx("span",{className:"layout-card-label",children:r.label})},r.id))}),e.jsxs("label",{className:"checkbox-row","data-setting-id":"ui.showHeader",children:[e.jsx("input",{type:"checkbox",checked:a.ui.showHeader,onChange:r=>s({showHeader:r.target.checked})}),e.jsx("span",{children:"Show header"})]}),e.jsxs("label",{className:"checkbox-row","data-setting-id":"ui.showStatusBar",children:[e.jsx("input",{type:"checkbox",checked:a.ui.showStatusBar,onChange:r=>s({showStatusBar:r.target.checked})}),e.jsx("span",{children:"Show status bar"})]}),e.jsxs("div",{className:"field","data-setting-id":"ui.defaultTab",children:[e.jsx("label",{className:"field-label",children:"Default tab"}),e.jsxs("select",{className:"select",value:a.ui.defaultTab,onChange:r=>s({defaultTab:r.target.value}),children:[e.jsx("option",{value:"overview",children:"Overview"}),e.jsx("option",{value:"chat",children:"Chat"}),e.jsx("option",{value:"agents",children:"Agents"}),e.jsx("option",{value:"artifacts",children:"Plans"}),e.jsx("option",{value:"projects",children:"Projects"}),e.jsx("option",{value:"tasks",children:"Tasks"}),e.jsx("option",{value:"config",children:"Config"}),e.jsx("option",{value:"settings",children:"Settings"}),e.jsx("option",{value:"mods",children:"Mods"}),e.jsx("option",{value:"schedules",children:"Schedules"})]})]})]}),e.jsxs(E,{id:"settings-general","data-section":"general",children:[e.jsx(B,{children:"General"}),e.jsx(P,{children:"Default agent + model override."}),e.jsxs("div",{className:"field","data-setting-id":"defaultAgent",children:[e.jsx("label",{className:"field-label",htmlFor:"set-default-agent",children:"Default agent"}),e.jsx(de,{initialValue:a.defaultAgent||"",saveFn:async r=>{l("defaultAgent",r),c==null||c("defaultAgent",r)},render:({value:r,onChange:p,onBlur:x})=>e.jsx("input",{id:"set-default-agent",className:"input",type:"text",placeholder:"e.g. odin",value:r,onChange:i=>p(i.target.value),onBlur:x})})]}),e.jsxs("div",{className:"field","data-setting-id":"defaultModel",children:[e.jsx("label",{className:"field-label",htmlFor:"set-default-model",children:"Model override"}),e.jsx(de,{initialValue:a.defaultModel||"",saveFn:async r=>{l("defaultModel",r),c==null||c("defaultModel",r)},render:({value:r,onChange:p,onBlur:x})=>e.jsx("input",{id:"set-default-model",className:"input",type:"text",placeholder:"(leave empty for provider default)",value:r,onChange:i=>p(i.target.value),onBlur:x})})]})]})]})}function ss({initialStatus:a}){var m;const[s,l]=o.useState(a??null),[c,r]=o.useState(""),[p,x]=o.useState(!1),[i,n]=o.useState(null);o.useEffect(()=>{s===null&&k.get("/tailscale/status").then(f=>l(f)).catch(()=>l(null))},[]);const u=async()=>{try{const f=await k.get("/tailscale/status");l(f)}catch{n("Failed to load Tailscale status")}},g=async()=>{if(c.trim()){x(!0),n(null);try{await k.post("/tailscale/setup",{authKey:c.trim()}),await u(),r("")}catch(f){n(f.message||"Authentication failed")}finally{x(!1)}}},j=async()=>{var f,w,z;if(s){x(!0),n(null);try{await k.post("/tailscale/setup",{port:((f=s.settings)==null?void 0:f.port)||4321,https:((w=s.settings)==null?void 0:w.https)!==!1,hostname:((z=s.settings)==null?void 0:z.hostname)||""}),await u()}catch($){n($.message||"Setup failed")}finally{x(!1)}}},y=async()=>{x(!0),n(null);try{await k.post("/tailscale/unserve"),await u()}catch(f){n(f.message||"Remove failed")}finally{x(!1)}},S=(s==null?void 0:s.installed)??!1,L=(s==null?void 0:s.authenticated)??!1,C=((m=s==null?void 0:s.settings)==null?void 0:m.enabled)??!1,h=C?`https://${(s==null?void 0:s.hostname)||"bizar-dash"}`:null;return S?e.jsxs(E,{id:"settings-tailscale-auth","data-section":"tailscale",children:[e.jsxs(B,{children:[e.jsx(ce,{size:14})," Tailscale Integration"]}),e.jsx(P,{children:"Expose the dashboard over your Tailscale network using an auth key."}),i&&e.jsx("p",{style:{color:"var(--color-error, #f85149)",fontSize:"0.85rem"},children:i}),L?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"status-row",style:{display:"flex",alignItems:"center",gap:"0.5rem",marginBottom:"0.75rem"},children:[e.jsx(V,{size:16,style:{color:"var(--color-success, #3fb950)"}}),e.jsxs("span",{children:["Authenticated as ",e.jsx("strong",{children:(s==null?void 0:s.hostname)||"unknown"})]})]}),C&&h?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"status-row",style:{display:"flex",alignItems:"center",gap:"0.5rem",marginBottom:"0.75rem"},children:[e.jsx(Se,{size:16}),e.jsx("a",{href:h,target:"_blank",rel:"noreferrer",children:h})]}),e.jsx(b,{variant:"secondary",size:"sm",onClick:y,disabled:p,children:"Remove serve"})]}):e.jsx(b,{variant:"primary",size:"sm",onClick:j,disabled:p,children:"Set up Tailscale serve"})]}):e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"muted",style:{marginBottom:"0.75rem"},children:"Not authenticated with Tailscale."}),e.jsxs("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap"},children:[e.jsx("input",{type:"text",className:"input",placeholder:"tskey-...",value:c,onChange:f=>r(f.target.value),style:{flex:1,minWidth:"200px"},disabled:p}),e.jsx(b,{variant:"primary",size:"sm",onClick:g,disabled:p||!c.trim(),children:"Authenticate"})]})]})]}):e.jsxs(E,{id:"settings-tailscale-auth","data-section":"tailscale",children:[e.jsxs(B,{children:[e.jsx(ce,{size:14})," Tailscale Integration"]}),e.jsx(P,{children:"Tailscale is not installed on this machine."}),e.jsxs("p",{className:"muted",children:["Install from"," ",e.jsx("a",{href:"https://tailscale.com/download",target:"_blank",rel:"noreferrer",children:"tailscale.com/download"})]})]})}function as({settings:a,patchTop:s}){var l,c,r;return e.jsxs(E,{id:"settings-system-llm","data-section":"system-llm",children:[e.jsxs(B,{children:[e.jsx(ze,{size:14})," System LLM API"]}),e.jsx(P,{children:"Configures the LLM used for automatic title generation, prompt enhancement, summarization, and other system-level calls."}),e.jsxs("label",{className:"checkbox-row","data-setting-id":"systemLlm.enabled",children:[e.jsx("input",{type:"checkbox",checked:!!((l=a.systemLlm)!=null&&l.enabled),onChange:p=>{const x=a.systemLlm||{enabled:!0,provider:"cline",model:"cline/deepseek-v4-flash-free"};s("systemLlm",{...x,enabled:p.target.checked})}}),e.jsx("span",{children:"Enable system LLM calls"})]}),e.jsxs("div",{className:"field","data-setting-id":"systemLlm.provider",style:{marginTop:"var(--space-3)"},children:[e.jsx("label",{className:"field-label",htmlFor:"set-system-llm-provider",children:"Provider"}),e.jsxs("select",{id:"set-system-llm-provider",className:"select",value:((c=a.systemLlm)==null?void 0:c.provider)||"cline",onChange:p=>{const x=a.systemLlm||{enabled:!0,provider:"cline",model:"cline/deepseek-v4-flash-free"};s("systemLlm",{...x,provider:p.target.value})},children:[e.jsx("option",{value:"cline",children:"Cline"}),e.jsx("option",{value:"openrouter",children:"OpenRouter"}),e.jsx("option",{value:"minimax",children:"MiniMax"})]})]}),e.jsxs("div",{className:"field","data-setting-id":"systemLlm.model",children:[e.jsx("label",{className:"field-label",htmlFor:"set-system-llm-model",children:"Model"}),e.jsx("input",{id:"set-system-llm-model",className:"input mono",type:"text",placeholder:"cline/deepseek-v4-flash-free",value:((r=a.systemLlm)==null?void 0:r.model)||"cline/deepseek-v4-flash-free",onChange:p=>{const x=a.systemLlm||{enabled:!0,provider:"cline",model:"cline/deepseek-v4-flash-free"};s("systemLlm",{...x,model:p.target.value})}}),e.jsxs("p",{className:"field-help",children:["The API key is read from ",e.jsx("code",{children:"auth.json"})," for the selected provider. Leave the default model for best results."]})]}),e.jsxs("div",{style:{marginTop:"var(--space-4)"},children:[e.jsx("h4",{style:{margin:"0 0 var(--space-2)"},children:"Features using this API"}),e.jsxs("ul",{className:"settings-feature-list",style:{margin:0,paddingLeft:"var(--space-4)",lineHeight:1.8},children:[e.jsx("li",{children:"Auto-title generation for new chat sessions"}),e.jsx("li",{children:"Auto-title generation for new tasks"}),e.jsx("li",{children:'"Enhance prompt" button in the task input'}),e.jsx("li",{children:'"Enhance prompt" button in the chat composer'}),e.jsx("li",{className:"muted",style:{fontSize:12},children:"Future: summarization, name generation, and more"})]})]})]})}const Ve=[{value:"anthropic",label:"Anthropic"},{value:"anyllm",label:"AnyLLM"},{value:"litellm-anthropic",label:"LiteLLM (Anthropic)"},{value:"litellm-openai",label:"LiteLLM (OpenAI)"}];function Oe({settings:a,onPatch:s}){const l=Y(),[c,r]=o.useState(null),[p,x]=o.useState(null),[i,n]=o.useState(!1),[u,g]=o.useState(!1),[j,y]=o.useState(!1),[S,L]=o.useState(!1),[C,h]=o.useState(!1),[m,f]=o.useState(!1),w=o.useCallback(async()=>{n(!0);try{const[d,U]=await Promise.all([k.get("/headroom/status"),k.get("/headroom/stats?hours=24").catch(()=>({error:"no stats"}))]);r(d),U.error||x(U)}catch(d){l.error(`Failed to load Headroom status: ${d.message}`)}finally{n(!1)}},[l]);o.useEffect(()=>{w()},[w]);const z=async()=>{g(!0);try{const d=await k.post("/headroom/install",{force:!0});d.installed?(l.success(`Headroom installed via ${d.method}.`),await w()):l.error('Headroom install failed. Try: pip install "headroom-ai[all]"')}catch(d){l.error(`Install failed: ${d.message}`)}finally{g(!1)}},$=async()=>{y(!0);try{(await k.post("/headroom/wrap",{port:a.port})).ok?(l.success("cline wrapped with Headroom."),await w()):l.error("Wrap failed.")}catch(d){l.error(`Wrap failed: ${d.message}`)}finally{y(!1)}},_=async()=>{L(!0);try{(await k.post("/headroom/unwrap")).ok?(l.success("cline unwrapped from Headroom."),await w()):l.error("Unwrap failed.")}catch(d){l.error(`Unwrap failed: ${d.message}`)}finally{L(!1)}},W=async()=>{h(!0);try{(await k.post("/headroom/proxy/start",{port:a.port,host:a.host})).ok?(l.success(`Headroom proxy started on ${a.host}:${a.port}.`),await w()):l.error("Proxy start failed.")}catch(d){l.error(`Proxy start failed: ${d.message}`)}finally{h(!1)}},K=async()=>{f(!0);try{(await k.post("/headroom/proxy/stop")).ok?(l.success("Headroom proxy stopped."),await w()):l.error("Proxy stop failed.")}catch(d){l.error(`Proxy stop failed: ${d.message}`)}finally{f(!1)}},Z=async()=>{try{const{spawn:d}=await ke(async()=>{const{spawn:U}=await import("./__vite-browser-external-BIHI7g3E.js");return{spawn:U}},[]);d("headroom",["dashboard"],{detached:!0,stdio:"ignore"})}catch{l.error("Could not open Headroom dashboard. Run `headroom dashboard` manually.")}},{installed:R,version:q,proxyRunning:M,proxyPort:X,wrapped:A}=c||{},H=(p==null?void 0:p.compressionRatio)??0,D=(p==null?void 0:p.tokensSaved)??0;return e.jsx("div",{id:"settings-headroom","data-section":"headroom",children:e.jsxs(E,{children:[e.jsxs(B,{children:[e.jsx(pe,{size:14,style:{color:M?"var(--success)":"var(--text-dim)"}}),"Headroom",R&&q&&e.jsxs("span",{style:{fontSize:11,color:"var(--text-dim)",marginLeft:6},children:["v",q," ",M?"✓":"✗"]}),!R&&e.jsx("span",{style:{fontSize:11,color:"var(--error)",marginLeft:6},children:"not installed"})]}),e.jsx(P,{children:"Context compression for token efficiency. Compresses tool outputs, logs, and conversation history by 60–95% before they reach the model."}),e.jsxs("div",{style:{display:"flex",gap:16,flexWrap:"wrap",marginTop:12,marginBottom:12},children:[e.jsxs("div",{className:"headroom-status-item",children:[R?e.jsx(V,{size:12,style:{color:"var(--success)"}}):e.jsx(se,{size:12,style:{color:"var(--error)"}}),e.jsx("span",{children:R?"Installed":"Not installed"})]}),e.jsxs("div",{className:"headroom-status-item",children:[M?e.jsx(V,{size:12,style:{color:"var(--success)"}}):e.jsx(se,{size:12,style:{color:"var(--text-dim)"}}),e.jsxs("span",{children:["Proxy ",M?`${X} ✓`:"stopped"]})]}),e.jsxs("div",{className:"headroom-status-item",children:[A?e.jsx(V,{size:12,style:{color:"var(--success)"}}):e.jsx(se,{size:12,style:{color:"var(--text-dim)"}}),e.jsxs("span",{children:["cline ",A?"wrapped":"not wrapped"]})]})]}),(D>0||H>0)&&e.jsxs("div",{style:{display:"flex",gap:24,marginBottom:12},children:[e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:20,fontWeight:700,color:"var(--success)"},children:H>0?`${Math.round(H*100)}%`:"—"}),e.jsx("div",{className:"muted",style:{fontSize:11},children:"Compression ratio"})]}),e.jsxs("div",{children:[e.jsx("div",{style:{fontSize:20,fontWeight:700,color:"var(--accent)"},children:D>0?D.toLocaleString():"—"}),e.jsx("div",{className:"muted",style:{fontSize:11},children:"Tokens saved (24h)"})]})]}),e.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginBottom:8},children:[R?e.jsxs(e.Fragment,{children:[e.jsxs(b,{variant:"secondary",size:"sm",onClick:$,disabled:j||A,title:A?"cline is already wrapped":"Wrap cline to route through Headroom proxy",children:[j?e.jsx("span",{className:"btn-spinner"}):e.jsx(Ae,{size:13}),j?"Wrapping…":A?"Wrapped ✓":"Wrap cline"]}),A&&e.jsxs(b,{variant:"ghost",size:"sm",onClick:_,disabled:S,children:[S?e.jsx("span",{className:"btn-spinner"}):e.jsx(O,{size:13}),S?"Unwrapping…":"Unwrap"]})]}):e.jsxs(b,{variant:"primary",size:"sm",onClick:z,disabled:u,children:[u?e.jsx("span",{className:"btn-spinner"}):e.jsx(G,{size:13}),u?"Installing…":"Install Headroom"]}),R&&e.jsxs(e.Fragment,{children:[M?e.jsxs(b,{variant:"secondary",size:"sm",onClick:K,disabled:m,children:[m?e.jsx("span",{className:"btn-spinner"}):e.jsx(Re,{size:13}),m?"Stopping…":"Stop proxy"]}):e.jsxs(b,{variant:"secondary",size:"sm",onClick:W,disabled:C,children:[C?e.jsx("span",{className:"btn-spinner"}):e.jsx(Le,{size:13}),C?"Starting…":"Start proxy"]}),e.jsxs(b,{variant:"ghost",size:"sm",onClick:Z,children:[e.jsx(Ie,{size:13}),"Dashboard"]})]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:w,disabled:i,children:e.jsx(O,{size:13,className:i?"spin":""})})]}),e.jsxs("div",{style:{marginTop:16},children:[e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.enabled,onChange:d=>s({enabled:d.target.checked})}),e.jsx("span",{children:"Enable Headroom"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.autoInstall,onChange:d=>s({autoInstall:d.target.checked})}),e.jsx("span",{children:"Auto-install if missing on dashboard startup"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.autoStart,onChange:d=>s({autoStart:d.target.checked})}),e.jsx("span",{children:"Auto-start proxy on dashboard startup"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.autoWrap,onChange:d=>s({autoWrap:d.target.checked})}),e.jsx("span",{children:"Auto-wrap cline on dashboard startup"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.routeAllProviders,onChange:d=>s({routeAllProviders:d.target.checked})}),e.jsx("span",{children:"Route all providers through Headroom proxy"})]}),e.jsxs("div",{className:"task-form-row",style:{marginTop:12},children:[e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Proxy port"}),e.jsx("input",{type:"number",className:"input",value:a.port,min:1,max:65535,onChange:d=>s({port:Math.max(1,Math.min(65535,parseInt(d.target.value,10)||8787))})})]}),e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Proxy host"}),e.jsx("input",{type:"text",className:"input",value:a.host,onChange:d=>s({host:d.target.value})})]})]}),e.jsxs("div",{className:"task-form-row",children:[e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Backend"}),e.jsx("select",{className:"select",value:a.backend,onChange:d=>s({backend:d.target.value}),children:Ve.map(d=>e.jsx("option",{value:d.value,children:d.label},d.value))})]}),e.jsxs("div",{className:"task-form-field",children:[e.jsx("label",{className:"field-label",children:"Monthly budget (USD)"}),e.jsx("input",{type:"number",className:"input",value:a.budget,min:0,step:1,onChange:d=>s({budget:Math.max(0,parseFloat(d.target.value)||0)})}),e.jsx("span",{className:"field-help",children:"0 = unlimited"})]})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.outputShaper,onChange:d=>s({outputShaper:d.target.checked})}),e.jsx("span",{children:"Enable output shaper"})]}),e.jsxs("label",{className:"checkbox-row",children:[e.jsx("input",{type:"checkbox",checked:a.telemetry,onChange:d=>s({telemetry:d.target.checked})}),e.jsx("span",{children:"Enable telemetry"})]})]})]})})}const ue={enabled:!0,autoInstall:!0,port:8787,host:"127.0.0.1",outputShaper:!1,telemetry:!1,budget:0,backend:"anthropic",autoStart:!0,autoWrap:!0,routeAllProviders:!0};function ts({settings:a,setSettings:s,setDirty:l}){return e.jsx(Oe,{settings:a.headroom||ue,onPatch:c=>{s(r=>({...r,headroom:{...r.headroom||ue,...c}})),l(!0)}})}function Fe(){const a=Y(),[s,l]=o.useState([]),[c,r]=o.useState(new Set),[p,x]=o.useState(!0),[i,n]=o.useState(""),[u,g]=o.useState(!0),j=o.useCallback(async()=>{x(!0);try{const[h,m]=await Promise.all([k.get("/activity"),k.get("/activity/hidden")]);l(Array.isArray(h.items)?h.items:[]),r(new Set(m.hidden||[]))}catch(h){a.error(`Load failed: ${h.message}`)}finally{x(!1)}},[a]);o.useEffect(()=>{j()},[j]);const y=(h,m)=>{const f=`${h.kind||""}|${h.ts||""}|${h.slug||""}|${m}`;let w=0;for(let z=0;z<f.length;z++)w=(w<<5)-w+f.charCodeAt(z)|0;return Math.abs(w).toString(16).padStart(8,"0").slice(0,16)},S=async()=>{try{await k.del("/activity/hide"),r(new Set),a.success("All hidden activity restored.")}catch(h){a.error(`Restore failed: ${h.message}`)}},L=async h=>{try{await k.del(`/activity/hide/${encodeURIComponent(h)}`);const m=new Set(c);m.delete(h),r(m)}catch(m){a.error(`Restore failed: ${m.message}`)}},C=s.filter((h,m)=>{const f=y(h,m);if(!u&&c.has(f))return!1;if(!i)return!0;const w=i.toLowerCase();return[h.kind,h.slug,h.message].some(z=>typeof z=="string"&&z.toLowerCase().includes(w))});return e.jsxs(E,{id:"settings-activity-log","data-section":"activity-log",children:[e.jsxs(B,{children:[e.jsx(pe,{size:14})," Activity log",e.jsxs("span",{className:"muted",style:{fontWeight:400,marginLeft:8,fontSize:12},children:[s.length," total · ",c.size," hidden"]}),e.jsx(b,{variant:"ghost",size:"sm",style:{marginLeft:"auto"},onClick:j,title:"Reload",children:e.jsx(O,{size:12})})]}),e.jsxs(P,{children:["Full history from ",e.jsx("code",{children:"~/.bizar/activity.log"}),". Hiding an item in the Overview only hides it there — the entry stays here."]}),e.jsxs("div",{className:"activity-log-toolbar",children:[e.jsxs("div",{className:"activity-log-search",children:[e.jsx(te,{size:12}),e.jsx("input",{type:"text",className:"input",placeholder:"Filter by kind, slug, or message…",value:i,onChange:h=>n(h.target.value)})]}),e.jsxs("label",{className:"activity-log-toggle",children:[e.jsx("input",{type:"checkbox",checked:u,onChange:h=>g(h.target.checked)}),"Show hidden"]}),e.jsxs(b,{variant:"ghost",size:"sm",disabled:c.size===0,onClick:S,title:"Restore all hidden items to the Overview",children:[e.jsx(ne,{size:12})," Restore all"]})]}),p?e.jsx("div",{className:"muted",style:{padding:"12px 0",fontSize:12},children:"Loading…"}):C.length===0?e.jsx("div",{className:"muted",style:{padding:"12px 0",fontSize:12},children:s.length===0?"No activity yet.":"No items match the current filter."}):e.jsxs("div",{className:"activity-log-table-wrap",children:[e.jsxs("table",{className:"activity-log-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Kind"}),e.jsx("th",{children:"Detail"}),e.jsx("th",{children:"Time"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:C.slice(0,200).map((h,m)=>{const f=y(h,m),w=c.has(f);return e.jsxs("tr",{className:T(w&&"activity-log-row-hidden"),children:[e.jsx("td",{className:"activity-log-kind",children:h.kind||"activity"}),e.jsx("td",{className:"activity-log-detail",children:h.message||h.slug||"—"}),e.jsx("td",{className:"activity-log-time mono",children:h.ts?new Date(h.ts).toLocaleString():"—"}),e.jsx("td",{children:w?e.jsx(b,{variant:"ghost",size:"sm",onClick:()=>L(f),title:"Restore to Overview",children:e.jsx(ne,{size:12})}):e.jsx("span",{className:"activity-log-state-tag",children:"shown"})})]},`${h.ts}-${m}`)})})]}),C.length>200&&e.jsxs("div",{className:"muted",style:{fontSize:11,padding:"8px 0"},children:["Showing first 200 of ",C.length,"."]})]})]})}function We({about:a}){return e.jsxs(E,{id:"settings-about","data-section":"about",children:[e.jsxs(B,{children:[e.jsx(Ee,{size:14})," About"]}),e.jsx(P,{children:"Build metadata."}),e.jsxs("dl",{className:"about-table",children:[e.jsx("dt",{children:"Version"}),e.jsx("dd",{className:"mono",children:(a==null?void 0:a.version)||"—"}),e.jsx("dt",{children:"Homepage"}),e.jsx("dd",{children:e.jsx("a",{href:(a==null?void 0:a.homepage)||"https://github.com/DrB0rk/BizarHarness",target:"_blank",rel:"noopener noreferrer",children:(a==null?void 0:a.homepage)||"https://github.com/DrB0rk/BizarHarness"})}),e.jsx("dt",{children:"License"}),e.jsx("dd",{children:(a==null?void 0:a.license)||"MIT"})]})]})}function ns({about:a}){return e.jsxs(e.Fragment,{children:[e.jsx(Fe,{}),e.jsx(We,{about:a})]})}function Ke({onError:a}){const s=Y(),[l,c]=o.useState([]),[r,p]=o.useState(!1),[x,i]=o.useState(!1),[n,u]=o.useState(new Set),[g,j]=o.useState(null),[y,S]=o.useState(""),[L,C]=o.useState(!1),[h,m]=o.useState(""),[f,w]=o.useState(""),[z,$]=o.useState(!1),[_,W]=o.useState(""),[K,Z]=o.useState(!1),[R,q]=o.useState(""),[M,X]=o.useState(new Set),A=o.useCallback(async()=>{p(!0);try{const t=await k.get("/env-vars");c(t)}catch(t){s.error(`Load failed: ${t.message}`),a==null||a(t.message)}finally{p(!1)}},[s,a]);o.useEffect(()=>{A()},[A]);const H=t=>{u(N=>{const v=new Set(N);return v.has(t)?v.delete(t):v.add(t),v})},D=async()=>{const t=h.trim().toUpperCase(),N=f.trim();if(!t||!/^BIZAR_[A-Z0-9_]+$/.test(t)){s.warning("Name must match BIZAR_<NAME> (e.g. BIZAR_MINIMAX_KEY)");return}if(!N){s.warning("Value is required.");return}if(l.some(v=>v.name===t)){s.warning(`${t} already exists.`);return}i(!0);try{await k.post("/env-vars",{name:t,value:N}),s.success(`${t} created.`),C(!1),m(""),w(""),await A()}catch(v){s.error(`Create failed: ${v.message}`)}finally{i(!1)}},d=t=>{j(t.name),S(t.value===t.value.replace(/\*/g,"")?t.value:""),u(N=>{const v=new Set(N);return v.add(t.name),v})},U=async t=>{if(!y.trim()){s.warning("Value cannot be empty.");return}i(!0);try{await k.put(`/env-vars/${encodeURIComponent(t)}`,{value:y.trim()}),s.success(`${t} updated.`),j(null),await A()}catch(N){s.error(`Update failed: ${N.message}`)}finally{i(!1)}},re=async t=>{if(confirm(`Delete ${t}? This cannot be undone.`))try{await k.del(`/env-vars/${encodeURIComponent(t)}`),s.success(`${t} deleted.`),await A()}catch(N){s.error(`Delete failed: ${N.message}`)}},ge=async()=>{if(!_.trim()){s.warning("Nothing to import.");return}Z(!0);try{const t=await k.post("/env-vars/bulk-import",{envContent:_});s.success(`Imported ${t.imported}, skipped ${t.skipped}.`),t.errors.length>0&&s.warning(`${t.errors.length} lines had errors: ${t.errors.slice(0,3).join("; ")}${t.errors.length>3?"…":""}`),W(""),$(!1),await A()}catch(t){s.error(`Bulk import failed: ${t.message}`)}finally{Z(!1)}},je=async()=>{try{const t=await k.get("/env-vars/export"),N=new Blob([t],{type:"text/plain"}),v=URL.createObjectURL(N),I=document.createElement("a");I.href=v,I.download=".env",I.click(),URL.revokeObjectURL(v),s.success("Exported .env file.")}catch(t){s.error(`Export failed: ${t.message}`)}},F=o.useMemo(()=>{if(!R.trim())return l;const t=R.toLowerCase();return l.filter(N=>N.name.toLowerCase().includes(t))},[l,R]),Q=o.useMemo(()=>{const t={};for(const N of F){const v=N.name.split("_")[0]+"_";(t[v]??(t[v]=[])).push(N)}return t},[F]),fe=t=>{X(N=>{const v=new Set(N);return v.has(t)?v.delete(t):v.add(t),v})},le=o.useMemo(()=>{const t=["BIZAR_","PROVIDER_","MODEL_","API_"];return Object.keys(Q).sort((v,I)=>{const J=t.indexOf(v),ee=t.indexOf(I);return J===-1&&ee===-1?v.localeCompare(I):J===-1?1:ee===-1?-1:J-ee})},[Q]);if(r)return e.jsx("div",{className:"muted",style:{padding:"16px 0",fontSize:13},children:"Loading env vars…"});const ve=le.length>1;return e.jsxs("div",{className:"env-var-manager",children:[e.jsxs("div",{className:"env-var-toolbar",children:[e.jsxs(b,{variant:"primary",size:"sm",onClick:()=>C(!0),children:[e.jsx(Be,{size:12})," New variable"]}),e.jsxs(b,{variant:"secondary",size:"sm",onClick:()=>$(t=>!t),className:z?"active":"",children:[e.jsx(Pe,{size:12})," Bulk import"]}),e.jsxs(b,{variant:"ghost",size:"sm",onClick:je,title:"Export as .env",children:[e.jsx(G,{size:12})," Export"]}),e.jsxs("div",{className:"env-var-search-wrap",children:[e.jsx(te,{size:12,className:"env-var-search-icon"}),e.jsx("input",{className:"env-var-search input",placeholder:"Filter…",value:R,onChange:t=>q(t.target.value)})]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:A,title:"Reload",children:e.jsx(O,{size:12})})]}),z&&e.jsxs("div",{className:"env-var-bulk-panel",children:[e.jsxs("div",{className:"env-var-bulk-header",children:[e.jsxs("span",{children:["Paste ",e.jsx("code",{children:"KEY=value"})," lines (one per line):"]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:()=>$(!1),children:e.jsx(oe,{size:12})})]}),e.jsx("textarea",{className:"input mono env-var-bulk-textarea",placeholder:`BIZAR_API_KEY=your-key-here
|
|
3
3
|
PROVIDER_OPENAI_KEY=sk-...
|
|
4
|
-
MODEL_KEY=gem-...`,value:_,onChange:t=>W(t.target.value),rows:6}),e.jsxs("div",{className:"env-var-bulk-footer",children:[e.jsx(b,{variant:"primary",size:"sm",onClick:ge,disabled:K||!_.trim(),children:K?"Importing…":"Import"}),e.jsx("span",{className:"muted",style:{fontSize:11},children:"Existing keys are skipped unless re-created individually. Invalid lines are reported."})]})]}),l.length===0&&!L&&e.jsxs("div",{className:"env-var-empty",children:[e.jsx(xe,{size:20}),e.jsx("span",{children:"No BIZAR_* env vars yet."}),e.jsx("span",{style:{fontSize:11},children:"Create one to store API keys securely."})]}),L&&e.jsxs("div",{className:"env-var-add-form",children:[e.jsxs("div",{className:"env-var-add-row",children:[e.jsx("input",{className:"input mono",style:{width:240},placeholder:"BIZAR_NAME",value:h,onChange:t=>m(t.target.value.toUpperCase()),onKeyDown:t=>{t.key==="Enter"&&D(),t.key==="Escape"&&C(!1)},autoFocus:!0}),e.jsx("input",{className:"input mono",type:"password",placeholder:"value (API key, token, etc.)",value:
|
|
4
|
+
MODEL_KEY=gem-...`,value:_,onChange:t=>W(t.target.value),rows:6}),e.jsxs("div",{className:"env-var-bulk-footer",children:[e.jsx(b,{variant:"primary",size:"sm",onClick:ge,disabled:K||!_.trim(),children:K?"Importing…":"Import"}),e.jsx("span",{className:"muted",style:{fontSize:11},children:"Existing keys are skipped unless re-created individually. Invalid lines are reported."})]})]}),l.length===0&&!L&&e.jsxs("div",{className:"env-var-empty",children:[e.jsx(xe,{size:20}),e.jsx("span",{children:"No BIZAR_* env vars yet."}),e.jsx("span",{style:{fontSize:11},children:"Create one to store API keys securely."})]}),L&&e.jsxs("div",{className:"env-var-add-form",children:[e.jsxs("div",{className:"env-var-add-row",children:[e.jsx("input",{className:"input mono",style:{width:240},placeholder:"BIZAR_NAME",value:h,onChange:t=>m(t.target.value.toUpperCase()),onKeyDown:t=>{t.key==="Enter"&&D(),t.key==="Escape"&&C(!1)},autoFocus:!0}),e.jsx("input",{className:"input mono",type:"password",placeholder:"value (API key, token, etc.)",value:f,onChange:t=>w(t.target.value),onKeyDown:t=>{t.key==="Enter"&&D(),t.key==="Escape"&&C(!1)}}),e.jsxs(b,{variant:"primary",size:"sm",onClick:D,disabled:x,children:[e.jsx(V,{size:12})," Create"]}),e.jsx(b,{variant:"ghost",size:"sm",onClick:()=>{C(!1),m(""),w("")},children:e.jsx(oe,{size:12})})]}),e.jsxs("p",{style:{fontSize:11,color:"var(--text-dim)",margin:0},children:["Names must match ",e.jsxs("code",{children:["BIZAR_",e.jsx("var",{children:"NAME"})]})," (uppercase letters, digits, underscores)."]})]}),F.length>0&&(ve?e.jsx("div",{className:"env-var-groups",children:le.map(t=>{const N=Q[t],v=M.has(t);return e.jsxs("div",{className:"env-var-group",children:[e.jsxs("button",{type:"button",className:"env-var-group-header",onClick:()=>fe(t),children:[v?e.jsx(Te,{size:12}):e.jsx($e,{size:12}),e.jsx("span",{className:"env-var-group-prefix mono",children:t}),e.jsxs("span",{className:"env-var-group-count muted",children:["(",N.length,")"]})]}),!v&&e.jsx("div",{className:"env-var-list",children:N.map(I=>e.jsx(he,{v:I,editing:g,editValue:y,isRevealed:n.has(I.name),onToggleReveal:H,onStartEdit:d,onEditValueChange:S,onHandleUpdate:U,onCancelEdit:()=>j(null),onDelete:re,saving:x},I.name))})]},t)})}):e.jsx("div",{className:"env-var-list",children:F.map(t=>e.jsx(he,{v:t,editing:g,editValue:y,isRevealed:n.has(t.name),onToggleReveal:H,onStartEdit:d,onEditValueChange:S,onHandleUpdate:U,onCancelEdit:()=>j(null),onDelete:re,saving:x},t.name))})),F.length===0&&l.length>0&&e.jsxs("div",{className:"env-var-empty",children:[e.jsx(te,{size:16}),e.jsxs("span",{children:['No env vars match "',R,'"']})]})]})}function he({v:a,editing:s,editValue:l,isRevealed:c,onToggleReveal:r,onStartEdit:p,onEditValueChange:x,onHandleUpdate:i,onCancelEdit:n,onDelete:u,saving:g}){const j=s===a.name;return e.jsxs("div",{className:T("env-var-row",j&&"env-var-row-editing"),children:[e.jsx("span",{className:"env-var-name mono",children:a.name}),j?e.jsx("input",{className:"input mono",type:"password",style:{flex:1,minWidth:200},value:l,onChange:y=>x(y.target.value),onKeyDown:y=>{y.key==="Enter"&&i(a.name),y.key==="Escape"&&n()},autoFocus:!0}):e.jsx("span",{className:T("env-var-value mono",!c&&"env-var-value-masked"),children:a.value}),e.jsx("span",{className:"env-var-source muted",children:a.source}),e.jsxs("div",{className:"env-var-actions",children:[!j&&e.jsx("button",{type:"button",className:"icon-btn",title:c?"Hide":"Reveal",onClick:()=>r(a.name),children:c?e.jsx(Me,{size:12}):e.jsx(ne,{size:12})}),j?e.jsxs(e.Fragment,{children:[e.jsx(b,{variant:"primary",size:"sm",onClick:()=>i(a.name),disabled:g,children:"Save"}),e.jsx(b,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"})]}):e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",className:"icon-btn",title:"Edit",onClick:()=>p(a),children:e.jsx(De,{size:12})}),e.jsx("button",{type:"button",className:"icon-btn icon-btn-danger",title:"Delete",onClick:()=>u(a.name),children:e.jsx(Ue,{size:12})})]})]})]})}function rs(){return e.jsxs(E,{id:"settings-env-vars","data-section":"env-vars",children:[e.jsxs(B,{children:[e.jsx(xe,{size:14})," Environment Variables"]}),e.jsxs(P,{children:["Manage BIZAR_* env vars (API keys, secrets). Values are stored in ",e.jsx("code",{children:"~/.config/bizar/env.json"})," (mode 0600)."]}),e.jsx(Ke,{})]})}export{de as A,b as B,E as C,rs as E,es as G,ts as H,as as S,ss as T,Je as U,B as a,P as b,Qe as c,ns as d};
|