specrails-hub 1.64.0 → 1.65.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 +12 -10
- package/client/dist/assets/{ActivityFeedPage-lzLYInqo.js → ActivityFeedPage-C1_ez0Af.js} +1 -1
- package/client/dist/assets/{AgentsPage-dxJPxmmK.js → AgentsPage-DXO-gjtw.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-8Vdtr1uS.js → AnalyticsPage-0Fu4Rn6_.js} +1 -1
- package/client/dist/assets/{BarChart-4okIQvSE.js → BarChart-Dz_dPaiK.js} +1 -1
- package/client/dist/assets/CodePage-B1bkNVia.js +3 -0
- package/client/dist/assets/{DocsDialog-DMcv6ck1.js → DocsDialog-BJzQDy38.js} +1 -1
- package/client/dist/assets/{DocsPage-DE_8xnfv.js → DocsPage-CAoKk_kJ.js} +1 -1
- package/client/dist/assets/{ExportDropdown-BvMqXS54.js → ExportDropdown-tFIBg_zE.js} +1 -1
- package/client/dist/assets/{HubAnalyticsPage-Df8jpa5g.js → HubAnalyticsPage-BLM0LHs3.js} +1 -1
- package/client/dist/assets/{IntegrationsPage-DXc7CVyH.js → IntegrationsPage-B3AaUU2n.js} +1 -1
- package/client/dist/assets/{JobDetailPage-CgxKcObX.js → JobDetailPage-DcrNv55J.js} +1 -1
- package/client/dist/assets/{JobsPage-B4DkIsJY.js → JobsPage-8SSMZjRs.js} +1 -1
- package/client/dist/assets/{dist-js-CuAOZeJt.js → dist-js-BvnRm6Dv.js} +1 -1
- package/client/dist/assets/{dist-js-DjwnH824.js → dist-js-CTHX9F-p.js} +1 -1
- package/client/dist/assets/index-BjiyyM2M.css +2 -0
- package/client/dist/assets/{index-CGRWJr7_.js → index-hPtSDG5z.js} +46 -45
- package/client/dist/assets/{lib-BhWg9Tvv.js → lib-jLo-VAZq.js} +1 -1
- package/client/dist/assets/useProjectCache-Dcn_gU6_.js +1 -0
- package/client/dist/index.html +14 -2
- package/docs/README.md +3 -0
- package/docs/cli.md +56 -36
- package/docs/codex.md +83 -22
- package/docs/creating-specs.md +85 -64
- package/docs/customizing.md +73 -49
- package/docs/getting-started.md +18 -16
- package/docs/internals/README.md +7 -4
- package/docs/internals/adding-a-provider.md +238 -0
- package/docs/internals/api-reference.md +241 -94
- package/docs/internals/architecture.md +186 -104
- package/docs/internals/configuration.md +90 -60
- package/docs/internals/openspec-workflow.md +182 -90
- package/docs/internals/operations-runbook.md +123 -39
- package/docs/internals/profiles.md +64 -18
- package/docs/platforms/macos.md +92 -20
- package/docs/platforms/windows.md +45 -17
- package/docs/running-pipelines.md +87 -58
- package/docs/terminal.md +17 -11
- package/docs/tracking-cost.md +70 -40
- package/package.json +1 -1
- package/server/dist/agent-refine-manager.js +29 -0
- package/server/dist/attachment-manager.js +9 -1
- package/server/dist/auth.js +88 -1
- package/server/dist/chat-manager.js +413 -389
- package/server/dist/code-explorer-router.js +139 -27
- package/server/dist/config.js +23 -4
- package/server/dist/db.js +57 -10
- package/server/dist/docs-router.js +17 -3
- package/server/dist/explore-contract-refine.js +7 -1
- package/server/dist/file-provenance.js +46 -6
- package/server/dist/file-summary-generator.js +59 -10
- package/server/dist/file-summary-manager.js +178 -32
- package/server/dist/hub-analytics.js +8 -2
- package/server/dist/hub-db.js +15 -1
- package/server/dist/index.js +58 -12
- package/server/dist/plugin-manager.js +11 -1
- package/server/dist/plugins/json-mutation.js +10 -5
- package/server/dist/project-registry.js +74 -15
- package/server/dist/project-router.js +139 -2
- package/server/dist/proposal-manager.js +27 -0
- package/server/dist/queue-manager.js +52 -6
- package/server/dist/rails-router.js +25 -18
- package/server/dist/setup-manager.js +8 -4
- package/server/dist/smash-runner.js +164 -141
- package/server/dist/spec-launcher-manager.js +18 -0
- package/server/dist/spending.js +28 -6
- package/server/dist/telemetry-export.js +18 -1
- package/server/dist/telemetry-receiver.js +8 -2
- package/server/dist/ticket-store.js +21 -2
- package/server/dist/util/secure-fs.js +50 -0
- package/server/dist/ws-routing.js +47 -0
- package/client/dist/assets/CodePage-Dg7-L6U8.js +0 -3
- package/client/dist/assets/index-DRN9DysR.css +0 -2
- package/client/dist/assets/useProjectCache-CB8aP5ib.js +0 -1
- package/docs/adding-a-provider.md +0 -159
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://nodejs.org)
|
|
12
12
|
[](https://www.typescriptlang.org/)
|
|
13
|
-
[](https://react.dev)
|
|
14
14
|
[](https://tauri.app)
|
|
15
15
|
[](#-bring-your-own-agent)
|
|
16
16
|
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
**specrails-hub** turns *"I'll just let the AI do it"* into a workflow you can **see, steer, and trust**. It's a local-first dashboard and CLI that sits on top of [**specrails-core**](https://github.com/fjpulidop/specrails-core) and gives you **one window for all your projects**:
|
|
26
26
|
|
|
27
27
|
- 💬 Shape a spec in conversation with an AI, or generate one in a single shot.
|
|
28
|
-
- 🛤️ Drag specs onto **execution rails** and run them —
|
|
28
|
+
- 🛤️ Drag specs onto **execution rails** and run them — one job at a time per project, in parallel across projects.
|
|
29
29
|
- 🤖 Watch the **Architect → Developer → Reviewer → Ship** pipeline stream live.
|
|
30
30
|
- 💰 See exactly **what each agent cost you** this week, per provider, per ticket.
|
|
31
31
|
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
|
|
52
52
|
| | |
|
|
53
53
|
|---|---|
|
|
54
|
-
| 🛤️ **Execution rails** | Each rail is an independent lane.
|
|
54
|
+
| 🛤️ **Execution rails** | Each rail is an independent lane. Within a project, jobs run **one at a time** (rails let you queue and organise the work); true parallelism is **across projects**. Each rail carries its own **agent profile** (which agents, which models, how tasks route). |
|
|
55
55
|
| 🧩 **Agent profiles** | A per-project, declarative catalog that tells the implement pipeline which agents to run and at what model — snapshotted per job so concurrent rails stay isolated. |
|
|
56
56
|
| 📡 **Live job detail** | A premium ticket-identity header, live duration ticker, incremental turns/tokens, and authoritative cost on exit. |
|
|
57
57
|
| 🔌 **Plugins** | A per-project marketplace of MCP-based integrations (**Serena** semantic code-nav bundled today). Additive by design — installing plugin N+1 never disturbs plugin N. |
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
|
|
61
61
|
| | |
|
|
62
62
|
|---|---|
|
|
63
|
-
| 📊 **Analytics** | Every billable AI invocation — across rails, Quick, Explore, AI edits, and file summaries — is recorded for **both Claude and Codex**. Burn-rate hero, daily timeline, top tickets, model breakdown, cost-vs-turns scatter. |
|
|
63
|
+
| 📊 **Analytics** | Every billable AI invocation — across rails, Quick, Explore, AI edits, SMASH, and file summaries — is recorded for **both Claude and Codex**. Burn-rate hero, daily timeline, top tickets, model breakdown, cost-vs-turns scatter. |
|
|
64
64
|
| 🧮 **Honest numbers** | Claude cost is the provider-billed figure; Codex cost is **estimated** from a local rate-card (the CLI doesn't report it) and clearly flagged with a `~`. Token totals include the cache tiers, so the figures actually reconcile. |
|
|
65
65
|
| 📤 **Exports** | One-click CSV/JSON, plus per-ticket spending deep-links. |
|
|
66
66
|
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
| | |
|
|
70
70
|
|---|---|
|
|
71
71
|
| 🖥️ **Terminal panel** | A real VS-Code-style bottom panel (`Cmd/Ctrl+J`) powered by `node-pty` + xterm.js — WebGL rendering, search, ligatures, image inline, drag-drop paths, and OSC 133 shell integration. |
|
|
72
|
-
| 🎨 **Themes** |
|
|
72
|
+
| 🎨 **Themes** | Five built-ins — `specrails` (default), `dracula`, `aurora-light`, `obsidian-dark`, `matrix` — applied before React hydrates (no flash). |
|
|
73
73
|
| 🧭 **Code explorer** | A read-only, non-developer-friendly file tree + Monaco viewer with plain-language AI summaries and *"touched by AI"* provenance chips. |
|
|
74
74
|
| 💬 **Minimizable chats** | Park an Explore or AI-Edit session into a dock chip and pick it back up later — never lost across refreshes or project switches. |
|
|
75
75
|
|
|
@@ -129,7 +129,7 @@ specrails-hub add /path/to/your/project
|
|
|
129
129
|
# http://127.0.0.1:4200
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
If a project doesn't have specrails-core yet, a **
|
|
132
|
+
If a project doesn't have specrails-core yet, a **3-step setup wizard** (Configure → Install → Done) installs it for you — one flow, no tier picker, ~1 minute on a warm cache.
|
|
133
133
|
|
|
134
134
|
> 💡 **Prefer a desktop app?** Grab a signed macOS or Windows build — see [Desktop app](#%EF%B8%8F-desktop-app). It bundles the server, so there's no separate `start`.
|
|
135
135
|
|
|
@@ -152,7 +152,7 @@ When the hub is running, the CLI talks to it over HTTP + WebSocket; when it isn'
|
|
|
152
152
|
|
|
153
153
|
- 🟩 **Node.js 20+**
|
|
154
154
|
- 🤖 **At least one AI CLI** on your `PATH`:
|
|
155
|
-
- **[Claude Code](https://claude.com/claude-code)** — the `claude` binary
|
|
155
|
+
- **[Claude Code](https://claude.com/claude-code)** — the `claude` binary, signed in (via Claude subscription login or an `ANTHROPIC_API_KEY`).
|
|
156
156
|
- **[Codex CLI](https://developers.openai.com/codex)** ≥ 0.128.0 — the `codex` binary. Run `codex login` or set `OPENAI_API_KEY`.
|
|
157
157
|
- 🌿 **git**
|
|
158
158
|
- 🧪 *(optional)* **`uv`** — only if you want the Serena plugin
|
|
@@ -168,7 +168,7 @@ A clean **three-layer TypeScript monorepo** — one Express process runs in *hub
|
|
|
168
168
|
|
|
169
169
|
```
|
|
170
170
|
🗄️ server/ Express 5 + WebSocket + SQLite (better-sqlite3) · the brain
|
|
171
|
-
🎨 client/ React
|
|
171
|
+
🎨 client/ React 19 + Vite + Tailwind v4 · the dashboard
|
|
172
172
|
⌨️ cli/ specrails-hub command bridge · the terminal door
|
|
173
173
|
```
|
|
174
174
|
|
|
@@ -222,10 +222,12 @@ npm run dev # 🚀 server :4200 + client :4201, hot reloa
|
|
|
222
222
|
|
|
223
223
|
## 🖥️ Desktop app
|
|
224
224
|
|
|
225
|
-
|
|
225
|
+
Desktop builds for **macOS (Apple Silicon)**, **Windows (x64)**, and **Windows (arm64)** are published at:
|
|
226
226
|
|
|
227
227
|
> 📥 `https://specrails.dev/downloads/specrails-hub/latest/`
|
|
228
228
|
|
|
229
|
+
The macOS build is **signed + notarized**. The Windows installers are **unsigned in v1** — SmartScreen flags them, so click **More info → Run anyway**. (Authenticode signing is a planned follow-up.)
|
|
230
|
+
|
|
229
231
|
`npm run build:desktop` produces the `.app` / `.dmg` / `.exe`, but does **not** assemble the bundled runtimes — that app falls back to your system PATH and downloads a Playwright Chromium on first use. To build a self-contained app the way CI does (**macOS arm64 only**):
|
|
230
232
|
|
|
231
233
|
```bash
|
|
@@ -244,7 +246,7 @@ BUNDLE_CHROMIUM=true npm run build:desktop:local
|
|
|
244
246
|
## 🔒 Security model
|
|
245
247
|
|
|
246
248
|
- 🏠 Binds to `127.0.0.1` only — **do not expose to a network**.
|
|
247
|
-
-
|
|
249
|
+
- 🔑 A hub token is **auto-generated on first run** and persisted to `~/.specrails/hub.token` (mode `0600`). Every `/api/*` route requires it (except `/api/health` and `/api/hub/token`), and WebSocket upgrades carry it as a subprotocol. The browser client fetches it same-origin — there's nothing to configure.
|
|
248
250
|
- 🧷 Parameterised SQL everywhere — never string-interpolated.
|
|
249
251
|
- 🧬 Reserved files in your project (`.mcp.json`, `.specrails/plugins/state.json`, `.specrails/profiles/.user-preferred.json`) are mutated **surgically** — read → modify only owned keys → atomic temp+rename — so adding plugin N+1 never disturbs plugin N.
|
|
250
252
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{A as t,G as n,St as r,Vt as i,_t as a,at as o,bt as s,gt as c,it as l,xt as u,yt as d}from"./index-
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{A as t,G as n,St as r,Vt as i,_t as a,at as o,bt as s,gt as c,it as l,xt as u,yt as d}from"./index-hPtSDG5z.js";var f=a(`ban`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M4.929 4.929 19.07 19.071`,key:`196cmz`}]]),p=e(i(),1);function m(e){let t=new Set;return e.filter(e=>{let n=`${e.type}:${e.jobId}`;return t.has(n)?!1:(t.add(n),!0)})}function h({activeProjectId:e,limit:t=50}){let[n,i]=(0,p.useState)([]),[a,o]=(0,p.useState)(!1),[c,l]=(0,p.useState)(!0),u=(0,p.useRef)(e);(0,p.useEffect)(()=>{u.current=e},[e]);let{registerHandler:d,unregisterHandler:f}=s();(0,p.useEffect)(()=>{if(!e){i([]),l(!0);return}let n=!1;o(!0),i([]),l(!0);async function a(){let e=r();try{let r=await fetch(`${e}/activity?limit=${t}`);if(!r.ok||n)return;let a=await r.json();if(n)return;i(a),l(a.length===t)}catch{}finally{n||o(!1)}}return a(),()=>{n=!0}},[e,t]);let h=(0,p.useCallback)(async()=>{if(a||!c)return;o(!0);let e=r();try{i(n=>{let r=n[n.length-1];if(!r)return n;let a=encodeURIComponent(r.timestamp);return fetch(`${e}/activity?limit=${t}&before=${a}`).then(e=>e.json()).then(e=>{i(t=>m([...t,...e])),l(e.length===t),o(!1)}).catch(()=>o(!1)),n})}catch{o(!1)}},[a,c,t]),g=(0,p.useCallback)(e=>{let t=e,n=u.current;if(!(!t||typeof t.type!=`string`)&&!(t.projectId&&t.projectId!==n)){if(t.type===`queue`&&Array.isArray(t.jobs)){let e=[];for(let n of t.jobs){let t=n.status===`completed`?`job_completed`:n.status===`failed`?`job_failed`:n.status===`canceled`?`job_canceled`:`job_started`;e.push({id:`${t}:${n.id}`,type:t,jobId:n.id,jobCommand:n.command??``,timestamp:n.startedAt??new Date().toISOString(),summary:`${t.replace(`_`,` `)}: ${n.command??``}`,costUsd:null})}e.length>0&&i(t=>m([...e,...t]))}if(t.type===`phase`&&t.phase&&t.state&&t.timestamp){let e={id:`phase:${t.phase}:${t.state}:${t.timestamp}`,type:`job_started`,jobId:`phase-${t.phase}`,jobCommand:`Phase: ${t.phase} → ${t.state}`,timestamp:t.timestamp,summary:`Phase ${t.phase} is ${t.state}`,costUsd:null};i(t=>m([e,...t]))}}},[]);return(0,p.useLayoutEffect)(()=>(d(`activity`,g),()=>f(`activity`)),[g,d,f]),{items:n,loading:a,hasMore:c,loadMore:h}}var g=u();function _(e){let t=Date.now()-new Date(e).getTime(),n=Math.floor(t/1e3);if(n<60)return`${n}s ago`;let r=Math.floor(n/60);if(r<60)return`${r}m ago`;let i=Math.floor(r/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function v({type:e}){switch(e){case`job_completed`:return(0,g.jsx)(o,{className:`w-4 h-4 text-green-500 flex-shrink-0`});case`job_failed`:return(0,g.jsx)(l,{className:`w-4 h-4 text-red-500 flex-shrink-0`});case`job_canceled`:return(0,g.jsx)(f,{className:`w-4 h-4 text-muted-foreground flex-shrink-0`});default:return(0,g.jsx)(t,{className:`w-4 h-4 text-blue-500 flex-shrink-0`})}}function y(e){switch(e){case`job_completed`:return`Completed`;case`job_failed`:return`Failed`;case`job_canceled`:return`Canceled`;default:return`Started`}}function b(e){switch(e){case`job_completed`:return`text-green-500`;case`job_failed`:return`text-red-500`;case`job_canceled`:return`text-muted-foreground`;default:return`text-blue-500`}}function x(){let{activeProjectId:e}=d(),{items:t,loading:r,hasMore:i,loadMore:a}=h({activeProjectId:e}),o=(0,p.useRef)(null);return(0,p.useEffect)(()=>{let e=o.current;if(!e)return;let t=new IntersectionObserver(e=>{e[0].isIntersecting&&i&&!r&&a()},{threshold:.1});return t.observe(e),()=>t.disconnect()},[i,r,a]),(0,g.jsxs)(`div`,{className:`flex flex-col h-full overflow-hidden`,children:[(0,g.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 border-b border-border bg-background/50`,children:[(0,g.jsx)(c,{className:`w-4 h-4 text-muted-foreground`}),(0,g.jsx)(`h1`,{className:`text-sm font-medium`,children:`Activity`})]}),(0,g.jsxs)(`div`,{className:`flex-1 overflow-y-auto`,children:[r&&t.length===0?(0,g.jsx)(`div`,{className:`flex items-center justify-center h-32`,children:(0,g.jsx)(n,{className:`w-4 h-4 animate-spin text-muted-foreground`})}):t.length===0?(0,g.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-48 gap-2 text-muted-foreground`,children:[(0,g.jsx)(c,{className:`w-8 h-8 opacity-40`}),(0,g.jsx)(`p`,{className:`text-sm`,children:`No activity yet`}),(0,g.jsx)(`p`,{className:`text-xs opacity-70`,children:`Job events will appear here when jobs run`})]}):(0,g.jsx)(`ul`,{className:`divide-y divide-border/50`,children:t.map(e=>(0,g.jsxs)(`li`,{className:`flex items-center gap-3 px-4 py-2.5 hover:bg-accent/30 transition-colors`,children:[(0,g.jsx)(v,{type:e.type}),(0,g.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,g.jsx)(`p`,{className:`text-xs text-foreground truncate`,title:e.jobCommand,children:e.jobCommand}),(0,g.jsxs)(`div`,{className:`flex items-center gap-2 mt-0.5`,children:[(0,g.jsx)(`span`,{className:`text-xs font-medium ${b(e.type)}`,children:y(e.type)}),e.costUsd!=null&&(0,g.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`$`,e.costUsd.toFixed(4)]})]})]}),(0,g.jsx)(`span`,{className:`text-xs text-muted-foreground flex-shrink-0 tabular-nums`,children:_(e.timestamp)})]},`${e.type}:${e.jobId}`))}),(0,g.jsx)(`div`,{ref:o,className:`h-1`}),r&&t.length>0&&(0,g.jsx)(`div`,{className:`flex justify-center py-3`,children:(0,g.jsx)(n,{className:`w-4 h-4 animate-spin text-muted-foreground`})}),!i&&t.length>0&&(0,g.jsx)(`p`,{className:`text-center text-xs text-muted-foreground py-3`,children:`All activity loaded`})]})]})}export{x as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{$ as t,At as n,B as r,C as i,Ct as a,Dt as o,E as s,Et as c,F as l,Ft as u,G as d,H as f,I as p,L as m,M as h,Mt as g,N as _,Nt as v,O as y,Ot as b,P as x,Pt as S,S as C,St as w,T,Tt as E,U as D,Vt as O,W as k,X as A,_t as j,a as M,b as N,bt as P,ct as F,ft as I,ht as L,j as R,jt as z,kt as ee,lt as B,mt as V,ot as te,q as H,tt as ne,ut as U,w as W,wt as G,x as re,xt as ie,y as K,yt as ae}from"./index-CGRWJr7_.js";var oe=j(`flask-conical`,[[`path`,{d:`M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2`,key:`18mbvz`}],[`path`,{d:`M6.453 15h11.094`,key:`3shlmq`}],[`path`,{d:`M8.5 2h7`,key:`csnxdl`}]]),q=j(`history`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}],[`path`,{d:`M12 7v5l4 2`,key:`1fdv2h`}]]),se=j(`pin`,[[`path`,{d:`M12 17v5`,key:`bb1du9`}],[`path`,{d:`M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z`,key:`1nkz8b`}]]),ce=j(`wand-sparkles`,[[`path`,{d:`m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72`,key:`ul74o6`}],[`path`,{d:`m14 7 3 3`,key:`1r5n42`}],[`path`,{d:`M5 6v4`,key:`ilb8ba`}],[`path`,{d:`M19 14v4`,key:`blhpug`}],[`path`,{d:`M10 2v2`,key:`7u0qdc`}],[`path`,{d:`M7 8H3`,key:`zfb6yr`}],[`path`,{d:`M21 16h-4`,key:`1cnmox`}],[`path`,{d:`M11 3H9`,key:`1obp7u`}]]),J=e(O(),1),Y=ie(),X=/^[a-z0-9][a-z0-9-]*$/;function le({open:e,mode:t=`add`,initial:n,chainAgents:r,onConfirm:a,onCancel:o}){let[s,c]=(0,J.useState)(``),[l,u]=(0,J.useState)(r[0]??``);(0,J.useEffect)(()=>{e&&(t===`edit`&&n?(c(n.tags.join(`, `)),u(r.includes(n.agent)?n.agent:r[0]??``)):(c(``),u(r[0]??``)))},[e,t,n,r]);let d=s.split(`,`).map(e=>e.trim()).filter(Boolean),f=d.filter(e=>!X.test(e)),p=d.length>0&&f.length===0&&r.includes(l);return(0,Y.jsx)(K,{open:e,onOpenChange:e=>{e||o()},children:(0,Y.jsxs)(N,{className:`max-w-md`,children:[(0,Y.jsxs)(i,{children:[(0,Y.jsx)(W,{children:t===`edit`?`Edit routing rule`:`Add routing rule`}),(0,Y.jsx)(re,{children:t===`edit`?`Update the tags or target agent for this rule.`:`Add a tag-matched routing rule using lowercase kebab-case tags.`})]}),(0,Y.jsxs)(`div`,{className:`py-2 space-y-3`,children:[(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Tags`}),(0,Y.jsx)(M,{autoFocus:!0,value:s,onChange:e=>c(e.target.value),placeholder:`frontend, ui`,"aria-label":`Tags`,className:`text-sm font-mono`}),(0,Y.jsxs)(`p`,{className:`text-[11px] text-muted-foreground mt-1`,children:[`Comma-separated. Use lowercase kebab-case like `,(0,Y.jsx)(`code`,{children:`frontend`}),` or `,(0,Y.jsx)(`code`,{children:`api-design`}),`.`]}),f.length>0&&(0,Y.jsxs)(`p`,{className:`text-[11px] text-red-400 mt-1`,children:[`Invalid tag`,f.length===1?``:`s`,`: `,f.join(`, `),`. Tags must use lowercase letters, digits, and hyphens only.`]})]}),(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Route to`}),(0,Y.jsx)(`select`,{value:l,onChange:e=>u(e.target.value),"aria-label":`Route to`,className:`w-full h-9 px-2 text-sm rounded-md border border-border bg-background`,children:r.map(e=>(0,Y.jsx)(`option`,{value:e,children:e},e))}),(0,Y.jsx)(`p`,{className:`text-[11px] text-muted-foreground mt-1`,children:`Only agents in this profile's chain can be routing targets.`})]})]}),(0,Y.jsxs)(C,{children:[(0,Y.jsx)(y,{variant:`ghost`,size:`sm`,onClick:o,children:`Cancel`}),(0,Y.jsx)(y,{size:`sm`,onClick:()=>a(d,l),disabled:!p,children:t===`edit`?`Save changes`:`Add rule`})]})]})})}var Z=new Set([`sr-architect`,`sr-developer`,`sr-reviewer`,`sr-merge-resolver`]),ue=[`sonnet`,`opus`,`haiku`],de=/^[a-z0-9][a-z0-9-]*$/;function fe({profile:e,onChange:t,footer:r,onValidityChange:i,onSoftWarningsChange:s}){let[c,l]=(0,J.useState)([]),[u,d]=(0,J.useState)(!1),[p,m]=(0,J.useState)(!1),[h,_]=(0,J.useState)(null);(0,J.useEffect)(()=>{let e=!1;return fetch(`${w()}/profiles/catalog`).then(e=>e.ok?e.json():{agents:[]}).then(t=>{e||l(t.agents)}).catch(()=>{e||l([])}),()=>{e=!0}},[]);let x=n=>{let r=JSON.parse(JSON.stringify(e));n(r),t(r)},S=new Set(e.agents.map(e=>e.id)),C=c.filter(e=>!S.has(e.id)),T=(0,J.useMemo)(()=>{let t=[];for(let n of Z)e.agents.some(e=>e.id===n)||t.push(`Missing required baseline agent: ${n}`);let n=e.routing.filter(e=>`default`in e&&e.default===!0);if(n.length>1&&t.push(`Routing may have at most one default rule (found ${n.length})`),n.length===1){let n=e.routing[e.routing.length-1];`default`in n&&n.default===!0||t.push(`The default routing rule must be the last entry`)}for(let n of e.routing)if(e.agents.some(e=>e.id===n.agent)||t.push(`Routing references agent not in the chain: ${n.agent}`),`tags`in n){let e=n.tags.filter(e=>!de.test(e));e.length>0&&t.push(`Routing rule ${n.agent} has invalid tags: ${e.join(`, `)} (use lowercase kebab-case)`)}return t},[e]),D=(0,J.useMemo)(()=>{if(e.routing.length===0)return[];let t=new Set(e.routing.map(e=>e.agent));return e.agents.filter(e=>!Z.has(e.id)&&!t.has(e.id)).map(e=>e.id)},[e]),O=(0,J.useMemo)(()=>e.routing.some(e=>`default`in e&&e.default===!0),[e.routing]);(0,J.useEffect)(()=>{i&&i(T)},[T,i]),(0,J.useEffect)(()=>{s&&s({agentsMissingRouting:D})},[D,s]);let k=e=>{x(t=>{let n={id:e,model:`sonnet`},r=t.agents.findIndex(e=>e.id===`sr-merge-resolver`);r>=0?t.agents.splice(r,0,n):t.agents.push(n)}),d(!1)},A=t=>{let n=e.agents[t];Z.has(n.id)||x(e=>{e.agents.splice(t,1),e.routing=e.routing.filter(e=>e.agent!==n.id)})},j=(t,n)=>{if(t===n)return;let r=e.agents.findIndex(e=>e.id===t),i=e.agents.findIndex(e=>e.id===n);if(r<0||i<0)return;let a=G(e.agents,r,i),o=a.findIndex(e=>e.id===`sr-architect`);if(o>0){let[e]=a.splice(o,1);a.unshift(e)}let s=a.findIndex(e=>e.id===`sr-merge-resolver`);if(s>=0&&s!==a.length-1){let[e]=a.splice(s,1);a.push(e)}x(e=>{e.agents=a})},N=v(g(n,{activationConstraint:{distance:4}}),g(ee,{coordinateGetter:E})),P=e=>{let{active:t,over:n}=e;n&&j(String(t.id),String(n.id))},F=(e,t)=>{x(n=>{n.agents[e].model=t})},I=(e,t)=>{x(n=>{let r={tags:e,agent:t},i=n.routing.findIndex(e=>`default`in e&&e.default===!0);i>=0?n.routing.splice(i,0,r):n.routing.push(r)}),m(!1)},L=()=>{x(e=>{e.routing.some(e=>`default`in e&&e.default===!0)||e.agents.some(e=>e.id===`sr-developer`)&&e.routing.push({default:!0,agent:`sr-developer`})})},B=e=>`default`in e&&e.default===!0,V=(e,t)=>{x(n=>{let r=n.routing[e];r&&(B(r)||(r.agent=t))})},te=(e,t,n)=>{x(r=>{let i=r.routing[e];i&&(B(i)||(i.tags=t,i.agent=n))})},H=e=>{x(t=>{let n=t.routing[e];n&&(B(n)||t.routing.splice(e,1))})},ne=(t,n)=>{let r=t+n;if(r<0||r>=e.routing.length)return;let i=e.routing[t],a=e.routing[r];B(i)||B(a)||x(e=>{let[n]=e.routing.splice(t,1);e.routing.splice(r,0,n)})};return(0,Y.jsxs)(`div`,{className:`p-6 space-y-6 max-w-3xl`,children:[(0,Y.jsx)(le,{open:p,mode:`add`,chainAgents:e.agents.map(e=>e.id),onConfirm:I,onCancel:()=>m(!1)}),(0,Y.jsx)(le,{open:h!==null,mode:`edit`,initial:h!==null&&e.routing[h]&&!(`default`in e.routing[h])?{tags:e.routing[h].tags,agent:e.routing[h].agent}:void 0,chainAgents:e.agents.map(e=>e.id),onConfirm:(e,t)=>{h!==null&&(te(h,e,t),_(null))},onCancel:()=>_(null)}),T.length>0&&(0,Y.jsxs)(`div`,{className:`px-3 py-2 text-xs rounded-md border border-yellow-500/30 bg-yellow-500/10 text-yellow-500`,children:[(0,Y.jsxs)(`div`,{className:`font-medium mb-1`,children:[T.length,` validation `,T.length===1?`issue`:`issues`]}),(0,Y.jsx)(`ul`,{className:`list-disc list-inside space-y-0.5`,children:T.map((e,t)=>(0,Y.jsx)(`li`,{children:e},t))})]}),(0,Y.jsxs)(`section`,{className:`space-y-3`,children:[(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Name`}),(0,Y.jsx)(M,{value:e.name,disabled:!0,className:`text-sm`})]}),(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Description`}),(0,Y.jsx)(M,{value:e.description??``,onChange:e=>x(t=>{t.description=e.target.value}),className:`text-sm`,placeholder:`What is this profile for?`})]})]}),(0,Y.jsxs)(`section`,{children:[(0,Y.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2`,children:`Orchestrator`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-3 p-3 rounded-md border border-border`,children:[(0,Y.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,Y.jsx)(`div`,{className:`text-sm font-mono text-foreground truncate`,children:`/specrails:implement · /specrails:batch-implement`}),(0,Y.jsx)(`div`,{className:`text-[11px] text-muted-foreground mt-0.5`,children:`Top-level model for both commands. batch-implement delegates to implement per feature, so every rail it spawns inherits this profile's agent chain.`})]}),(0,Y.jsx)(he,{value:e.orchestrator.model,onChange:e=>x(t=>{t.orchestrator.model=e})})]})]}),(0,Y.jsxs)(`section`,{children:[(0,Y.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,Y.jsxs)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:[`Agent chain (`,e.agents.length,`)`]}),(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:()=>d(e=>!e),disabled:C.length===0,title:C.length===0?`All catalog agents are already in the chain`:`Add an agent from the catalog`,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1`}),` Add`]})]}),u&&(0,Y.jsxs)(`div`,{className:`mb-2 p-2 rounded-md border border-border bg-muted/30`,children:[(0,Y.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5 px-1`,children:[(0,Y.jsxs)(`span`,{className:`text-[11px] text-muted-foreground`,children:[`Pick from catalog (`,C.length,` available)`]}),(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:()=>d(!1),title:`Close`,children:(0,Y.jsx)(R,{className:`w-3 h-3`})})]}),C.length===0?(0,Y.jsx)(`div`,{className:`px-2 py-3 text-xs text-muted-foreground text-center`,children:`No more agents in the catalog. Add custom agents from the Agents Catalog tab.`}):(0,Y.jsx)(`div`,{className:`space-y-0.5 max-h-64 overflow-auto`,children:C.map(e=>(0,Y.jsxs)(`button`,{type:`button`,onClick:()=>k(e.id),className:`w-full flex items-center justify-between gap-2 px-2 py-1.5 text-left rounded hover:bg-accent transition-colors`,children:[(0,Y.jsx)(`span`,{className:`text-sm font-mono`,children:e.id}),(0,Y.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded `+(e.kind===`custom`?`bg-purple-500/15 text-purple-400`:`bg-muted text-muted-foreground`),children:e.kind})]},e.id))})]}),(0,Y.jsx)(b,{sensors:N,collisionDetection:z,onDragEnd:P,children:(0,Y.jsx)(a,{items:e.agents.map(e=>e.id),strategy:o,children:(0,Y.jsx)(`div`,{className:`space-y-1.5`,children:e.agents.map((e,t)=>(0,Y.jsx)(pe,{agent:e,canRemove:!Z.has(e.id),onModel:e=>F(t,e),onRemove:()=>A(t)},e.id))})})})]}),(0,Y.jsxs)(`section`,{children:[(0,Y.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,Y.jsxs)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:[`Routing (`,e.routing.length,`)`]}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-1`,children:[!O&&(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:L,disabled:e.agents.length===0,title:e.agents.length===0?`Add at least one agent before creating routing rules`:void 0,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1`}),` Add default`]}),(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:()=>m(!0),disabled:e.agents.length===0,title:e.agents.length===0?`Add at least one agent before creating routing rules`:void 0,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1`}),` Add rule`]})]})]}),(0,Y.jsx)(`p`,{className:`text-[11px] text-muted-foreground mb-2`,children:`First matching rule wins. Rules are editable and removable, and the default catch-all stays last when present. If you leave routing empty, the pipeline falls back to the first developer-shaped agent in the chain.`}),D.length>0&&(0,Y.jsxs)(`div`,{className:`mb-2 px-3 py-2 text-xs rounded-md border border-yellow-500/30 bg-yellow-500/10 text-yellow-500`,children:[(0,Y.jsx)(`div`,{className:`font-medium mb-1`,children:`Untargeted agents in the chain`}),(0,Y.jsxs)(`div`,{children:[`No routing rule points to: `,(0,Y.jsx)(`span`,{className:`font-mono`,children:D.join(`, `)}),`. Add a tag rule or retarget the default rule if you want them to run.`]})]}),(0,Y.jsx)(`div`,{className:`space-y-1.5`,children:e.routing.map((t,n)=>{let r=`default`in t&&t.default===!0;return(0,Y.jsx)(me,{rule:t,ordinal:n+1,isLast:n===e.routing.length-1,canMove:!r,canRemove:!r,canEdit:!r,chainAgents:e.agents.map(e=>e.id),onAgentChange:e=>V(n,e),onEdit:()=>_(n),onUp:()=>ne(n,-1),onDown:()=>ne(n,1),onRemove:()=>H(n)},n)})})]}),r&&(0,Y.jsx)(`div`,{className:`pt-3 border-t border-border`,children:r})]})}function pe({agent:e,canRemove:t,onModel:n,onRemove:r}){let i=Z.has(e.id),a=e.id===`sr-architect`,o=e.id===`sr-merge-resolver`,{attributes:s,listeners:l,setNodeRef:u,transform:d,transition:f,isDragging:p}=c({id:e.id});return(0,Y.jsxs)(`div`,{ref:u,style:{transform:S.Transform.toString(d),transition:f,opacity:p?.5:void 0,zIndex:p?10:void 0},className:`flex items-center gap-2 px-2 py-1.5 rounded-md border border-border group hover:bg-accent/30 transition-colors bg-background`,children:[(0,Y.jsx)(`button`,{type:`button`,className:`flex-shrink-0 p-0.5 rounded text-muted-foreground cursor-grab active:cursor-grabbing hover:text-foreground`,title:`Drag to reorder`,"aria-label":`Drag handle`,...s,...l,children:(0,Y.jsx)(H,{className:`w-3.5 h-3.5`})}),(0,Y.jsx)(`span`,{className:`text-sm font-mono flex-1 truncate`,children:e.id}),a&&(0,Y.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded bg-accent-primary/15 text-accent-primary`,title:`Pinned to first position — pipeline always starts with sr-architect`,children:[(0,Y.jsx)(se,{className:`w-2.5 h-2.5 rotate-[135deg]`}),` first`]}),o&&(0,Y.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded bg-accent-primary/15 text-accent-primary`,title:`Pinned to last position — merge phase always runs last`,children:[(0,Y.jsx)(se,{className:`w-2.5 h-2.5 rotate-45`}),` last`]}),i&&!a&&!o&&(0,Y.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground`,children:`required`}),(0,Y.jsx)(he,{value:e.model??`sonnet`,onChange:n}),(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-red-500/20 text-red-400 rounded disabled:opacity-30 disabled:cursor-not-allowed opacity-0 group-hover:opacity-100 transition-opacity`,onClick:r,disabled:!t,title:t?`Remove`:`Required baseline agent — the pipeline depends on this row`,children:(0,Y.jsx)(R,{className:`w-3 h-3`})})]})}function me({rule:e,ordinal:t,isLast:n,canMove:r,canRemove:i,canEdit:a,chainAgents:o,onAgentChange:s,onEdit:c,onUp:l,onDown:u,onRemove:d}){let f=`default`in e&&e.default===!0;return(0,Y.jsxs)(`div`,{className:`flex items-center gap-2 px-2 py-1.5 rounded-md border border-border group hover:bg-accent/30 transition-colors`,children:[(0,Y.jsxs)(`span`,{className:`text-[10px] font-mono text-muted-foreground w-5 text-center flex-shrink-0`,children:[t,`.`]}),f?(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground flex-1`,children:`everything else`}):(0,Y.jsx)(`span`,{className:`text-xs flex-1 flex gap-1 flex-wrap items-center`,children:e.tags.map(e=>(0,Y.jsx)(`span`,{className:`px-1.5 py-0.5 rounded bg-muted font-mono text-[11px]`,children:e},e))}),(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`→`}),f?(0,Y.jsx)(`span`,{className:`h-7 max-w-[15rem] px-2 text-xs font-mono rounded border border-border bg-muted/40 text-muted-foreground inline-flex items-center`,"aria-label":`Default routing target (core, read-only)`,title:`Core fallback — not editable`,children:e.agent}):(0,Y.jsx)(`select`,{value:e.agent,onChange:e=>s(e.target.value),"aria-label":`Routing target for rule ${t}`,className:`h-7 max-w-[15rem] px-2 text-xs font-mono rounded border border-border bg-background`,children:o.map(e=>(0,Y.jsx)(`option`,{value:e,children:e},e))}),(0,Y.jsxs)(`div`,{className:`flex gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity`,children:[a&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:c,title:`Edit rule`,"aria-label":`Edit rule ${t}`,children:(0,Y.jsx)(D,{className:`w-3 h-3`})}),r&&!n&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:u,title:`Move down`,children:(0,Y.jsx)(L,{className:`w-3 h-3`})}),r&&t>1&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:l,title:`Move up`,children:(0,Y.jsx)(I,{className:`w-3 h-3`})}),i&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-red-500/20 text-red-400 rounded`,onClick:d,title:`Remove`,children:(0,Y.jsx)(R,{className:`w-3 h-3`})})]}),f&&(0,Y.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground`,title:`Core fallback — the pipeline's last-resort rule, pinned to sr-developer`,children:`core · default`})]})}function he({value:e,onChange:t}){return(0,Y.jsx)(`select`,{value:e,onChange:e=>t(e.target.value),className:`h-7 px-2 text-xs rounded border border-border bg-background`,children:ue.map(e=>(0,Y.jsx)(`option`,{value:e,children:e},e))})}function ge({open:e,title:t,description:n,placeholder:r,initialValue:a=``,confirmLabel:o=`Confirm`,inputPattern:s,inputInvalidHint:c,onConfirm:l,onCancel:u}){let[d,f]=(0,J.useState)(a);(0,J.useEffect)(()=>{e&&f(a)},[e,a]);let p=d.trim(),m=!s||s.test(p),h=p.length>0&&m;return(0,Y.jsx)(K,{open:e,onOpenChange:e=>{e||u()},children:(0,Y.jsxs)(N,{className:`max-w-md`,children:[(0,Y.jsx)(i,{children:(0,Y.jsx)(W,{children:t})}),(0,Y.jsxs)(`div`,{className:`py-2 space-y-2`,children:[n&&(0,Y.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:n}),(0,Y.jsx)(M,{autoFocus:!0,value:d,placeholder:r,onChange:e=>f(e.target.value),onKeyDown:e=>{e.key===`Enter`&&h&&l(p)},className:`text-sm font-mono`}),p.length>0&&!m&&c&&(0,Y.jsx)(`p`,{className:`text-[11px] text-yellow-500`,children:c})]}),(0,Y.jsxs)(C,{children:[(0,Y.jsx)(y,{variant:`ghost`,size:`sm`,onClick:u,children:`Cancel`}),(0,Y.jsx)(y,{size:`sm`,onClick:()=>l(p),disabled:!h,children:o})]})]})})}function _e({open:e,title:t,description:n,confirmLabel:r=`Confirm`,destructive:a=!1,onConfirm:o,onCancel:s}){return(0,Y.jsx)(K,{open:e,onOpenChange:e=>{e||s()},children:(0,Y.jsxs)(N,{className:`max-w-md`,children:[(0,Y.jsx)(i,{children:(0,Y.jsx)(W,{children:t})}),n&&(0,Y.jsx)(`div`,{className:`py-2`,children:(0,Y.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:n})}),(0,Y.jsxs)(C,{children:[(0,Y.jsx)(y,{variant:`ghost`,size:`sm`,onClick:s,children:`Cancel`}),(0,Y.jsx)(y,{size:`sm`,onClick:o,className:a?`bg-red-500 hover:bg-red-600 text-white`:void 0,children:r})]})]})})}function ve(){let[e,t]=(0,J.useState)([]),[n,r]=(0,J.useState)(null),[i,a]=(0,J.useState)(null),[o,s]=(0,J.useState)(!0),[c,l]=(0,J.useState)(null),[d,p]=(0,J.useState)(!1),[h,g]=(0,J.useState)([]),[v,b]=(0,J.useState)([]),[x,S]=(0,J.useState)(!1),[C,T]=(0,J.useState)(null),[E,D]=(0,J.useState)(null),O=(0,J.useCallback)(async()=>{s(!0),l(null);try{let e=await fetch(`${w()}/profiles`);if(!e.ok)throw Error(`List failed: ${e.status}`);let i=await e.json();t(i.profiles),i.profiles.length>0&&!n&&r(i.profiles[0].name)}catch(e){l(e.message)}finally{s(!1)}},[n]);(0,J.useEffect)(()=>{O()},[O]),(0,J.useEffect)(()=>{if(!n){a(null);return}let e=!1;return fetch(`${w()}/profiles/${encodeURIComponent(n)}`).then(e=>{if(!e.ok)throw Error(`Load failed: ${e.status}`);return e.json()}).then(t=>{e||a(t.profile)}).catch(t=>{e||l(t.message)}),()=>{e=!0}},[n]);let k=(0,J.useCallback)(async()=>{p(!0),l(null);try{let e=await fetch(`${w()}/profiles/migrate-from-settings`,{method:`POST`});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??`Migration failed: ${e.status}`)}await O(),r(`default`),u.success(`Profile migrated`,{description:`default profile created from your current agents`})}catch(e){let t=e.message;l(t),u.error(`Migration failed`,{description:t})}finally{p(!1)}},[O]),A=(0,J.useCallback)(async e=>{S(!1),p(!0),l(null);try{let t={schemaVersion:1,name:e,description:``,orchestrator:{model:`sonnet`},agents:[{id:`sr-architect`,model:`sonnet`,required:!0},{id:`sr-developer`,model:`sonnet`,required:!0},{id:`sr-reviewer`,model:`sonnet`,required:!0},{id:`sr-merge-resolver`,model:`sonnet`,required:!0}],routing:[{default:!0,agent:`sr-developer`}]},n=await fetch(`${w()}/profiles`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Create failed: ${n.status}`)}await O(),r(e),u.success(`Profile created`,{description:e})}catch(e){let t=e.message;l(t),u.error(`Failed to create profile`,{description:t})}finally{p(!1)}},[O]),j=(0,J.useCallback)(async(e,t)=>{T(null),p(!0),l(null);try{let n=await fetch(`${w()}/profiles/${encodeURIComponent(e)}/duplicate`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({name:t})});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Duplicate failed: ${n.status}`)}await O(),r(t),u.success(`Profile duplicated`,{description:`${e} → ${t}`})}catch(e){let t=e.message;l(t),u.error(`Failed to duplicate profile`,{description:t})}finally{p(!1)}},[O]),M=(0,J.useCallback)(async e=>{D(null),p(!0),l(null);try{let t=await fetch(`${w()}/profiles/${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error??`Delete failed: ${t.status}`)}r(t=>t===e?null:t),await O(),u.success(`Profile deleted`,{description:e})}catch(e){let t=e.message;l(t),u.error(`Failed to delete profile`,{description:t})}finally{p(!1)}},[O]),N=(0,J.useCallback)(()=>S(!0),[]),P=(0,J.useCallback)(e=>T({from:e}),[]),F=(0,J.useCallback)(e=>D({name:e}),[]),I=(0,J.useCallback)(async(e,t)=>{p(!0),l(null);try{let n=await fetch(`${w()}/profiles/${encodeURIComponent(e.name)}`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Save failed: ${n.status}`)}a(e),t.length>0?u.warning(`Profile saved with untargeted agents`,{description:`No routing rule points to: ${t.join(`, `)}. Add a tag rule or retarget the default rule if you want them to run.`,duration:6e3}):u.success(`Profile saved`,{description:e.name})}catch(e){let t=e.message;l(t),u.error(`Failed to save profile`,{description:t})}finally{p(!1)}},[]),L=(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(ge,{open:x,title:`New profile`,description:`Pick a lowercase kebab-case name (letters, digits, and hyphens).`,placeholder:`my-profile`,confirmLabel:`Create`,inputPattern:/^[a-z0-9][a-z0-9-]*$/,inputInvalidHint:`Must start with a letter or digit and contain only lowercase letters, digits, and hyphens.`,onConfirm:e=>void A(e),onCancel:()=>S(!1)}),C&&(0,Y.jsx)(ge,{open:!0,title:`Duplicate "${C.from}"`,description:`Name for the new profile.`,placeholder:`${C.from}-copy`,initialValue:`${C.from}-copy`,confirmLabel:`Duplicate`,inputPattern:/^[a-z0-9][a-z0-9-]*$/,inputInvalidHint:`Lowercase kebab-case only.`,onConfirm:e=>void j(C.from,e),onCancel:()=>T(null)}),E&&(0,Y.jsx)(_e,{open:!0,title:`Delete profile "${E.name}"?`,description:`This cannot be undone. Jobs already launched with this profile keep their snapshot; future launches will fall back to the resolution order.`,confirmLabel:`Delete`,destructive:!0,onConfirm:()=>void M(E.name),onCancel:()=>D(null)})]});return o?(0,Y.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,Y.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Loading profiles…`})}):e.length===0?(0,Y.jsxs)(Y.Fragment,{children:[L,(0,Y.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,Y.jsxs)(`div`,{className:`text-center max-w-md`,children:[(0,Y.jsx)(`div`,{className:`text-sm font-medium text-foreground`,children:`No profiles yet`}),(0,Y.jsx)(`div`,{className:`text-xs text-muted-foreground mt-1 mb-4`,children:`Profiles let you save orchestrator + agent + routing combinations and pick one per rail.`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-2 justify-center`,children:[(0,Y.jsxs)(y,{size:`sm`,onClick:k,disabled:d,children:[(0,Y.jsx)(ce,{className:`w-3.5 h-3.5 mr-1.5`}),` Migrate from current agents`]}),(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:N,disabled:d,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1.5`}),` Blank profile`]})]}),(0,Y.jsxs)(`div`,{className:`text-[11px] text-muted-foreground/70 mt-3`,children:[`"Migrate" reads your existing `,(0,Y.jsx)(`code`,{className:`text-foreground`,children:`.claude/agents/`}),` `,`frontmatter models and creates a `,(0,Y.jsx)(`code`,{className:`text-foreground`,children:`default`}),` profile mirroring today's behavior — zero-loss.`]}),c&&(0,Y.jsx)(`div`,{className:`mt-3 text-xs text-red-400`,children:c})]})})]}):(0,Y.jsxs)(`div`,{className:`flex flex-col h-full`,children:[L,(0,Y.jsxs)(`div`,{className:`flex flex-1 min-h-0`,children:[(0,Y.jsxs)(`aside`,{className:`w-64 flex-shrink-0 border-r border-border flex flex-col`,children:[(0,Y.jsxs)(`div`,{className:`p-3 flex items-center justify-between`,children:[(0,Y.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:`Profiles`}),(0,Y.jsx)(y,{size:`sm`,variant:`ghost`,onClick:N,disabled:d,children:(0,Y.jsx)(f,{className:`w-3.5 h-3.5`})})]}),(0,Y.jsx)(`div`,{className:`flex-1 overflow-auto px-2 pb-3`,children:e.map(e=>(0,Y.jsxs)(`div`,{className:`group mb-1 rounded-md px-2 py-1.5 text-xs cursor-pointer transition-colors flex items-center justify-between `+(e.name===n?`bg-accent text-foreground`:`text-muted-foreground hover:bg-accent/50 hover:text-foreground`),onClick:()=>r(e.name),role:`button`,tabIndex:0,onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&r(e.name)},children:[(0,Y.jsxs)(`div`,{className:`flex items-center gap-1.5 min-w-0`,children:[(0,Y.jsx)(`span`,{className:`truncate font-medium`,children:e.name}),e.isDefault&&(0,Y.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`(team default)`})]}),(0,Y.jsxs)(`div`,{className:`flex gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity`,children:[(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,title:`Duplicate`,onClick:t=>{t.stopPropagation(),P(e.name)},children:(0,Y.jsx)(ne,{className:`w-3 h-3`})}),!e.isDefault&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-red-500/20 text-red-400 rounded`,title:`Delete`,onClick:t=>{t.stopPropagation(),F(e.name)},children:(0,Y.jsx)(_,{className:`w-3 h-3`})})]})]},e.name))})]}),(0,Y.jsxs)(`main`,{className:`flex-1 overflow-auto`,children:[c&&(0,Y.jsx)(`div`,{className:`mx-4 mt-4 px-3 py-2 text-xs rounded border border-red-500/30 bg-red-500/10 text-red-400`,children:c}),i?(0,Y.jsx)(fe,{profile:i,onChange:a,onValidityChange:g,onSoftWarningsChange:e=>b(e.agentsMissingRouting),footer:(0,Y.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,Y.jsxs)(y,{size:`sm`,onClick:()=>void I(i,v),disabled:d||h.length>0,title:h.length>0?`Fix validation issues before saving`:void 0,children:[(0,Y.jsx)(m,{className:`w-3.5 h-3.5 mr-1.5`}),`Save`]}),d&&(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Saving…`}),h.length>0&&(0,Y.jsxs)(`span`,{className:`text-xs text-yellow-500`,children:[h.length,` `,h.length===1?`issue`:`issues`,` to resolve`]})]})},i.name):(0,Y.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,Y.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Select a profile to edit`})})]})]})]})}function Q(e){let t=e.workflow.map((e,t)=>`${t+1}. ${e}`).join(`
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{$ as t,At as n,B as r,C as i,Ct as a,Dt as o,E as s,Et as c,F as l,Ft as u,G as d,H as f,I as p,L as m,M as h,Mt as g,N as _,Nt as v,O as y,Ot as b,P as x,Pt as S,S as C,St as w,T,Tt as E,U as D,Vt as O,W as k,X as A,_t as j,a as M,b as N,bt as P,ct as F,ft as I,ht as L,j as R,jt as z,kt as ee,lt as B,mt as V,ot as te,q as H,tt as ne,ut as U,w as W,wt as G,x as re,xt as ie,y as K,yt as ae}from"./index-hPtSDG5z.js";var oe=j(`flask-conical`,[[`path`,{d:`M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2`,key:`18mbvz`}],[`path`,{d:`M6.453 15h11.094`,key:`3shlmq`}],[`path`,{d:`M8.5 2h7`,key:`csnxdl`}]]),q=j(`history`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}],[`path`,{d:`M12 7v5l4 2`,key:`1fdv2h`}]]),se=j(`pin`,[[`path`,{d:`M12 17v5`,key:`bb1du9`}],[`path`,{d:`M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z`,key:`1nkz8b`}]]),ce=j(`wand-sparkles`,[[`path`,{d:`m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72`,key:`ul74o6`}],[`path`,{d:`m14 7 3 3`,key:`1r5n42`}],[`path`,{d:`M5 6v4`,key:`ilb8ba`}],[`path`,{d:`M19 14v4`,key:`blhpug`}],[`path`,{d:`M10 2v2`,key:`7u0qdc`}],[`path`,{d:`M7 8H3`,key:`zfb6yr`}],[`path`,{d:`M21 16h-4`,key:`1cnmox`}],[`path`,{d:`M11 3H9`,key:`1obp7u`}]]),J=e(O(),1),Y=ie(),X=/^[a-z0-9][a-z0-9-]*$/;function le({open:e,mode:t=`add`,initial:n,chainAgents:r,onConfirm:a,onCancel:o}){let[s,c]=(0,J.useState)(``),[l,u]=(0,J.useState)(r[0]??``);(0,J.useEffect)(()=>{e&&(t===`edit`&&n?(c(n.tags.join(`, `)),u(r.includes(n.agent)?n.agent:r[0]??``)):(c(``),u(r[0]??``)))},[e,t,n,r]);let d=s.split(`,`).map(e=>e.trim()).filter(Boolean),f=d.filter(e=>!X.test(e)),p=d.length>0&&f.length===0&&r.includes(l);return(0,Y.jsx)(K,{open:e,onOpenChange:e=>{e||o()},children:(0,Y.jsxs)(N,{className:`max-w-md`,children:[(0,Y.jsxs)(i,{children:[(0,Y.jsx)(W,{children:t===`edit`?`Edit routing rule`:`Add routing rule`}),(0,Y.jsx)(re,{children:t===`edit`?`Update the tags or target agent for this rule.`:`Add a tag-matched routing rule using lowercase kebab-case tags.`})]}),(0,Y.jsxs)(`div`,{className:`py-2 space-y-3`,children:[(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Tags`}),(0,Y.jsx)(M,{autoFocus:!0,value:s,onChange:e=>c(e.target.value),placeholder:`frontend, ui`,"aria-label":`Tags`,className:`text-sm font-mono`}),(0,Y.jsxs)(`p`,{className:`text-[11px] text-muted-foreground mt-1`,children:[`Comma-separated. Use lowercase kebab-case like `,(0,Y.jsx)(`code`,{children:`frontend`}),` or `,(0,Y.jsx)(`code`,{children:`api-design`}),`.`]}),f.length>0&&(0,Y.jsxs)(`p`,{className:`text-[11px] text-red-400 mt-1`,children:[`Invalid tag`,f.length===1?``:`s`,`: `,f.join(`, `),`. Tags must use lowercase letters, digits, and hyphens only.`]})]}),(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Route to`}),(0,Y.jsx)(`select`,{value:l,onChange:e=>u(e.target.value),"aria-label":`Route to`,className:`w-full h-9 px-2 text-sm rounded-md border border-border bg-background`,children:r.map(e=>(0,Y.jsx)(`option`,{value:e,children:e},e))}),(0,Y.jsx)(`p`,{className:`text-[11px] text-muted-foreground mt-1`,children:`Only agents in this profile's chain can be routing targets.`})]})]}),(0,Y.jsxs)(C,{children:[(0,Y.jsx)(y,{variant:`ghost`,size:`sm`,onClick:o,children:`Cancel`}),(0,Y.jsx)(y,{size:`sm`,onClick:()=>a(d,l),disabled:!p,children:t===`edit`?`Save changes`:`Add rule`})]})]})})}var Z=new Set([`sr-architect`,`sr-developer`,`sr-reviewer`,`sr-merge-resolver`]),ue=[`sonnet`,`opus`,`haiku`],de=/^[a-z0-9][a-z0-9-]*$/;function fe({profile:e,onChange:t,footer:r,onValidityChange:i,onSoftWarningsChange:s}){let[c,l]=(0,J.useState)([]),[u,d]=(0,J.useState)(!1),[p,m]=(0,J.useState)(!1),[h,_]=(0,J.useState)(null);(0,J.useEffect)(()=>{let e=!1;return fetch(`${w()}/profiles/catalog`).then(e=>e.ok?e.json():{agents:[]}).then(t=>{e||l(t.agents)}).catch(()=>{e||l([])}),()=>{e=!0}},[]);let x=n=>{let r=JSON.parse(JSON.stringify(e));n(r),t(r)},S=new Set(e.agents.map(e=>e.id)),C=c.filter(e=>!S.has(e.id)),T=(0,J.useMemo)(()=>{let t=[];for(let n of Z)e.agents.some(e=>e.id===n)||t.push(`Missing required baseline agent: ${n}`);let n=e.routing.filter(e=>`default`in e&&e.default===!0);if(n.length>1&&t.push(`Routing may have at most one default rule (found ${n.length})`),n.length===1){let n=e.routing[e.routing.length-1];`default`in n&&n.default===!0||t.push(`The default routing rule must be the last entry`)}for(let n of e.routing)if(e.agents.some(e=>e.id===n.agent)||t.push(`Routing references agent not in the chain: ${n.agent}`),`tags`in n){let e=n.tags.filter(e=>!de.test(e));e.length>0&&t.push(`Routing rule ${n.agent} has invalid tags: ${e.join(`, `)} (use lowercase kebab-case)`)}return t},[e]),D=(0,J.useMemo)(()=>{if(e.routing.length===0)return[];let t=new Set(e.routing.map(e=>e.agent));return e.agents.filter(e=>!Z.has(e.id)&&!t.has(e.id)).map(e=>e.id)},[e]),O=(0,J.useMemo)(()=>e.routing.some(e=>`default`in e&&e.default===!0),[e.routing]);(0,J.useEffect)(()=>{i&&i(T)},[T,i]),(0,J.useEffect)(()=>{s&&s({agentsMissingRouting:D})},[D,s]);let k=e=>{x(t=>{let n={id:e,model:`sonnet`},r=t.agents.findIndex(e=>e.id===`sr-merge-resolver`);r>=0?t.agents.splice(r,0,n):t.agents.push(n)}),d(!1)},A=t=>{let n=e.agents[t];Z.has(n.id)||x(e=>{e.agents.splice(t,1),e.routing=e.routing.filter(e=>e.agent!==n.id)})},j=(t,n)=>{if(t===n)return;let r=e.agents.findIndex(e=>e.id===t),i=e.agents.findIndex(e=>e.id===n);if(r<0||i<0)return;let a=G(e.agents,r,i),o=a.findIndex(e=>e.id===`sr-architect`);if(o>0){let[e]=a.splice(o,1);a.unshift(e)}let s=a.findIndex(e=>e.id===`sr-merge-resolver`);if(s>=0&&s!==a.length-1){let[e]=a.splice(s,1);a.push(e)}x(e=>{e.agents=a})},N=v(g(n,{activationConstraint:{distance:4}}),g(ee,{coordinateGetter:E})),P=e=>{let{active:t,over:n}=e;n&&j(String(t.id),String(n.id))},F=(e,t)=>{x(n=>{n.agents[e].model=t})},I=(e,t)=>{x(n=>{let r={tags:e,agent:t},i=n.routing.findIndex(e=>`default`in e&&e.default===!0);i>=0?n.routing.splice(i,0,r):n.routing.push(r)}),m(!1)},L=()=>{x(e=>{e.routing.some(e=>`default`in e&&e.default===!0)||e.agents.some(e=>e.id===`sr-developer`)&&e.routing.push({default:!0,agent:`sr-developer`})})},B=e=>`default`in e&&e.default===!0,V=(e,t)=>{x(n=>{let r=n.routing[e];r&&(B(r)||(r.agent=t))})},te=(e,t,n)=>{x(r=>{let i=r.routing[e];i&&(B(i)||(i.tags=t,i.agent=n))})},H=e=>{x(t=>{let n=t.routing[e];n&&(B(n)||t.routing.splice(e,1))})},ne=(t,n)=>{let r=t+n;if(r<0||r>=e.routing.length)return;let i=e.routing[t],a=e.routing[r];B(i)||B(a)||x(e=>{let[n]=e.routing.splice(t,1);e.routing.splice(r,0,n)})};return(0,Y.jsxs)(`div`,{className:`p-6 space-y-6 max-w-3xl`,children:[(0,Y.jsx)(le,{open:p,mode:`add`,chainAgents:e.agents.map(e=>e.id),onConfirm:I,onCancel:()=>m(!1)}),(0,Y.jsx)(le,{open:h!==null,mode:`edit`,initial:h!==null&&e.routing[h]&&!(`default`in e.routing[h])?{tags:e.routing[h].tags,agent:e.routing[h].agent}:void 0,chainAgents:e.agents.map(e=>e.id),onConfirm:(e,t)=>{h!==null&&(te(h,e,t),_(null))},onCancel:()=>_(null)}),T.length>0&&(0,Y.jsxs)(`div`,{className:`px-3 py-2 text-xs rounded-md border border-yellow-500/30 bg-yellow-500/10 text-yellow-500`,children:[(0,Y.jsxs)(`div`,{className:`font-medium mb-1`,children:[T.length,` validation `,T.length===1?`issue`:`issues`]}),(0,Y.jsx)(`ul`,{className:`list-disc list-inside space-y-0.5`,children:T.map((e,t)=>(0,Y.jsx)(`li`,{children:e},t))})]}),(0,Y.jsxs)(`section`,{className:`space-y-3`,children:[(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Name`}),(0,Y.jsx)(M,{value:e.name,disabled:!0,className:`text-sm`})]}),(0,Y.jsxs)(`div`,{children:[(0,Y.jsx)(`label`,{className:`block text-xs font-medium text-muted-foreground mb-1`,children:`Description`}),(0,Y.jsx)(M,{value:e.description??``,onChange:e=>x(t=>{t.description=e.target.value}),className:`text-sm`,placeholder:`What is this profile for?`})]})]}),(0,Y.jsxs)(`section`,{children:[(0,Y.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2`,children:`Orchestrator`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-3 p-3 rounded-md border border-border`,children:[(0,Y.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,Y.jsx)(`div`,{className:`text-sm font-mono text-foreground truncate`,children:`/specrails:implement · /specrails:batch-implement`}),(0,Y.jsx)(`div`,{className:`text-[11px] text-muted-foreground mt-0.5`,children:`Top-level model for both commands. batch-implement delegates to implement per feature, so every rail it spawns inherits this profile's agent chain.`})]}),(0,Y.jsx)(he,{value:e.orchestrator.model,onChange:e=>x(t=>{t.orchestrator.model=e})})]})]}),(0,Y.jsxs)(`section`,{children:[(0,Y.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,Y.jsxs)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:[`Agent chain (`,e.agents.length,`)`]}),(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:()=>d(e=>!e),disabled:C.length===0,title:C.length===0?`All catalog agents are already in the chain`:`Add an agent from the catalog`,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1`}),` Add`]})]}),u&&(0,Y.jsxs)(`div`,{className:`mb-2 p-2 rounded-md border border-border bg-muted/30`,children:[(0,Y.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5 px-1`,children:[(0,Y.jsxs)(`span`,{className:`text-[11px] text-muted-foreground`,children:[`Pick from catalog (`,C.length,` available)`]}),(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:()=>d(!1),title:`Close`,children:(0,Y.jsx)(R,{className:`w-3 h-3`})})]}),C.length===0?(0,Y.jsx)(`div`,{className:`px-2 py-3 text-xs text-muted-foreground text-center`,children:`No more agents in the catalog. Add custom agents from the Agents Catalog tab.`}):(0,Y.jsx)(`div`,{className:`space-y-0.5 max-h-64 overflow-auto`,children:C.map(e=>(0,Y.jsxs)(`button`,{type:`button`,onClick:()=>k(e.id),className:`w-full flex items-center justify-between gap-2 px-2 py-1.5 text-left rounded hover:bg-accent transition-colors`,children:[(0,Y.jsx)(`span`,{className:`text-sm font-mono`,children:e.id}),(0,Y.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded `+(e.kind===`custom`?`bg-purple-500/15 text-purple-400`:`bg-muted text-muted-foreground`),children:e.kind})]},e.id))})]}),(0,Y.jsx)(b,{sensors:N,collisionDetection:z,onDragEnd:P,children:(0,Y.jsx)(a,{items:e.agents.map(e=>e.id),strategy:o,children:(0,Y.jsx)(`div`,{className:`space-y-1.5`,children:e.agents.map((e,t)=>(0,Y.jsx)(pe,{agent:e,canRemove:!Z.has(e.id),onModel:e=>F(t,e),onRemove:()=>A(t)},e.id))})})})]}),(0,Y.jsxs)(`section`,{children:[(0,Y.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,Y.jsxs)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:[`Routing (`,e.routing.length,`)`]}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-1`,children:[!O&&(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:L,disabled:e.agents.length===0,title:e.agents.length===0?`Add at least one agent before creating routing rules`:void 0,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1`}),` Add default`]}),(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:()=>m(!0),disabled:e.agents.length===0,title:e.agents.length===0?`Add at least one agent before creating routing rules`:void 0,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1`}),` Add rule`]})]})]}),(0,Y.jsx)(`p`,{className:`text-[11px] text-muted-foreground mb-2`,children:`First matching rule wins. Rules are editable and removable, and the default catch-all stays last when present. If you leave routing empty, the pipeline falls back to the first developer-shaped agent in the chain.`}),D.length>0&&(0,Y.jsxs)(`div`,{className:`mb-2 px-3 py-2 text-xs rounded-md border border-yellow-500/30 bg-yellow-500/10 text-yellow-500`,children:[(0,Y.jsx)(`div`,{className:`font-medium mb-1`,children:`Untargeted agents in the chain`}),(0,Y.jsxs)(`div`,{children:[`No routing rule points to: `,(0,Y.jsx)(`span`,{className:`font-mono`,children:D.join(`, `)}),`. Add a tag rule or retarget the default rule if you want them to run.`]})]}),(0,Y.jsx)(`div`,{className:`space-y-1.5`,children:e.routing.map((t,n)=>{let r=`default`in t&&t.default===!0;return(0,Y.jsx)(me,{rule:t,ordinal:n+1,isLast:n===e.routing.length-1,canMove:!r,canRemove:!r,canEdit:!r,chainAgents:e.agents.map(e=>e.id),onAgentChange:e=>V(n,e),onEdit:()=>_(n),onUp:()=>ne(n,-1),onDown:()=>ne(n,1),onRemove:()=>H(n)},n)})})]}),r&&(0,Y.jsx)(`div`,{className:`pt-3 border-t border-border`,children:r})]})}function pe({agent:e,canRemove:t,onModel:n,onRemove:r}){let i=Z.has(e.id),a=e.id===`sr-architect`,o=e.id===`sr-merge-resolver`,{attributes:s,listeners:l,setNodeRef:u,transform:d,transition:f,isDragging:p}=c({id:e.id});return(0,Y.jsxs)(`div`,{ref:u,style:{transform:S.Transform.toString(d),transition:f,opacity:p?.5:void 0,zIndex:p?10:void 0},className:`flex items-center gap-2 px-2 py-1.5 rounded-md border border-border group hover:bg-accent/30 transition-colors bg-background`,children:[(0,Y.jsx)(`button`,{type:`button`,className:`flex-shrink-0 p-0.5 rounded text-muted-foreground cursor-grab active:cursor-grabbing hover:text-foreground`,title:`Drag to reorder`,"aria-label":`Drag handle`,...s,...l,children:(0,Y.jsx)(H,{className:`w-3.5 h-3.5`})}),(0,Y.jsx)(`span`,{className:`text-sm font-mono flex-1 truncate`,children:e.id}),a&&(0,Y.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded bg-accent-primary/15 text-accent-primary`,title:`Pinned to first position — pipeline always starts with sr-architect`,children:[(0,Y.jsx)(se,{className:`w-2.5 h-2.5 rotate-[135deg]`}),` first`]}),o&&(0,Y.jsxs)(`span`,{className:`inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded bg-accent-primary/15 text-accent-primary`,title:`Pinned to last position — merge phase always runs last`,children:[(0,Y.jsx)(se,{className:`w-2.5 h-2.5 rotate-45`}),` last`]}),i&&!a&&!o&&(0,Y.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground`,children:`required`}),(0,Y.jsx)(he,{value:e.model??`sonnet`,onChange:n}),(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-red-500/20 text-red-400 rounded disabled:opacity-30 disabled:cursor-not-allowed opacity-0 group-hover:opacity-100 transition-opacity`,onClick:r,disabled:!t,title:t?`Remove`:`Required baseline agent — the pipeline depends on this row`,children:(0,Y.jsx)(R,{className:`w-3 h-3`})})]})}function me({rule:e,ordinal:t,isLast:n,canMove:r,canRemove:i,canEdit:a,chainAgents:o,onAgentChange:s,onEdit:c,onUp:l,onDown:u,onRemove:d}){let f=`default`in e&&e.default===!0;return(0,Y.jsxs)(`div`,{className:`flex items-center gap-2 px-2 py-1.5 rounded-md border border-border group hover:bg-accent/30 transition-colors`,children:[(0,Y.jsxs)(`span`,{className:`text-[10px] font-mono text-muted-foreground w-5 text-center flex-shrink-0`,children:[t,`.`]}),f?(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground flex-1`,children:`everything else`}):(0,Y.jsx)(`span`,{className:`text-xs flex-1 flex gap-1 flex-wrap items-center`,children:e.tags.map(e=>(0,Y.jsx)(`span`,{className:`px-1.5 py-0.5 rounded bg-muted font-mono text-[11px]`,children:e},e))}),(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`→`}),f?(0,Y.jsx)(`span`,{className:`h-7 max-w-[15rem] px-2 text-xs font-mono rounded border border-border bg-muted/40 text-muted-foreground inline-flex items-center`,"aria-label":`Default routing target (core, read-only)`,title:`Core fallback — not editable`,children:e.agent}):(0,Y.jsx)(`select`,{value:e.agent,onChange:e=>s(e.target.value),"aria-label":`Routing target for rule ${t}`,className:`h-7 max-w-[15rem] px-2 text-xs font-mono rounded border border-border bg-background`,children:o.map(e=>(0,Y.jsx)(`option`,{value:e,children:e},e))}),(0,Y.jsxs)(`div`,{className:`flex gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity`,children:[a&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:c,title:`Edit rule`,"aria-label":`Edit rule ${t}`,children:(0,Y.jsx)(D,{className:`w-3 h-3`})}),r&&!n&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:u,title:`Move down`,children:(0,Y.jsx)(L,{className:`w-3 h-3`})}),r&&t>1&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,onClick:l,title:`Move up`,children:(0,Y.jsx)(I,{className:`w-3 h-3`})}),i&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-red-500/20 text-red-400 rounded`,onClick:d,title:`Remove`,children:(0,Y.jsx)(R,{className:`w-3 h-3`})})]}),f&&(0,Y.jsx)(`span`,{className:`text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground`,title:`Core fallback — the pipeline's last-resort rule, pinned to sr-developer`,children:`core · default`})]})}function he({value:e,onChange:t}){return(0,Y.jsx)(`select`,{value:e,onChange:e=>t(e.target.value),className:`h-7 px-2 text-xs rounded border border-border bg-background`,children:ue.map(e=>(0,Y.jsx)(`option`,{value:e,children:e},e))})}function ge({open:e,title:t,description:n,placeholder:r,initialValue:a=``,confirmLabel:o=`Confirm`,inputPattern:s,inputInvalidHint:c,onConfirm:l,onCancel:u}){let[d,f]=(0,J.useState)(a);(0,J.useEffect)(()=>{e&&f(a)},[e,a]);let p=d.trim(),m=!s||s.test(p),h=p.length>0&&m;return(0,Y.jsx)(K,{open:e,onOpenChange:e=>{e||u()},children:(0,Y.jsxs)(N,{className:`max-w-md`,children:[(0,Y.jsx)(i,{children:(0,Y.jsx)(W,{children:t})}),(0,Y.jsxs)(`div`,{className:`py-2 space-y-2`,children:[n&&(0,Y.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:n}),(0,Y.jsx)(M,{autoFocus:!0,value:d,placeholder:r,onChange:e=>f(e.target.value),onKeyDown:e=>{e.key===`Enter`&&h&&l(p)},className:`text-sm font-mono`}),p.length>0&&!m&&c&&(0,Y.jsx)(`p`,{className:`text-[11px] text-yellow-500`,children:c})]}),(0,Y.jsxs)(C,{children:[(0,Y.jsx)(y,{variant:`ghost`,size:`sm`,onClick:u,children:`Cancel`}),(0,Y.jsx)(y,{size:`sm`,onClick:()=>l(p),disabled:!h,children:o})]})]})})}function _e({open:e,title:t,description:n,confirmLabel:r=`Confirm`,destructive:a=!1,onConfirm:o,onCancel:s}){return(0,Y.jsx)(K,{open:e,onOpenChange:e=>{e||s()},children:(0,Y.jsxs)(N,{className:`max-w-md`,children:[(0,Y.jsx)(i,{children:(0,Y.jsx)(W,{children:t})}),n&&(0,Y.jsx)(`div`,{className:`py-2`,children:(0,Y.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:n})}),(0,Y.jsxs)(C,{children:[(0,Y.jsx)(y,{variant:`ghost`,size:`sm`,onClick:s,children:`Cancel`}),(0,Y.jsx)(y,{size:`sm`,onClick:o,className:a?`bg-red-500 hover:bg-red-600 text-white`:void 0,children:r})]})]})})}function ve(){let[e,t]=(0,J.useState)([]),[n,r]=(0,J.useState)(null),[i,a]=(0,J.useState)(null),[o,s]=(0,J.useState)(!0),[c,l]=(0,J.useState)(null),[d,p]=(0,J.useState)(!1),[h,g]=(0,J.useState)([]),[v,b]=(0,J.useState)([]),[x,S]=(0,J.useState)(!1),[C,T]=(0,J.useState)(null),[E,D]=(0,J.useState)(null),O=(0,J.useCallback)(async()=>{s(!0),l(null);try{let e=await fetch(`${w()}/profiles`);if(!e.ok)throw Error(`List failed: ${e.status}`);let i=await e.json();t(i.profiles),i.profiles.length>0&&!n&&r(i.profiles[0].name)}catch(e){l(e.message)}finally{s(!1)}},[n]);(0,J.useEffect)(()=>{O()},[O]),(0,J.useEffect)(()=>{if(!n){a(null);return}let e=!1;return fetch(`${w()}/profiles/${encodeURIComponent(n)}`).then(e=>{if(!e.ok)throw Error(`Load failed: ${e.status}`);return e.json()}).then(t=>{e||a(t.profile)}).catch(t=>{e||l(t.message)}),()=>{e=!0}},[n]);let k=(0,J.useCallback)(async()=>{p(!0),l(null);try{let e=await fetch(`${w()}/profiles/migrate-from-settings`,{method:`POST`});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error??`Migration failed: ${e.status}`)}await O(),r(`default`),u.success(`Profile migrated`,{description:`default profile created from your current agents`})}catch(e){let t=e.message;l(t),u.error(`Migration failed`,{description:t})}finally{p(!1)}},[O]),A=(0,J.useCallback)(async e=>{S(!1),p(!0),l(null);try{let t={schemaVersion:1,name:e,description:``,orchestrator:{model:`sonnet`},agents:[{id:`sr-architect`,model:`sonnet`,required:!0},{id:`sr-developer`,model:`sonnet`,required:!0},{id:`sr-reviewer`,model:`sonnet`,required:!0},{id:`sr-merge-resolver`,model:`sonnet`,required:!0}],routing:[{default:!0,agent:`sr-developer`}]},n=await fetch(`${w()}/profiles`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Create failed: ${n.status}`)}await O(),r(e),u.success(`Profile created`,{description:e})}catch(e){let t=e.message;l(t),u.error(`Failed to create profile`,{description:t})}finally{p(!1)}},[O]),j=(0,J.useCallback)(async(e,t)=>{T(null),p(!0),l(null);try{let n=await fetch(`${w()}/profiles/${encodeURIComponent(e)}/duplicate`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({name:t})});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Duplicate failed: ${n.status}`)}await O(),r(t),u.success(`Profile duplicated`,{description:`${e} → ${t}`})}catch(e){let t=e.message;l(t),u.error(`Failed to duplicate profile`,{description:t})}finally{p(!1)}},[O]),M=(0,J.useCallback)(async e=>{D(null),p(!0),l(null);try{let t=await fetch(`${w()}/profiles/${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error??`Delete failed: ${t.status}`)}r(t=>t===e?null:t),await O(),u.success(`Profile deleted`,{description:e})}catch(e){let t=e.message;l(t),u.error(`Failed to delete profile`,{description:t})}finally{p(!1)}},[O]),N=(0,J.useCallback)(()=>S(!0),[]),P=(0,J.useCallback)(e=>T({from:e}),[]),F=(0,J.useCallback)(e=>D({name:e}),[]),I=(0,J.useCallback)(async(e,t)=>{p(!0),l(null);try{let n=await fetch(`${w()}/profiles/${encodeURIComponent(e.name)}`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Save failed: ${n.status}`)}a(e),t.length>0?u.warning(`Profile saved with untargeted agents`,{description:`No routing rule points to: ${t.join(`, `)}. Add a tag rule or retarget the default rule if you want them to run.`,duration:6e3}):u.success(`Profile saved`,{description:e.name})}catch(e){let t=e.message;l(t),u.error(`Failed to save profile`,{description:t})}finally{p(!1)}},[]),L=(0,Y.jsxs)(Y.Fragment,{children:[(0,Y.jsx)(ge,{open:x,title:`New profile`,description:`Pick a lowercase kebab-case name (letters, digits, and hyphens).`,placeholder:`my-profile`,confirmLabel:`Create`,inputPattern:/^[a-z0-9][a-z0-9-]*$/,inputInvalidHint:`Must start with a letter or digit and contain only lowercase letters, digits, and hyphens.`,onConfirm:e=>void A(e),onCancel:()=>S(!1)}),C&&(0,Y.jsx)(ge,{open:!0,title:`Duplicate "${C.from}"`,description:`Name for the new profile.`,placeholder:`${C.from}-copy`,initialValue:`${C.from}-copy`,confirmLabel:`Duplicate`,inputPattern:/^[a-z0-9][a-z0-9-]*$/,inputInvalidHint:`Lowercase kebab-case only.`,onConfirm:e=>void j(C.from,e),onCancel:()=>T(null)}),E&&(0,Y.jsx)(_e,{open:!0,title:`Delete profile "${E.name}"?`,description:`This cannot be undone. Jobs already launched with this profile keep their snapshot; future launches will fall back to the resolution order.`,confirmLabel:`Delete`,destructive:!0,onConfirm:()=>void M(E.name),onCancel:()=>D(null)})]});return o?(0,Y.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,Y.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Loading profiles…`})}):e.length===0?(0,Y.jsxs)(Y.Fragment,{children:[L,(0,Y.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,Y.jsxs)(`div`,{className:`text-center max-w-md`,children:[(0,Y.jsx)(`div`,{className:`text-sm font-medium text-foreground`,children:`No profiles yet`}),(0,Y.jsx)(`div`,{className:`text-xs text-muted-foreground mt-1 mb-4`,children:`Profiles let you save orchestrator + agent + routing combinations and pick one per rail.`}),(0,Y.jsxs)(`div`,{className:`flex items-center gap-2 justify-center`,children:[(0,Y.jsxs)(y,{size:`sm`,onClick:k,disabled:d,children:[(0,Y.jsx)(ce,{className:`w-3.5 h-3.5 mr-1.5`}),` Migrate from current agents`]}),(0,Y.jsxs)(y,{size:`sm`,variant:`ghost`,onClick:N,disabled:d,children:[(0,Y.jsx)(f,{className:`w-3.5 h-3.5 mr-1.5`}),` Blank profile`]})]}),(0,Y.jsxs)(`div`,{className:`text-[11px] text-muted-foreground/70 mt-3`,children:[`"Migrate" reads your existing `,(0,Y.jsx)(`code`,{className:`text-foreground`,children:`.claude/agents/`}),` `,`frontmatter models and creates a `,(0,Y.jsx)(`code`,{className:`text-foreground`,children:`default`}),` profile mirroring today's behavior — zero-loss.`]}),c&&(0,Y.jsx)(`div`,{className:`mt-3 text-xs text-red-400`,children:c})]})})]}):(0,Y.jsxs)(`div`,{className:`flex flex-col h-full`,children:[L,(0,Y.jsxs)(`div`,{className:`flex flex-1 min-h-0`,children:[(0,Y.jsxs)(`aside`,{className:`w-64 flex-shrink-0 border-r border-border flex flex-col`,children:[(0,Y.jsxs)(`div`,{className:`p-3 flex items-center justify-between`,children:[(0,Y.jsx)(`div`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wide`,children:`Profiles`}),(0,Y.jsx)(y,{size:`sm`,variant:`ghost`,onClick:N,disabled:d,children:(0,Y.jsx)(f,{className:`w-3.5 h-3.5`})})]}),(0,Y.jsx)(`div`,{className:`flex-1 overflow-auto px-2 pb-3`,children:e.map(e=>(0,Y.jsxs)(`div`,{className:`group mb-1 rounded-md px-2 py-1.5 text-xs cursor-pointer transition-colors flex items-center justify-between `+(e.name===n?`bg-accent text-foreground`:`text-muted-foreground hover:bg-accent/50 hover:text-foreground`),onClick:()=>r(e.name),role:`button`,tabIndex:0,onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&r(e.name)},children:[(0,Y.jsxs)(`div`,{className:`flex items-center gap-1.5 min-w-0`,children:[(0,Y.jsx)(`span`,{className:`truncate font-medium`,children:e.name}),e.isDefault&&(0,Y.jsx)(`span`,{className:`text-[10px] text-muted-foreground`,children:`(team default)`})]}),(0,Y.jsxs)(`div`,{className:`flex gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity`,children:[(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-accent rounded`,title:`Duplicate`,onClick:t=>{t.stopPropagation(),P(e.name)},children:(0,Y.jsx)(ne,{className:`w-3 h-3`})}),!e.isDefault&&(0,Y.jsx)(`button`,{type:`button`,className:`p-1 hover:bg-red-500/20 text-red-400 rounded`,title:`Delete`,onClick:t=>{t.stopPropagation(),F(e.name)},children:(0,Y.jsx)(_,{className:`w-3 h-3`})})]})]},e.name))})]}),(0,Y.jsxs)(`main`,{className:`flex-1 overflow-auto`,children:[c&&(0,Y.jsx)(`div`,{className:`mx-4 mt-4 px-3 py-2 text-xs rounded border border-red-500/30 bg-red-500/10 text-red-400`,children:c}),i?(0,Y.jsx)(fe,{profile:i,onChange:a,onValidityChange:g,onSoftWarningsChange:e=>b(e.agentsMissingRouting),footer:(0,Y.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,Y.jsxs)(y,{size:`sm`,onClick:()=>void I(i,v),disabled:d||h.length>0,title:h.length>0?`Fix validation issues before saving`:void 0,children:[(0,Y.jsx)(m,{className:`w-3.5 h-3.5 mr-1.5`}),`Save`]}),d&&(0,Y.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Saving…`}),h.length>0&&(0,Y.jsxs)(`span`,{className:`text-xs text-yellow-500`,children:[h.length,` `,h.length===1?`issue`:`issues`,` to resolve`]})]})},i.name):(0,Y.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,Y.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Select a profile to edit`})})]})]})]})}function Q(e){let t=e.workflow.map((e,t)=>`${t+1}. ${e}`).join(`
|
|
2
2
|
`);return`---
|
|
3
3
|
name: ${e.id}
|
|
4
4
|
description: "${e.descriptionOneLine}"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as e}from"./chunk-CilyBKbf.js";import{t}from"./clsx-Cv6vnfjX.js";import{B as n,St as r,Vt as i,_t as a,bt as o,h as s,o as c,pt as l,s as u,vt as d,xt as f,yt as p,zt as m}from"./index-CGRWJr7_.js";import{t as h}from"./ExportDropdown-BvMqXS54.js";import{A as g,B as _,C as v,D as y,E as b,F as x,G as S,H as C,I as w,J as T,K as E,L as D,M as O,N as k,O as A,P as j,Q as M,R as N,S as P,T as F,V as I,X as L,Z as R,_ as z,_t as ee,a as B,at as te,b as ne,c as re,ct as ie,et as ae,f as oe,g as se,gt as ce,h as le,i as ue,j as de,k as fe,l as pe,lt as V,m as me,n as he,nt as H,o as ge,ot as _e,p as ve,pt as U,q as ye,r as be,rt as W,s as xe,st as Se,t as Ce,tt as we,ut as G,v as Te,x as Ee,y as De,z as Oe}from"./BarChart-4okIQvSE.js";var ke=a(`arrow-down-right`,[[`path`,{d:`m7 7 10 10`,key:`1fmybs`}],[`path`,{d:`M17 7v10H7`,key:`6fjiku`}]]),K=e(i(),1),q=f();function J(e){return e>=100?`$${e.toFixed(0)}`:e>=10?`$${e.toFixed(1)}`:`$${e.toFixed(2)}`}function Ae(e){return e>=1e3?`$${(e/1e3).toFixed(1)}k`:`$${e.toFixed(2)}`}function je(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:`${e}`}var Me=[`job`,`explore-spec`,`quick-spec`,`ai-edit`,`smash`];function Ne({data:e,loading:t}){let[n,r]=(0,K.useState)(0),i=(0,K.useRef)(0);if((0,K.useEffect)(()=>{if(!e)return;let t=e.summary.totalCostUsd;if(i.current===0&&t>0){let e=performance.now(),n=i=>{let a=Math.min(1,(i-e)/600),o=1-(1-a)**3;r(0+(t-0)*o),a<1&&requestAnimationFrame(n)};requestAnimationFrame(n)}else r(t);i.current=t},[e]),t&&!e)return(0,q.jsx)(`div`,{className:`h-44 rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let a=e.summary.totalCostUsd,o=e.summary.totalRuns,s=e.summary.totalTokens??0,d=e.summary.totalEstimatedCostUsd??0,f=e.summary.deltaPct,p=e.trackingStartedAt,m=d>0,h=Me.map(t=>{let n=e.bySurface.find(e=>e.surface===t);return{surface:t,costUsd:n?.costUsd??0,count:n?.count??0}});return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-gradient-to-br from-card/80 to-card/40 p-5`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-end justify-between gap-3 mb-4`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`text-[11px] uppercase tracking-wider text-muted-foreground mb-1`,children:`Spending`}),(0,q.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,q.jsx)(`div`,{className:`text-5xl font-semibold tabular-nums tracking-tight`,children:Ae(n)}),f!==null&&(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-0.5 text-xs font-medium ${f>=0?`text-accent-warning`:`text-accent-success`}`,children:[f>=0?(0,q.jsx)(l,{className:`w-3 h-3`}):(0,q.jsx)(ke,{className:`w-3 h-3`}),Math.abs(f).toFixed(0),`% vs prev`]})]}),(0,q.jsxs)(`div`,{className:`text-xs text-muted-foreground mt-1 tabular-nums flex items-center gap-2`,children:[(0,q.jsxs)(`span`,{children:[o,` invocation`,o===1?``:`s`]}),s>0&&(0,q.jsxs)(`span`,{className:`text-muted-foreground/80`,title:`Total tokens = fresh input + output + cache-read + cache-create across all invocations in this window.`,children:[`· `,je(s),` tokens`]}),m&&(0,q.jsxs)(`span`,{className:`text-[10px] text-muted-foreground/70 italic`,title:`Includes ${J(d)} of estimated cost from providers without a native cost field (e.g. codex via the local pricing table).`,children:[`· includes ~`,J(d),` estimated`]})]})]}),o===0&&p&&(0,q.jsxs)(`div`,{className:`text-xs text-muted-foreground`,children:[`Tracking started `,p.slice(0,10)]})]}),o===0?(0,q.jsxs)(`div`,{className:`rounded-lg border border-dashed border-border/40 p-6 text-center`,children:[(0,q.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No invocations yet for this filter window.`}),(0,q.jsxs)(`p`,{className:`text-xs text-muted-foreground/70 mt-1`,children:[`Tracking started `,p?p.slice(0,10):`on first invocation`]})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`h-3 w-full rounded-full overflow-hidden bg-background-deep flex`,children:h.map(e=>{let t=a>0?e.costUsd/a*100:0;return t===0?null:(0,q.jsx)(`div`,{className:`h-full ${c[e.surface].dot}`,style:{width:`${t}%`},title:`${u[e.surface]}: ${J(e.costUsd)}`},e.surface)})}),(0,q.jsx)(`div`,{className:`mt-3 flex flex-wrap items-center gap-x-5 gap-y-1.5 text-xs`,children:h.filter(e=>e.costUsd>0).map(e=>(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 tabular-nums`,children:[(0,q.jsx)(`span`,{className:`w-2 h-2 rounded-full ${c[e.surface].dot}`}),(0,q.jsx)(`span`,{className:`text-muted-foreground`,children:u[e.surface]}),(0,q.jsx)(`span`,{className:`text-foreground font-medium`,children:J(e.costUsd)}),(0,q.jsx)(`span`,{className:`text-muted-foreground/60`,children:`·`}),(0,q.jsx)(`span`,{className:`text-muted-foreground/80`,children:e.count})]},e.surface))})]})]})}var Pe={claude:`Claude`,codex:`Codex`},Fe={claude:`bg-accent-info`,codex:`bg-accent-highlight`};function Ie(e){return e>=100?`$${e.toFixed(0)}`:e>=10?`$${e.toFixed(1)}`:e>=.01?`$${e.toFixed(2)}`:`$${e.toFixed(4)}`}function Le(e){return Pe[e]??e}function Re(e){return Fe[e]??`bg-accent-secondary`}function ze({data:e,loading:t}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-32 rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e||e.byProvider.length===0||e.byProvider.length===1)return null;let n=e.byProvider.reduce((e,t)=>e+t.costUsd+t.estimatedCostUsd,0);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsx)(`div`,{className:`flex items-baseline justify-between mb-3`,children:(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`text-[11px] uppercase tracking-wider text-muted-foreground`,children:`By provider`}),(0,q.jsxs)(`div`,{className:`text-xs text-muted-foreground/70 mt-0.5`,children:[`How cost splits across the AI CLIs in this project. The`,` `,(0,q.jsx)(`span`,{className:`font-medium`,children:`~`}),` prefix marks rows where cost is estimated from the local pricing table (the provider does not report it natively).`]})]})}),n===0?(0,q.jsx)(`div`,{className:`text-xs text-muted-foreground italic`,children:`No cost recorded yet in this window.`}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`h-2 w-full rounded-full overflow-hidden bg-background-deep flex mb-3`,children:e.byProvider.map(e=>{let t=e.costUsd+e.estimatedCostUsd,r=n>0?t/n*100:0;return r===0?null:(0,q.jsx)(`div`,{className:`h-full ${Re(e.provider)}`,style:{width:`${r}%`},title:`${Le(e.provider)}: ${Ie(t)} (${e.count})`},e.provider)})}),(0,q.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-2`,children:e.byProvider.map(e=>(0,q.jsx)(Be,{entry:e},e.provider))})]})]})}function Be({entry:e}){let t=e.costUsd+e.estimatedCostUsd,n=e.costUsd===0&&e.estimatedCostUsd>0;return(0,q.jsxs)(`div`,{className:`flex items-center gap-2.5 rounded-md border border-border/30 px-2.5 py-1.5`,children:[(0,q.jsx)(`span`,{className:`w-2 h-2 rounded-full shrink-0 ${Re(e.provider)}`}),(0,q.jsx)(`span`,{className:`text-xs font-medium`,children:Le(e.provider)}),(0,q.jsxs)(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[e.count,` run`,e.count===1?``:`s`]}),(0,q.jsxs)(`span`,{className:`ml-auto text-xs font-medium tabular-nums`,children:[n?`~`:``,Ie(t)]})]})}var Ve=[`option`,`isActive`];function Y(){return Y=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Y.apply(null,arguments)}function He(e,t){if(e==null)return{};var n,r,i=Ue(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Ue(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function We(e){var{option:t,isActive:n}=e,r=He(e,Ve);return typeof t==`string`?K.createElement(P,Y({option:K.createElement(Se,Y({type:t},r)),isActive:n,shapeType:`symbols`},r)):K.createElement(P,Y({option:t,isActive:n,shapeType:`symbols`},r))}var Ge=ae([(e,t,n,r,i,a,o)=>N(e,void 0,void 0,o),(e,t,n,r,i,a,o)=>k(e,`xAxis`,t,o),(e,t,n,r,i,a,o)=>j(e,`xAxis`,t,o),(e,t,n,r,i,a,o)=>k(e,`yAxis`,n,o),(e,t,n,r,i,a,o)=>j(e,`yAxis`,n,o),(e,t,n,r)=>w(e,`zAxis`,r,!1),ae([x,(e,t,n,r,i)=>i],(e,t)=>e.filter(e=>e.type===`scatter`).find(e=>e.id===t)),(e,t,n,r,i,a)=>a],(e,t,n,r,i,a,o,s)=>{var{chartData:c,dataStartIndex:l,dataEndIndex:u}=e;if(o!=null){var d=o?.data!=null&&o.data.length>0?o.data:c?.slice(l,u+1);if(!(d==null||t==null||r==null||n==null||i==null||n?.length===0||i?.length===0))return ot({displayedData:d,xAxis:t,yAxis:r,zAxis:a,scatterSettings:o,xAxisTicks:n,yAxisTicks:i,cells:s})}}),Ke=[`id`],qe=[`onMouseEnter`,`onClick`,`onMouseLeave`],Je=[`animationBegin`,`animationDuration`,`animationEasing`,`hide`,`isAnimationActive`,`legendType`,`lineJointType`,`lineType`,`shape`,`xAxisId`,`yAxisId`,`zAxisId`];function X(e,t){if(e==null)return{};var n,r,i=Ye(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Ye(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function Z(){return Z=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Z.apply(null,arguments)}function Xe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function Q(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?Xe(Object(n),!0).forEach(function(t){Ze(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Xe(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function Ze(e,t,n){return(t=Qe(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Qe(e){var t=$e(e,`string`);return typeof t==`symbol`?t:t+``}function $e(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var et=e=>{var{dataKey:t,name:n,fill:r,legendType:i,hide:a}=e;return[{inactive:a,dataKey:t,type:i,color:r,value:R(n,t),payload:e}]},tt=K.memo(e=>{var{dataKey:t,points:n,stroke:r,strokeWidth:i,fill:a,name:o,hide:s,tooltipType:c,id:l}=e,u={dataDefinedOnItem:n?.map(e=>e.tooltipPayload),getPosition:e=>{var t;return n==null||(t=n[Number(e)])==null?void 0:t.tooltipPosition},settings:{stroke:r,strokeWidth:i,fill:a,nameKey:void 0,dataKey:t,name:R(o,t),hide:s,type:c,color:a,unit:``,graphicalItemId:l}};return K.createElement(Te,{tooltipEntrySettings:u})});function nt(e){var{points:t,props:n}=e,{line:r,lineType:i,lineJointType:a}=n;if(!r)return null;var o=ce(n),s=ee(r),c,l;if(i===`joint`)c=t.map(e=>({x:e.cx??null,y:e.cy??null}));else if(i===`fitting`){var{xmin:u,xmax:d,a:f,b:p}=ie(t),m=e=>f*e+p;c=[{x:u,y:m(u)},{x:d,y:m(d)}]}var h=Q(Q(Q({},o),{},{fill:`none`,stroke:o&&o.fill},s),{},{points:c});return l=K.isValidElement(r)?K.cloneElement(r,h):typeof r==`function`?r(h):K.createElement(I,Z({},h,{type:a})),K.createElement(U,{className:`recharts-scatter-line`,key:`recharts-scatter-line`},l)}function rt(e){var{showLabels:t,points:n,children:r}=e,i=S(),a=(0,K.useMemo)(()=>n?.map(e=>{var t={x:e.x??0,y:e.y??0,width:e.width,height:e.height,lowerWidth:e.width,upperWidth:e.width};return Q(Q({},t),{},{value:void 0,payload:e.payload,viewBox:t,parentViewBox:i,fill:void 0})}),[i,n]);return K.createElement(F,{value:t?a:void 0},r)}function it(e){var{points:t,allOtherScatterProps:n}=e,{shape:r,activeShape:i,dataKey:a}=n,{id:o}=n,s=X(n,Ke),c=H(de),{onMouseEnter:l,onClick:u,onMouseLeave:d}=n,f=X(n,qe),p=ne(l,a,o),m=Ee(d),h=De(u,a,o);if(!_e(t))return null;var _=ce(s);return K.createElement(K.Fragment,null,K.createElement(nt,{points:t,props:s}),t.map((e,t)=>{var n=i!=null&&i!==!1,a=n&&c===String(t),s=n&&a?i:r,l=Q(Q(Q({},_),e),{},{index:t,[T]:String(o)});return K.createElement(g,{key:`symbol-${e?.cx}-${e?.cy}-${e?.size}-${t}`,zIndex:a?D.activeDot:void 0},K.createElement(U,Z({className:`recharts-scatter-symbol`},te(f,e,t),{onMouseEnter:p(e,t),onMouseLeave:m(e,t),onClick:h(e,t)}),K.createElement(We,Z({option:s,isActive:a},l))))}))}function at(e){var{previousPointsRef:t,props:n}=e,{points:r,isAnimationActive:i,animationBegin:a,animationDuration:o,animationEasing:s}=n,c=t.current,l=Oe(n,`recharts-scatter-`),[u,d]=(0,K.useState)(!1),f=(0,K.useCallback)(()=>{d(!1)},[]),p=(0,K.useCallback)(()=>{d(!0)},[]),m=!u;return K.createElement(rt,{showLabels:m,points:r},n.children,K.createElement(_,{animationId:l,begin:a,duration:o,isActive:i,easing:s,onAnimationEnd:f,onAnimationStart:p,key:l},e=>{var i=e===1?r:r?.map((t,n)=>{var r=c&&c[n];return r?Q(Q({},t),{},{cx:t.cx==null?void 0:V(r.cx,t.cx,e),cy:t.cy==null?void 0:V(r.cy,t.cy,e),size:V(r.size,t.size,e)}):Q(Q({},t),{},{size:V(0,t.size,e)})});return e>0&&(t.current=i),K.createElement(U,null,K.createElement(it,{points:i,allOtherScatterProps:n,showLabels:m}))}),K.createElement(b,{label:n.label}))}function ot(e){var{displayedData:t,xAxis:n,yAxis:r,zAxis:i,scatterSettings:a,xAxisTicks:o,yAxisTicks:s,cells:c}=e,l=G(n.dataKey)?a.dataKey:n.dataKey,u=G(r.dataKey)?a.dataKey:r.dataKey,d=i&&i.dataKey,f=i?i.range:O.range,p=f&&f[0],m=n.scale.bandwidth?n.scale.bandwidth():0,h=r.scale.bandwidth?r.scale.bandwidth():0;return t.map((e,t)=>{var f=M(e,l),g=M(e,u),_=!G(d)&&M(e,d)||`-`,v=[{name:G(n.dataKey)?a.name:n.name||String(n.dataKey),unit:n.unit||``,value:f,payload:e,dataKey:l,type:a.tooltipType,graphicalItemId:a.id},{name:G(r.dataKey)?a.name:r.name||String(r.dataKey),unit:r.unit||``,value:g,payload:e,dataKey:u,type:a.tooltipType,graphicalItemId:a.id}];_!==`-`&&i!=null&&v.push({name:i.name||i.dataKey,unit:i.unit||``,value:_,payload:e,dataKey:d,type:a.tooltipType,graphicalItemId:a.id});var y=L({axis:n,ticks:o,bandSize:m,entry:e,index:t,dataKey:l}),b=L({axis:r,ticks:s,bandSize:h,entry:e,index:t,dataKey:u}),x=_!==`-`&&i!=null?i.scale.map(_):p,S=x==null?0:Math.sqrt(Math.max(x,0)/Math.PI);return Q(Q({},e),{},{cx:y,cy:b,x:y==null?void 0:y-S,y:b==null?void 0:b-S,width:2*S,height:2*S,size:x,node:{x:f,y:g,z:_},tooltipPayload:v,tooltipPosition:{x:y,y:b},payload:e},c&&c[t]&&c[t].props)})}var st=(e,t,n)=>({x:e.cx,y:e.cy,value:Number(n===`x`?e.node.x:e.node.y),errorVal:M(e,t)});function ct(e){var{hide:n,points:r,className:i,needClip:a,xAxisId:o,yAxisId:s,id:c}=e,l=(0,K.useRef)(null);if(n)return null;var u=t(`recharts-scatter`,i),d=c;return K.createElement(g,{zIndex:e.zIndex},K.createElement(U,{className:u,clipPath:a?`url(#clipPath-${d})`:void 0,id:c},a&&K.createElement(`defs`,null,K.createElement(ge,{clipPathId:d,xAxisId:o,yAxisId:s})),K.createElement(re,{xAxisId:o,yAxisId:s,data:r,dataPointFormatter:st,errorBarOffset:0},K.createElement(U,{key:`recharts-scatter-symbols`},K.createElement(at,{props:e,previousPointsRef:l})))))}var lt={xAxisId:0,yAxisId:0,zAxisId:0,label:!1,line:!1,legendType:`circle`,lineType:`joint`,lineJointType:`linear`,shape:`circle`,hide:!1,isAnimationActive:`auto`,animationBegin:0,animationDuration:400,animationEasing:`linear`,zIndex:D.scatter};function ut(e){var t=W(e,lt),{animationBegin:n,animationDuration:r,animationEasing:i,hide:a,isAnimationActive:o,legendType:s,lineJointType:c,lineType:l,shape:u,xAxisId:d,yAxisId:f,zAxisId:p}=t,m=X(t,Je),{needClip:h}=xe(d,f),g=(0,K.useMemo)(()=>v(e.children,y),[e.children]),_=ye(),b=H(t=>Ge(t,d,f,p,e.id,g,_));return h==null||b==null?null:K.createElement(K.Fragment,null,K.createElement(tt,{dataKey:e.dataKey,points:b,stroke:e.stroke,strokeWidth:e.strokeWidth,fill:e.fill,name:e.name,hide:e.hide,tooltipType:e.tooltipType,id:e.id}),K.createElement(ct,Z({},m,{xAxisId:d,yAxisId:f,zAxisId:p,lineType:l,lineJointType:c,legendType:s,shape:u,hide:a,isAnimationActive:o,animationBegin:n,animationDuration:r,animationEasing:i,points:b,needClip:h})))}function dt(e){var t=W(e,lt),n=ye();return K.createElement(se,{id:t.id,type:`scatter`},e=>K.createElement(K.Fragment,null,K.createElement(z,{legendPayload:et(t)}),K.createElement(le,{type:`scatter`,id:e,data:t.data,xAxisId:t.xAxisId,yAxisId:t.yAxisId,zAxisId:t.zAxisId,dataKey:t.dataKey,hide:t.hide,name:t.name,tooltipType:t.tooltipType,isPanorama:n}),K.createElement(ut,Z({},t,{id:e}))))}var ft=K.memo(dt,C);ft.displayName=`Scatter`;function pt(e){var t=we(),n=(0,K.useRef)(null);return(0,K.useLayoutEffect)(()=>{n.current===null?t(oe(e)):n.current!==e&&t(me({prev:n.current,next:e})),n.current=e},[e,t]),(0,K.useLayoutEffect)(()=>()=>{n.current&&=(t(ve(n.current)),null)},[t]),null}var mt={zAxisId:0,range:O.range,scale:O.scale,type:O.type};function ht(e){var t=W(e,mt);return K.createElement(pt,{domain:t.domain,id:t.zAxisId,dataKey:t.dataKey,name:t.name,unit:t.unit,range:t.range,scale:t.scale,type:t.type,allowDuplicatedCategory:O.allowDuplicatedCategory,allowDataOverflow:O.allowDataOverflow,reversed:O.reversed,includeHidden:O.includeHidden})}ht.displayName=`ZAxis`;var gt=[`item`],_t=(0,K.forwardRef)((e,t)=>K.createElement(he,{chartName:`ScatterChart`,defaultTooltipEventType:`item`,validateTooltipEventTypes:gt,tooltipPayloadSearcher:fe,categoricalChartProps:e,ref:t}));function vt({data:e,loading:t}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[220px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let n=e.dailyTimeline.map(e=>({date:e.date.slice(5),Jobs:e.jobsCostUsd,Explore:e.exploreCostUsd,Quick:e.quickCostUsd,Refine:e.aiEditCostUsd,"File summaries":e.fileSummaryCostUsd??0})),r=n.every(e=>e.Jobs+e.Explore+e.Quick+e.Refine+e[`File summaries`]===0);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`Daily timeline`}),(0,q.jsx)(`span`,{className:`text-[10px] text-muted-foreground/70`,children:`stacked by surface`})]}),r?(0,q.jsx)(`div`,{className:`h-40 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No spend in this period.`}):(0,q.jsx)(`div`,{className:`h-[220px]`,children:(0,q.jsx)(E,{width:`100%`,height:`100%`,children:(0,q.jsxs)(Ce,{data:n,margin:{top:10,right:10,left:-8,bottom:0},children:[(0,q.jsx)(pe,{strokeDasharray:`2 4`,stroke:`currentColor`,className:`text-border/30`,vertical:!1}),(0,q.jsx)(ue,{dataKey:`date`,tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`}),(0,q.jsx)(be,{tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`,tickFormatter:e=>`$${e}`}),(0,q.jsx)(A,{contentStyle:{backgroundColor:`var(--popover)`,border:`1px solid var(--border)`,fontSize:11,borderRadius:6},formatter:(e,t)=>[`$${typeof e==`number`?e.toFixed(2):`—`}`,String(t)]}),(0,q.jsx)(B,{dataKey:`Jobs`,stackId:`a`,fill:`var(--accent-info, #5fa8d3)`}),(0,q.jsx)(B,{dataKey:`Explore`,stackId:`a`,fill:`var(--accent-highlight, #c084fc)`}),(0,q.jsx)(B,{dataKey:`Quick`,stackId:`a`,fill:`var(--accent-secondary, #f7768e)`}),(0,q.jsx)(B,{dataKey:`Refine`,stackId:`a`,fill:`var(--accent-success, #50fa7b)`}),(0,q.jsx)(B,{dataKey:`File summaries`,stackId:`a`,fill:`var(--accent-warning, #f1fa8c)`})]})})})]})}function yt(e){return e==null?`—`:e<.005?`$${e.toFixed(4)}`:e<1?`$${e.toFixed(3)}`:`$${e.toFixed(2)}`}function bt(e){return e==null?`—`:e<1e3?`${e} ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${Math.floor(e%6e4/1e3)}s`}function xt({values:e}){let t=Math.max(1e-4,...e);return(0,q.jsx)(`div`,{className:`flex items-end gap-[1px] h-5`,children:e.map((e,n)=>(0,q.jsx)(`div`,{className:`w-[3px] rounded-sm bg-foreground/40`,style:{height:`${Math.max(2,e/t*20)}px`}},n))})}function St({mode:e,label:t,accentClass:n}){let r=e.mode===`explore`&&e.totalRuns<5;return(0,q.jsxs)(`div`,{className:`flex-1 p-4 first:pr-2 last:pl-2`,children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,q.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full ${n}`}),(0,q.jsx)(`span`,{className:`text-xs font-medium uppercase tracking-wider text-muted-foreground`,children:t})]}),r?(0,q.jsxs)(`div`,{className:`py-3`,children:[(0,q.jsx)(`p`,{className:`text-sm text-foreground`,children:`Try Explore for richer specs`}),(0,q.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-1`,children:[e.totalRuns,` run`,e.totalRuns===1?``:`s`,` so far`]})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`text-3xl font-semibold tabular-nums tracking-tight`,children:yt(e.avgCostPerSpec)}),(0,q.jsx)(`div`,{className:`text-[11px] text-muted-foreground mt-0.5`,children:`per spec`}),(0,q.jsx)(`div`,{className:`mt-3`,children:(0,q.jsx)(xt,{values:e.sparkline.length>0?e.sparkline:[0]})}),(0,q.jsxs)(`div`,{className:`mt-3 space-y-0.5 text-xs tabular-nums text-muted-foreground`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`span`,{className:`text-foreground font-medium`,children:e.ticketsCreated}),` created · `,e.totalRuns,` runs`]}),(0,q.jsxs)(`div`,{children:[bt(e.avgDurationMs),` avg`]}),(0,q.jsx)(`div`,{className:`truncate`,children:e.dominantModel??`—`})]})]})]})}function Ct({data:e,loading:t}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[220px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let n=e.byMode.find(e=>e.mode===`quick`),r=e.byMode.find(e=>e.mode===`explore`);if(!n||!r)return null;let i=n.avgCostPerSpec&&r.avgCostPerSpec&&n.avgCostPerSpec>0?r.avgCostPerSpec/n.avgCostPerSpec:null,a=i!==null&&n.totalRuns>=1&&r.totalRuns>=5;return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40`,children:[(0,q.jsx)(`div`,{className:`px-4 pt-3 pb-1`,children:(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`Quick vs Explore`})}),(0,q.jsxs)(`div`,{className:`flex divide-x divide-border/40`,children:[(0,q.jsx)(St,{mode:n,label:`Quick`,accentClass:`bg-accent-secondary`}),(0,q.jsx)(St,{mode:r,label:`Explore`,accentClass:`bg-accent-highlight`})]}),a&&(0,q.jsx)(`div`,{className:`px-4 pb-3 -mt-1`,children:(0,q.jsx)(`div`,{className:`text-center text-[11px] text-muted-foreground tabular-nums`,children:(0,q.jsxs)(`span`,{className:`px-2`,children:[`━━━━━━ `,i.toFixed(1),`× more per spec ━━━━━━`]})})})]})}function wt({data:e,loading:t,onSelectModel:n,activeModel:r}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[220px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let i=e.byModel.reduce((e,t)=>e+t.costUsd,0),a=e.byModel.slice(0,5);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3`,children:`Models`}),a.length===0?(0,q.jsx)(`div`,{className:`h-32 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No models recorded.`}):(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:a.map(e=>{let t=i>0?e.costUsd/i*100:0,a=r===e.model;return(0,q.jsx)(`li`,{children:(0,q.jsxs)(`button`,{type:`button`,onClick:()=>n(e.model),className:`w-full text-left group rounded-md px-2 py-1.5 transition-colors ${a?`bg-accent-highlight/10 ring-1 ring-accent-highlight/30`:`hover:bg-accent/30`}`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between text-[12px] mb-1 tabular-nums`,children:[(0,q.jsx)(`span`,{className:`truncate font-medium`,children:e.model}),(0,q.jsxs)(`span`,{className:`text-muted-foreground`,children:[`$`,e.costUsd.toFixed(2),` · `,e.count]})]}),(0,q.jsx)(`div`,{className:`h-1.5 rounded-full bg-background-deep overflow-hidden`,children:(0,q.jsx)(`div`,{className:`h-full ${a?`bg-accent-highlight`:`bg-foreground/40 group-hover:bg-foreground/60`} transition-colors`,style:{width:`${t}%`}})})]})},e.model)})})]})}var Tt={job:`var(--accent-info, #5fa8d3)`,"quick-spec":`var(--accent-secondary, #f7768e)`,"explore-spec":`var(--accent-highlight, #c084fc)`,"ai-edit":`var(--accent-success, #50fa7b)`,smash:`var(--accent-highlight, #c084fc)`};function Et({data:e,loading:t,onSelectPoint:n}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[260px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let r=[`job`,`quick-spec`,`explore-spec`,`ai-edit`,`smash`],i=r.map(t=>({surface:t,points:e.scatter.filter(e=>e.surface===t).map(e=>({id:e.id,x:e.numTurns??Math.round((e.durationMs??0)/1e3),y:e.costUsd,surface:t,ticketId:e.ticketId,startedAt:e.startedAt,raw:e}))})),a=e.scatter.length===0;return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`Cost vs Turns`}),(0,q.jsx)(`div`,{className:`flex flex-wrap items-center gap-2 text-[10px]`,children:r.map(e=>(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-1`,children:[(0,q.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full`,style:{background:Tt[e]}}),(0,q.jsx)(`span`,{className:`text-muted-foreground`,children:u[e]})]},e))})]}),a?(0,q.jsx)(`div`,{className:`h-40 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No invocations to plot.`}):(0,q.jsx)(`div`,{className:`h-[260px]`,children:(0,q.jsx)(E,{width:`100%`,height:`100%`,children:(0,q.jsxs)(_t,{margin:{top:10,right:10,left:-8,bottom:5},children:[(0,q.jsx)(pe,{strokeDasharray:`2 4`,stroke:`currentColor`,className:`text-border/30`}),(0,q.jsx)(ue,{type:`number`,dataKey:`x`,name:`turns`,tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`,label:{value:`turns`,position:`insideBottomRight`,offset:-2,fontSize:10,fill:`currentColor`}}),(0,q.jsx)(be,{type:`number`,dataKey:`y`,name:`cost`,tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`,tickFormatter:e=>`$${e.toFixed(e<1?2:0)}`}),(0,q.jsx)(ht,{range:[40,80]}),(0,q.jsx)(A,{cursor:{strokeDasharray:`3 3`},contentStyle:{backgroundColor:`var(--popover)`,border:`1px solid var(--border)`,fontSize:11,borderRadius:6},formatter:(e,t)=>{let n=String(t);return n===`cost`&&typeof e==`number`?[`$${e.toFixed(3)}`,`cost`]:[String(e),n]}}),i.map(e=>(0,q.jsx)(ft,{data:e.points,fill:Tt[e.surface],onClick:e=>{let t=e;t?.raw&&n(t.raw)}},e.surface))]})})})]})}function Dt({data:e,loading:t,onSelectTicket:n}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-40 rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let r=e.topTickets;return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3`,children:`Top tickets`}),r.length===0?(0,q.jsx)(`div`,{className:`h-32 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No ticket activity in this period.`}):(0,q.jsx)(`ul`,{className:`divide-y divide-border/30`,children:r.map((e,t)=>{let r=Object.entries(e.bySurface).filter(([,e])=>e.count>0).map(([e,t])=>`${t.count} ${u[e].toLowerCase()}`).join(` + `),i=e.isUnattributed,a=i?`Unattributed`:e.ticketTitle?`#${e.ticketId} ${e.ticketTitle}`:`deleted ticket #${e.ticketId}`;return(0,q.jsx)(`li`,{children:(0,q.jsxs)(`button`,{type:`button`,onClick:()=>n(e.ticketId),className:`w-full text-left flex items-center justify-between gap-3 py-2 px-1 hover:bg-accent/30 rounded transition-colors ${!e.ticketTitle&&!i?`opacity-50`:``}`,disabled:i,children:[(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-sm truncate`,children:a}),(0,q.jsx)(`div`,{className:`text-[11px] text-muted-foreground truncate`,children:r||`—`})]}),(0,q.jsxs)(`div`,{className:`text-right tabular-nums`,children:[(0,q.jsxs)(`div`,{className:`text-sm font-medium`,children:[`$`,e.totalCostUsd.toFixed(2)]}),(0,q.jsxs)(`div`,{className:`text-[10px] text-muted-foreground`,children:[e.totalRuns,` run`,e.totalRuns===1?``:`s`]})]})]})},`${e.ticketId??`u`}-${t}`)})})]})}function Ot(e){return e==null?`—`:e<.005?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function kt(e){return e==null?`—`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function At(e){return e.surface_ref_id?.startsWith(`contract-refine:`)?!0:e.surface===`explore-spec`&&e.ticket_id!=null&&e.conversation_id!=null&&e.surface_ref_id===e.conversation_id&&e.model==null}function jt(e){let t=new Map;for(let n of e)n.model&&(n.conversation_id&&t.set(`conversation:${n.conversation_id}`,n.model),n.ticket_id!=null&&n.surface===`explore-spec`&&t.set(`ticket:${n.ticket_id}:explore-spec`,n.model),n.ticket_id!=null&&n.surface===`quick-spec`&&t.set(`ticket:${n.ticket_id}:quick-spec`,n.model));return t}function Mt(e,t){if(e.model)return e.model;if(!At(e))return null;if(e.conversation_id){let n=t.get(`conversation:${e.conversation_id}`);if(n)return n}return e.ticket_id==null?null:t.get(`ticket:${e.ticket_id}:${e.surface}`)??null}function Nt({rows:e,loading:t,truncated:n,totalAvailable:r,tableFilters:i,onTableFiltersChange:a}){let[o,s]=(0,K.useState)(null),l=jt(e);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3 mb-3`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`All invocations`}),(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 text-[11px]`,children:[(0,q.jsxs)(`select`,{value:i.status??``,onChange:e=>a({...i,status:e.target.value||void 0}),className:`h-7 px-2 rounded-md bg-background-deep border border-border/60 text-xs`,"aria-label":`Status filter`,children:[(0,q.jsx)(`option`,{value:``,children:`All status`}),(0,q.jsx)(`option`,{value:`success`,children:`Success`}),(0,q.jsx)(`option`,{value:`failed`,children:`Failed`}),(0,q.jsx)(`option`,{value:`aborted`,children:`Aborted`})]}),(0,q.jsx)(`input`,{type:`number`,step:`0.01`,min:`0`,placeholder:`≥ $0.00`,value:i.minCostUsd??``,onChange:e=>{let t=e.target.value===``?void 0:parseFloat(e.target.value);a({...i,minCostUsd:Number.isNaN(t)?void 0:t})},className:`h-7 w-24 px-2 rounded-md bg-background-deep border border-border/60 text-xs tabular-nums`,"aria-label":`Minimum cost filter`})]})]}),t?(0,q.jsx)(`div`,{className:`h-32 rounded bg-card/30 animate-pulse`}):e.length===0?(0,q.jsx)(`div`,{className:`h-32 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No invocations match the current filters.`}):(0,q.jsx)(`div`,{className:`overflow-x-auto`,children:(0,q.jsxs)(`table`,{className:`w-full text-[12px] tabular-nums`,children:[(0,q.jsx)(`thead`,{className:`text-[10px] uppercase tracking-wider text-muted-foreground`,children:(0,q.jsxs)(`tr`,{className:`text-left`,children:[(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Surface`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Ticket`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2 text-right`,children:`Cost`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2 text-right`,children:`Turns`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2 text-right`,children:`Tokens`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Model`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Status`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Started`})]})}),(0,q.jsx)(`tbody`,{children:e.map(e=>{let t=e.surface,n=c[t],r=(e.tokens_in??0)+(e.tokens_out??0)+(e.tokens_cache_read??0)+(e.tokens_cache_create??0),i=At(e),a=i?`Contract Layer`:u[t],d=Mt(e,l);return(0,q.jsxs)(`tr`,{onClick:()=>s(o===e.id?null:e.id),className:`border-t border-border/30 hover:bg-accent/30 cursor-pointer`,children:[(0,q.jsx)(`td`,{className:`px-2 py-2`,children:(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 px-2 h-5 rounded-full text-[10px] font-medium ${n.bg} ${n.text}`,children:[(0,q.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full ${n.dot}`}),a]})}),(0,q.jsx)(`td`,{className:`px-2 py-2 max-w-[260px]`,children:e.ticket_id==null?e.ticket_title?(0,q.jsx)(`span`,{className:`truncate block text-muted-foreground/90 italic`,title:`Provisional Explore title — not yet committed`,children:e.ticket_title}):(0,q.jsx)(`span`,{className:`text-muted-foreground/70`,children:`—`}):(0,q.jsxs)(`span`,{className:`truncate block`,children:[`#`,e.ticket_id,` `,i?(0,q.jsx)(`span`,{className:`text-muted-foreground/90`,children:`Contract Layer refinement`}):e.ticket_title??(0,q.jsx)(`span`,{className:`text-muted-foreground/70 italic`,children:`(deleted)`})]})}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-right font-medium`,children:e.total_cost_usd_estimated===1&&e.total_cost_usd!=null?(0,q.jsxs)(`span`,{title:`Estimated from local pricing table — this provider does not report cost natively.`,className:`text-muted-foreground/90`,children:[`~`,Ot(e.total_cost_usd)]}):Ot(e.total_cost_usd)}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-right`,children:kt(e.num_turns)}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-right`,children:r>0?kt(r):`—`}),(0,q.jsxs)(`td`,{className:`px-2 py-2 max-w-[180px] truncate`,children:[d??`—`,d&&!e.model?(0,q.jsx)(`span`,{className:`ml-1 text-[10px] text-muted-foreground/70`,children:`inferred`}):null]}),(0,q.jsxs)(`td`,{className:`px-2 py-2`,children:[e.status===`success`?(0,q.jsx)(`span`,{className:`text-accent-success/90`,children:`●`}):e.status===`failed`?(0,q.jsx)(`span`,{className:`text-accent-warning`,children:`⚠`}):(0,q.jsx)(`span`,{className:`text-muted-foreground`,children:`○`}),(0,q.jsx)(`span`,{className:`ml-1 text-muted-foreground`,children:e.status})]}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-muted-foreground`,children:e.started_at.slice(0,16).replace(`T`,` `)})]},e.id)})})]})}),n&&(0,q.jsxs)(`div`,{className:`mt-2 text-[11px] text-muted-foreground/80`,children:[`Showing first `,e.length,` of `,r.toLocaleString(),` matching rows.`]})]})}var Pt=[{value:`7d`,label:`7d`},{value:`30d`,label:`30d`},{value:`90d`,label:`90d`},{value:`all`,label:`All`}],Ft=[{value:`all`,label:`All`},{value:`job`,label:`Jobs`},{value:`explore-spec`,label:`Explore`},{value:`quick-spec`,label:`Quick`},{value:`ai-edit`,label:`Refine`},{value:`smash`,label:`SMASH`},{value:`file-summary`,label:`File summaries`}];function $(e){let t=new URLSearchParams;return e.period&&t.set(`period`,e.period),e.from&&t.set(`from`,e.from),e.to&&t.set(`to`,e.to),e.surface&&e.surface.length>0&&t.set(`surface`,e.surface.join(`,`)),e.provider&&e.provider.length>0&&t.set(`provider`,e.provider.join(`,`)),e.model&&e.model.length>0&&t.set(`model`,e.model.join(`,`)),e.status&&t.set(`status`,e.status),typeof e.minCostUsd==`number`&&t.set(`minCostUsd`,String(e.minCostUsd)),typeof e.ticketId==`number`&&t.set(`ticketId`,String(e.ticketId)),t.toString()}function It(){let{activeProjectId:e,projects:t}=p(),[i,a]=m(),c=t.find(t=>t.id===e),l=c?d(c):[`claude`],u=l.length>1,f=i.get(`period`)??`30d`,g=(i.get(`surface`)??``).split(`,`).filter(Boolean),_=(i.get(`provider`)??``).split(`,`).filter(Boolean),v=i.get(`ticketId`),[y,b]=(0,K.useState)({period:f,surface:g.length>0?g:void 0,provider:_.length>0?_:void 0,ticketId:v?Number(v):void 0}),[x,S]=(0,K.useState)(null),[C,w]=(0,K.useState)(!0),[T,E]=(0,K.useState)(null),[D,O]=(0,K.useState)({}),[k,A]=(0,K.useState)(null),j=(0,K.useRef)(new Map),M=(0,K.useRef)(0);(0,K.useEffect)(()=>{let e=new URLSearchParams;e.set(`period`,y.period),y.surface&&y.surface.length>0&&e.set(`surface`,y.surface.join(`,`)),y.provider&&y.provider.length>0&&e.set(`provider`,y.provider.join(`,`)),y.ticketId&&e.set(`ticketId`,String(y.ticketId)),a(e,{replace:!0})},[y.period,y.surface,y.provider,y.ticketId,a]);let N=(0,K.useCallback)(async()=>{if(!e)return;let t=++M.current;E(null);let n=`${e}:${$(y)}`,i=j.current.get(n);i?(S(i),w(!1)):w(!0);try{let e=await fetch(`${r()}/spending?${$(y)}`);if(!e.ok)throw Error(`HTTP ${e.status}`);if(t!==M.current)return;let i=await e.json();j.current.set(n,i),S(i),w(!1)}catch(e){if(t!==M.current)return;E(e.message),w(!1)}},[e,y]),P=(0,K.useCallback)(async()=>{if(!e)return;let t={...y};D.model&&(t.model=[D.model]),D.status&&(t.status=D.status),typeof D.minCostUsd==`number`&&(t.minCostUsd=D.minCostUsd);try{let e=await fetch(`${r()}/invocations?${$(t)}&limit=100`);if(!e.ok)throw Error(`HTTP ${e.status}`);A(await e.json())}catch{A(null)}},[e,y,D]);(0,K.useEffect)(()=>{N()},[N]),(0,K.useEffect)(()=>{P()},[P]);let F=(0,K.useRef)(null),I=o();(0,K.useEffect)(()=>{let t=`analytics-spending`;return I.registerHandler(t,t=>{let n=t;n.type===`spending.invalidated`&&n.projectId===e&&(F.current&&clearTimeout(F.current),F.current=setTimeout(()=>{j.current.clear(),N(),P()},500))}),()=>{I.unregisterHandler(t)}},[I,e,N,P]);function L(e){if(e===`all`){b(e=>({...e,surface:void 0}));return}b(t=>{let n=t.surface??[],r=n.includes(e)?n.filter(t=>t!==e):[...n,e];return{...t,surface:r.length>0?r:void 0}})}function R(e){if(e===`all`){b(e=>({...e,provider:void 0}));return}b(t=>{let n=t.provider??[],r=n.includes(e)?n.filter(t=>t!==e):[...n,e];return{...t,provider:r.length>0?r:void 0}})}let z=y.surface,ee=!z||z.length===0,B=y.provider,te=!B||B.length===0,ne=(0,K.useMemo)(()=>{let e={period:y.period};return y.surface&&y.surface.length>0&&(e.surface=y.surface.join(`,`)),y.provider&&y.provider.length>0&&(e.provider=y.provider.join(`,`)),y.ticketId&&(e.ticketId=String(y.ticketId)),e},[y]),re=x?x.summary.totalRuns===0:!1;return(0,q.jsxs)(`div`,{className:`flex flex-col gap-6 p-4 pb-12`,children:[(0,q.jsxs)(`div`,{className:`sticky top-0 z-10 -mx-4 px-4 py-3 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-b border-border/40`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,q.jsx)(`h1`,{className:`text-base font-semibold tracking-tight`,children:`Analytics`}),y.ticketId&&(0,q.jsxs)(`button`,{type:`button`,onClick:()=>b(e=>({...e,ticketId:void 0})),className:`inline-flex items-center gap-1 h-6 px-2 rounded-full text-[11px] font-medium bg-accent-highlight/15 text-accent-highlight ring-1 ring-accent-highlight/30 hover:bg-accent-highlight/25`,children:[`ticket #`,y.ticketId,` · ✕`]})]}),(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsx)(`div`,{className:`flex items-center gap-1 rounded-md border border-border/60 bg-card/40 p-0.5`,children:Pt.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>b(t=>({...t,period:e.value})),className:`px-2.5 h-6 rounded text-[11px] font-medium transition-colors ${y.period===e.value?`bg-accent text-foreground`:`text-muted-foreground hover:text-foreground`}`,children:e.label},e.value))}),(0,q.jsx)(h,{baseUrl:`${r()}/analytics/export`,params:ne,disabled:re}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>{j.current.clear(),N(),P()},className:`h-7 w-7 inline-flex items-center justify-center rounded-md border border-border/60 bg-card/50 text-muted-foreground hover:text-foreground hover:bg-accent/60`,title:`Refresh`,children:(0,q.jsx)(n,{className:`w-3 h-3`})})]})]}),(0,q.jsx)(`div`,{className:`mt-3 flex flex-wrap items-center gap-1.5`,children:Ft.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>L(e.value),className:`h-7 px-3 rounded-full text-[11px] font-medium transition-all ${(e.value===`all`?ee:z?.includes(e.value)??!1)?`bg-foreground/10 text-foreground ring-1 ring-foreground/20`:`text-muted-foreground hover:text-foreground hover:bg-accent/40`}`,children:e.label},e.value))}),u&&(0,q.jsxs)(`div`,{className:`mt-2 flex flex-wrap items-center gap-1.5`,"data-testid":`analytics-provider-chips`,children:[(0,q.jsx)(`span`,{className:`text-[10px] uppercase tracking-wide text-muted-foreground/70 mr-1`,children:`Engine`}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>R(`all`),className:`h-7 px-3 rounded-full text-[11px] font-medium transition-all ${te?`bg-foreground/10 text-foreground ring-1 ring-foreground/20`:`text-muted-foreground hover:text-foreground hover:bg-accent/40`}`,children:`All`}),l.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>R(e),className:`h-7 px-3 rounded-full text-[11px] font-medium transition-all ${B?.includes(e)??!1?`bg-foreground/10 text-foreground ring-1 ring-foreground/20`:`text-muted-foreground hover:text-foreground hover:bg-accent/40`}`,children:s(e)},e))]})]}),T&&(0,q.jsxs)(`div`,{className:`rounded-lg border border-accent-warning/30 bg-accent-warning/10 p-4 flex items-center justify-between`,children:[(0,q.jsxs)(`p`,{className:`text-sm text-accent-warning`,children:[`Failed to load: `,T]}),(0,q.jsxs)(`button`,{onClick:()=>N(),className:`flex items-center gap-1.5 h-7 px-3 rounded-md text-xs text-accent-warning border border-accent-warning/30 hover:bg-accent-warning/10`,children:[(0,q.jsx)(n,{className:`w-3 h-3`}),`Retry`]})]}),(0,q.jsx)(Ne,{data:x,loading:C}),(0,q.jsx)(ze,{data:x,loading:C}),(0,q.jsx)(vt,{data:x,loading:C}),(0,q.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,q.jsx)(Ct,{data:x,loading:C}),(0,q.jsx)(wt,{data:x,loading:C,onSelectModel:e=>b(t=>({...t,model:[e]})),activeModel:y.model?.[0]})]}),(0,q.jsx)(Et,{data:x,loading:C,onSelectPoint:e=>{O(e=>({...e})),b(t=>({...t,ticketId:e.ticketId??void 0}))}}),(0,q.jsx)(Dt,{data:x,loading:C,onSelectTicket:e=>b(t=>({...t,ticketId:e??void 0}))}),(0,q.jsx)(Nt,{rows:k?.rows??[],loading:C&&!k,truncated:k?.truncated??!1,totalAvailable:k?.totalAvailable??0,tableFilters:D,onTableFiltersChange:O})]})}export{It as default};
|
|
1
|
+
import{r as e}from"./chunk-CilyBKbf.js";import{t}from"./clsx-Cv6vnfjX.js";import{B as n,St as r,Vt as i,_t as a,bt as o,h as s,o as c,pt as l,s as u,vt as d,xt as f,yt as p,zt as m}from"./index-hPtSDG5z.js";import{t as h}from"./ExportDropdown-tFIBg_zE.js";import{A as g,B as _,C as v,D as y,E as b,F as x,G as S,H as C,I as w,J as T,K as E,L as D,M as O,N as k,O as A,P as j,Q as M,R as N,S as P,T as F,V as I,X as L,Z as R,_ as z,_t as ee,a as B,at as te,b as ne,c as re,ct as ie,et as ae,f as oe,g as se,gt as ce,h as le,i as ue,j as de,k as fe,l as pe,lt as V,m as me,n as he,nt as H,o as ge,ot as _e,p as ve,pt as U,q as ye,r as be,rt as W,s as xe,st as Se,t as Ce,tt as we,ut as G,v as Te,x as Ee,y as De,z as Oe}from"./BarChart-Dz_dPaiK.js";var ke=a(`arrow-down-right`,[[`path`,{d:`m7 7 10 10`,key:`1fmybs`}],[`path`,{d:`M17 7v10H7`,key:`6fjiku`}]]),K=e(i(),1),q=f();function J(e){return e>=100?`$${e.toFixed(0)}`:e>=10?`$${e.toFixed(1)}`:`$${e.toFixed(2)}`}function Ae(e){return e>=1e3?`$${(e/1e3).toFixed(1)}k`:`$${e.toFixed(2)}`}function je(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:`${e}`}var Me=[`job`,`explore-spec`,`quick-spec`,`ai-edit`,`smash`];function Ne({data:e,loading:t}){let[n,r]=(0,K.useState)(0),i=(0,K.useRef)(0);if((0,K.useEffect)(()=>{if(!e)return;let t=e.summary.totalCostUsd;if(i.current===0&&t>0){let e=performance.now(),n=i=>{let a=Math.min(1,(i-e)/600),o=1-(1-a)**3;r(0+(t-0)*o),a<1&&requestAnimationFrame(n)};requestAnimationFrame(n)}else r(t);i.current=t},[e]),t&&!e)return(0,q.jsx)(`div`,{className:`h-44 rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let a=e.summary.totalCostUsd,o=e.summary.totalRuns,s=e.summary.totalTokens??0,d=e.summary.totalEstimatedCostUsd??0,f=e.summary.deltaPct,p=e.trackingStartedAt,m=d>0,h=Me.map(t=>{let n=e.bySurface.find(e=>e.surface===t);return{surface:t,costUsd:n?.costUsd??0,count:n?.count??0}});return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-gradient-to-br from-card/80 to-card/40 p-5`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-end justify-between gap-3 mb-4`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`text-[11px] uppercase tracking-wider text-muted-foreground mb-1`,children:`Spending`}),(0,q.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,q.jsx)(`div`,{className:`text-5xl font-semibold tabular-nums tracking-tight`,children:Ae(n)}),f!==null&&(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-0.5 text-xs font-medium ${f>=0?`text-accent-warning`:`text-accent-success`}`,children:[f>=0?(0,q.jsx)(l,{className:`w-3 h-3`}):(0,q.jsx)(ke,{className:`w-3 h-3`}),Math.abs(f).toFixed(0),`% vs prev`]})]}),(0,q.jsxs)(`div`,{className:`text-xs text-muted-foreground mt-1 tabular-nums flex items-center gap-2`,children:[(0,q.jsxs)(`span`,{children:[o,` invocation`,o===1?``:`s`]}),s>0&&(0,q.jsxs)(`span`,{className:`text-muted-foreground/80`,title:`Total tokens = fresh input + output + cache-read + cache-create across all invocations in this window.`,children:[`· `,je(s),` tokens`]}),m&&(0,q.jsxs)(`span`,{className:`text-[10px] text-muted-foreground/70 italic`,title:`Includes ${J(d)} of estimated cost from providers without a native cost field (e.g. codex via the local pricing table).`,children:[`· includes ~`,J(d),` estimated`]})]})]}),o===0&&p&&(0,q.jsxs)(`div`,{className:`text-xs text-muted-foreground`,children:[`Tracking started `,p.slice(0,10)]})]}),o===0?(0,q.jsxs)(`div`,{className:`rounded-lg border border-dashed border-border/40 p-6 text-center`,children:[(0,q.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`No invocations yet for this filter window.`}),(0,q.jsxs)(`p`,{className:`text-xs text-muted-foreground/70 mt-1`,children:[`Tracking started `,p?p.slice(0,10):`on first invocation`]})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`h-3 w-full rounded-full overflow-hidden bg-background-deep flex`,children:h.map(e=>{let t=a>0?e.costUsd/a*100:0;return t===0?null:(0,q.jsx)(`div`,{className:`h-full ${c[e.surface].dot}`,style:{width:`${t}%`},title:`${u[e.surface]}: ${J(e.costUsd)}`},e.surface)})}),(0,q.jsx)(`div`,{className:`mt-3 flex flex-wrap items-center gap-x-5 gap-y-1.5 text-xs`,children:h.filter(e=>e.costUsd>0).map(e=>(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 tabular-nums`,children:[(0,q.jsx)(`span`,{className:`w-2 h-2 rounded-full ${c[e.surface].dot}`}),(0,q.jsx)(`span`,{className:`text-muted-foreground`,children:u[e.surface]}),(0,q.jsx)(`span`,{className:`text-foreground font-medium`,children:J(e.costUsd)}),(0,q.jsx)(`span`,{className:`text-muted-foreground/60`,children:`·`}),(0,q.jsx)(`span`,{className:`text-muted-foreground/80`,children:e.count})]},e.surface))})]})]})}var Pe={claude:`Claude`,codex:`Codex`},Fe={claude:`bg-accent-info`,codex:`bg-accent-highlight`};function Ie(e){return e>=100?`$${e.toFixed(0)}`:e>=10?`$${e.toFixed(1)}`:e>=.01?`$${e.toFixed(2)}`:`$${e.toFixed(4)}`}function Le(e){return Pe[e]??e}function Re(e){return Fe[e]??`bg-accent-secondary`}function ze({data:e,loading:t}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-32 rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e||e.byProvider.length===0||e.byProvider.length===1)return null;let n=e.byProvider.reduce((e,t)=>e+t.costUsd+t.estimatedCostUsd,0);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsx)(`div`,{className:`flex items-baseline justify-between mb-3`,children:(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`text-[11px] uppercase tracking-wider text-muted-foreground`,children:`By provider`}),(0,q.jsxs)(`div`,{className:`text-xs text-muted-foreground/70 mt-0.5`,children:[`How cost splits across the AI CLIs in this project. The`,` `,(0,q.jsx)(`span`,{className:`font-medium`,children:`~`}),` prefix marks rows where cost is estimated from the local pricing table (the provider does not report it natively).`]})]})}),n===0?(0,q.jsx)(`div`,{className:`text-xs text-muted-foreground italic`,children:`No cost recorded yet in this window.`}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`h-2 w-full rounded-full overflow-hidden bg-background-deep flex mb-3`,children:e.byProvider.map(e=>{let t=e.costUsd+e.estimatedCostUsd,r=n>0?t/n*100:0;return r===0?null:(0,q.jsx)(`div`,{className:`h-full ${Re(e.provider)}`,style:{width:`${r}%`},title:`${Le(e.provider)}: ${Ie(t)} (${e.count})`},e.provider)})}),(0,q.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-2`,children:e.byProvider.map(e=>(0,q.jsx)(Be,{entry:e},e.provider))})]})]})}function Be({entry:e}){let t=e.costUsd+e.estimatedCostUsd,n=e.costUsd===0&&e.estimatedCostUsd>0;return(0,q.jsxs)(`div`,{className:`flex items-center gap-2.5 rounded-md border border-border/30 px-2.5 py-1.5`,children:[(0,q.jsx)(`span`,{className:`w-2 h-2 rounded-full shrink-0 ${Re(e.provider)}`}),(0,q.jsx)(`span`,{className:`text-xs font-medium`,children:Le(e.provider)}),(0,q.jsxs)(`span`,{className:`text-[10px] text-muted-foreground tabular-nums`,children:[e.count,` run`,e.count===1?``:`s`]}),(0,q.jsxs)(`span`,{className:`ml-auto text-xs font-medium tabular-nums`,children:[n?`~`:``,Ie(t)]})]})}var Ve=[`option`,`isActive`];function Y(){return Y=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Y.apply(null,arguments)}function He(e,t){if(e==null)return{};var n,r,i=Ue(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Ue(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function We(e){var{option:t,isActive:n}=e,r=He(e,Ve);return typeof t==`string`?K.createElement(P,Y({option:K.createElement(Se,Y({type:t},r)),isActive:n,shapeType:`symbols`},r)):K.createElement(P,Y({option:t,isActive:n,shapeType:`symbols`},r))}var Ge=ae([(e,t,n,r,i,a,o)=>N(e,void 0,void 0,o),(e,t,n,r,i,a,o)=>k(e,`xAxis`,t,o),(e,t,n,r,i,a,o)=>j(e,`xAxis`,t,o),(e,t,n,r,i,a,o)=>k(e,`yAxis`,n,o),(e,t,n,r,i,a,o)=>j(e,`yAxis`,n,o),(e,t,n,r)=>w(e,`zAxis`,r,!1),ae([x,(e,t,n,r,i)=>i],(e,t)=>e.filter(e=>e.type===`scatter`).find(e=>e.id===t)),(e,t,n,r,i,a)=>a],(e,t,n,r,i,a,o,s)=>{var{chartData:c,dataStartIndex:l,dataEndIndex:u}=e;if(o!=null){var d=o?.data!=null&&o.data.length>0?o.data:c?.slice(l,u+1);if(!(d==null||t==null||r==null||n==null||i==null||n?.length===0||i?.length===0))return ot({displayedData:d,xAxis:t,yAxis:r,zAxis:a,scatterSettings:o,xAxisTicks:n,yAxisTicks:i,cells:s})}}),Ke=[`id`],qe=[`onMouseEnter`,`onClick`,`onMouseLeave`],Je=[`animationBegin`,`animationDuration`,`animationEasing`,`hide`,`isAnimationActive`,`legendType`,`lineJointType`,`lineType`,`shape`,`xAxisId`,`yAxisId`,`zAxisId`];function X(e,t){if(e==null)return{};var n,r,i=Ye(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function Ye(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function Z(){return Z=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},Z.apply(null,arguments)}function Xe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function Q(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?Xe(Object(n),!0).forEach(function(t){Ze(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Xe(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function Ze(e,t,n){return(t=Qe(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Qe(e){var t=$e(e,`string`);return typeof t==`symbol`?t:t+``}function $e(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}var et=e=>{var{dataKey:t,name:n,fill:r,legendType:i,hide:a}=e;return[{inactive:a,dataKey:t,type:i,color:r,value:R(n,t),payload:e}]},tt=K.memo(e=>{var{dataKey:t,points:n,stroke:r,strokeWidth:i,fill:a,name:o,hide:s,tooltipType:c,id:l}=e,u={dataDefinedOnItem:n?.map(e=>e.tooltipPayload),getPosition:e=>{var t;return n==null||(t=n[Number(e)])==null?void 0:t.tooltipPosition},settings:{stroke:r,strokeWidth:i,fill:a,nameKey:void 0,dataKey:t,name:R(o,t),hide:s,type:c,color:a,unit:``,graphicalItemId:l}};return K.createElement(Te,{tooltipEntrySettings:u})});function nt(e){var{points:t,props:n}=e,{line:r,lineType:i,lineJointType:a}=n;if(!r)return null;var o=ce(n),s=ee(r),c,l;if(i===`joint`)c=t.map(e=>({x:e.cx??null,y:e.cy??null}));else if(i===`fitting`){var{xmin:u,xmax:d,a:f,b:p}=ie(t),m=e=>f*e+p;c=[{x:u,y:m(u)},{x:d,y:m(d)}]}var h=Q(Q(Q({},o),{},{fill:`none`,stroke:o&&o.fill},s),{},{points:c});return l=K.isValidElement(r)?K.cloneElement(r,h):typeof r==`function`?r(h):K.createElement(I,Z({},h,{type:a})),K.createElement(U,{className:`recharts-scatter-line`,key:`recharts-scatter-line`},l)}function rt(e){var{showLabels:t,points:n,children:r}=e,i=S(),a=(0,K.useMemo)(()=>n?.map(e=>{var t={x:e.x??0,y:e.y??0,width:e.width,height:e.height,lowerWidth:e.width,upperWidth:e.width};return Q(Q({},t),{},{value:void 0,payload:e.payload,viewBox:t,parentViewBox:i,fill:void 0})}),[i,n]);return K.createElement(F,{value:t?a:void 0},r)}function it(e){var{points:t,allOtherScatterProps:n}=e,{shape:r,activeShape:i,dataKey:a}=n,{id:o}=n,s=X(n,Ke),c=H(de),{onMouseEnter:l,onClick:u,onMouseLeave:d}=n,f=X(n,qe),p=ne(l,a,o),m=Ee(d),h=De(u,a,o);if(!_e(t))return null;var _=ce(s);return K.createElement(K.Fragment,null,K.createElement(nt,{points:t,props:s}),t.map((e,t)=>{var n=i!=null&&i!==!1,a=n&&c===String(t),s=n&&a?i:r,l=Q(Q(Q({},_),e),{},{index:t,[T]:String(o)});return K.createElement(g,{key:`symbol-${e?.cx}-${e?.cy}-${e?.size}-${t}`,zIndex:a?D.activeDot:void 0},K.createElement(U,Z({className:`recharts-scatter-symbol`},te(f,e,t),{onMouseEnter:p(e,t),onMouseLeave:m(e,t),onClick:h(e,t)}),K.createElement(We,Z({option:s,isActive:a},l))))}))}function at(e){var{previousPointsRef:t,props:n}=e,{points:r,isAnimationActive:i,animationBegin:a,animationDuration:o,animationEasing:s}=n,c=t.current,l=Oe(n,`recharts-scatter-`),[u,d]=(0,K.useState)(!1),f=(0,K.useCallback)(()=>{d(!1)},[]),p=(0,K.useCallback)(()=>{d(!0)},[]),m=!u;return K.createElement(rt,{showLabels:m,points:r},n.children,K.createElement(_,{animationId:l,begin:a,duration:o,isActive:i,easing:s,onAnimationEnd:f,onAnimationStart:p,key:l},e=>{var i=e===1?r:r?.map((t,n)=>{var r=c&&c[n];return r?Q(Q({},t),{},{cx:t.cx==null?void 0:V(r.cx,t.cx,e),cy:t.cy==null?void 0:V(r.cy,t.cy,e),size:V(r.size,t.size,e)}):Q(Q({},t),{},{size:V(0,t.size,e)})});return e>0&&(t.current=i),K.createElement(U,null,K.createElement(it,{points:i,allOtherScatterProps:n,showLabels:m}))}),K.createElement(b,{label:n.label}))}function ot(e){var{displayedData:t,xAxis:n,yAxis:r,zAxis:i,scatterSettings:a,xAxisTicks:o,yAxisTicks:s,cells:c}=e,l=G(n.dataKey)?a.dataKey:n.dataKey,u=G(r.dataKey)?a.dataKey:r.dataKey,d=i&&i.dataKey,f=i?i.range:O.range,p=f&&f[0],m=n.scale.bandwidth?n.scale.bandwidth():0,h=r.scale.bandwidth?r.scale.bandwidth():0;return t.map((e,t)=>{var f=M(e,l),g=M(e,u),_=!G(d)&&M(e,d)||`-`,v=[{name:G(n.dataKey)?a.name:n.name||String(n.dataKey),unit:n.unit||``,value:f,payload:e,dataKey:l,type:a.tooltipType,graphicalItemId:a.id},{name:G(r.dataKey)?a.name:r.name||String(r.dataKey),unit:r.unit||``,value:g,payload:e,dataKey:u,type:a.tooltipType,graphicalItemId:a.id}];_!==`-`&&i!=null&&v.push({name:i.name||i.dataKey,unit:i.unit||``,value:_,payload:e,dataKey:d,type:a.tooltipType,graphicalItemId:a.id});var y=L({axis:n,ticks:o,bandSize:m,entry:e,index:t,dataKey:l}),b=L({axis:r,ticks:s,bandSize:h,entry:e,index:t,dataKey:u}),x=_!==`-`&&i!=null?i.scale.map(_):p,S=x==null?0:Math.sqrt(Math.max(x,0)/Math.PI);return Q(Q({},e),{},{cx:y,cy:b,x:y==null?void 0:y-S,y:b==null?void 0:b-S,width:2*S,height:2*S,size:x,node:{x:f,y:g,z:_},tooltipPayload:v,tooltipPosition:{x:y,y:b},payload:e},c&&c[t]&&c[t].props)})}var st=(e,t,n)=>({x:e.cx,y:e.cy,value:Number(n===`x`?e.node.x:e.node.y),errorVal:M(e,t)});function ct(e){var{hide:n,points:r,className:i,needClip:a,xAxisId:o,yAxisId:s,id:c}=e,l=(0,K.useRef)(null);if(n)return null;var u=t(`recharts-scatter`,i),d=c;return K.createElement(g,{zIndex:e.zIndex},K.createElement(U,{className:u,clipPath:a?`url(#clipPath-${d})`:void 0,id:c},a&&K.createElement(`defs`,null,K.createElement(ge,{clipPathId:d,xAxisId:o,yAxisId:s})),K.createElement(re,{xAxisId:o,yAxisId:s,data:r,dataPointFormatter:st,errorBarOffset:0},K.createElement(U,{key:`recharts-scatter-symbols`},K.createElement(at,{props:e,previousPointsRef:l})))))}var lt={xAxisId:0,yAxisId:0,zAxisId:0,label:!1,line:!1,legendType:`circle`,lineType:`joint`,lineJointType:`linear`,shape:`circle`,hide:!1,isAnimationActive:`auto`,animationBegin:0,animationDuration:400,animationEasing:`linear`,zIndex:D.scatter};function ut(e){var t=W(e,lt),{animationBegin:n,animationDuration:r,animationEasing:i,hide:a,isAnimationActive:o,legendType:s,lineJointType:c,lineType:l,shape:u,xAxisId:d,yAxisId:f,zAxisId:p}=t,m=X(t,Je),{needClip:h}=xe(d,f),g=(0,K.useMemo)(()=>v(e.children,y),[e.children]),_=ye(),b=H(t=>Ge(t,d,f,p,e.id,g,_));return h==null||b==null?null:K.createElement(K.Fragment,null,K.createElement(tt,{dataKey:e.dataKey,points:b,stroke:e.stroke,strokeWidth:e.strokeWidth,fill:e.fill,name:e.name,hide:e.hide,tooltipType:e.tooltipType,id:e.id}),K.createElement(ct,Z({},m,{xAxisId:d,yAxisId:f,zAxisId:p,lineType:l,lineJointType:c,legendType:s,shape:u,hide:a,isAnimationActive:o,animationBegin:n,animationDuration:r,animationEasing:i,points:b,needClip:h})))}function dt(e){var t=W(e,lt),n=ye();return K.createElement(se,{id:t.id,type:`scatter`},e=>K.createElement(K.Fragment,null,K.createElement(z,{legendPayload:et(t)}),K.createElement(le,{type:`scatter`,id:e,data:t.data,xAxisId:t.xAxisId,yAxisId:t.yAxisId,zAxisId:t.zAxisId,dataKey:t.dataKey,hide:t.hide,name:t.name,tooltipType:t.tooltipType,isPanorama:n}),K.createElement(ut,Z({},t,{id:e}))))}var ft=K.memo(dt,C);ft.displayName=`Scatter`;function pt(e){var t=we(),n=(0,K.useRef)(null);return(0,K.useLayoutEffect)(()=>{n.current===null?t(oe(e)):n.current!==e&&t(me({prev:n.current,next:e})),n.current=e},[e,t]),(0,K.useLayoutEffect)(()=>()=>{n.current&&=(t(ve(n.current)),null)},[t]),null}var mt={zAxisId:0,range:O.range,scale:O.scale,type:O.type};function ht(e){var t=W(e,mt);return K.createElement(pt,{domain:t.domain,id:t.zAxisId,dataKey:t.dataKey,name:t.name,unit:t.unit,range:t.range,scale:t.scale,type:t.type,allowDuplicatedCategory:O.allowDuplicatedCategory,allowDataOverflow:O.allowDataOverflow,reversed:O.reversed,includeHidden:O.includeHidden})}ht.displayName=`ZAxis`;var gt=[`item`],_t=(0,K.forwardRef)((e,t)=>K.createElement(he,{chartName:`ScatterChart`,defaultTooltipEventType:`item`,validateTooltipEventTypes:gt,tooltipPayloadSearcher:fe,categoricalChartProps:e,ref:t}));function vt({data:e,loading:t}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[220px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let n=e.dailyTimeline.map(e=>({date:e.date.slice(5),Jobs:e.jobsCostUsd,Explore:e.exploreCostUsd,Quick:e.quickCostUsd,Refine:e.aiEditCostUsd,"File summaries":e.fileSummaryCostUsd??0})),r=n.every(e=>e.Jobs+e.Explore+e.Quick+e.Refine+e[`File summaries`]===0);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`Daily timeline`}),(0,q.jsx)(`span`,{className:`text-[10px] text-muted-foreground/70`,children:`stacked by surface`})]}),r?(0,q.jsx)(`div`,{className:`h-40 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No spend in this period.`}):(0,q.jsx)(`div`,{className:`h-[220px]`,children:(0,q.jsx)(E,{width:`100%`,height:`100%`,children:(0,q.jsxs)(Ce,{data:n,margin:{top:10,right:10,left:-8,bottom:0},children:[(0,q.jsx)(pe,{strokeDasharray:`2 4`,stroke:`currentColor`,className:`text-border/30`,vertical:!1}),(0,q.jsx)(ue,{dataKey:`date`,tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`}),(0,q.jsx)(be,{tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`,tickFormatter:e=>`$${e}`}),(0,q.jsx)(A,{contentStyle:{backgroundColor:`var(--popover)`,border:`1px solid var(--border)`,fontSize:11,borderRadius:6},formatter:(e,t)=>[`$${typeof e==`number`?e.toFixed(2):`—`}`,String(t)]}),(0,q.jsx)(B,{dataKey:`Jobs`,stackId:`a`,fill:`var(--accent-info, #5fa8d3)`}),(0,q.jsx)(B,{dataKey:`Explore`,stackId:`a`,fill:`var(--accent-highlight, #c084fc)`}),(0,q.jsx)(B,{dataKey:`Quick`,stackId:`a`,fill:`var(--accent-secondary, #f7768e)`}),(0,q.jsx)(B,{dataKey:`Refine`,stackId:`a`,fill:`var(--accent-success, #50fa7b)`}),(0,q.jsx)(B,{dataKey:`File summaries`,stackId:`a`,fill:`var(--accent-warning, #f1fa8c)`})]})})})]})}function yt(e){return e==null?`—`:e<.005?`$${e.toFixed(4)}`:e<1?`$${e.toFixed(3)}`:`$${e.toFixed(2)}`}function bt(e){return e==null?`—`:e<1e3?`${e} ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${Math.floor(e%6e4/1e3)}s`}function xt({values:e}){let t=Math.max(1e-4,...e);return(0,q.jsx)(`div`,{className:`flex items-end gap-[1px] h-5`,children:e.map((e,n)=>(0,q.jsx)(`div`,{className:`w-[3px] rounded-sm bg-foreground/40`,style:{height:`${Math.max(2,e/t*20)}px`}},n))})}function St({mode:e,label:t,accentClass:n}){let r=e.mode===`explore`&&e.totalRuns<5;return(0,q.jsxs)(`div`,{className:`flex-1 p-4 first:pr-2 last:pl-2`,children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-2 mb-2`,children:[(0,q.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full ${n}`}),(0,q.jsx)(`span`,{className:`text-xs font-medium uppercase tracking-wider text-muted-foreground`,children:t})]}),r?(0,q.jsxs)(`div`,{className:`py-3`,children:[(0,q.jsx)(`p`,{className:`text-sm text-foreground`,children:`Try Explore for richer specs`}),(0,q.jsxs)(`p`,{className:`text-xs text-muted-foreground mt-1`,children:[e.totalRuns,` run`,e.totalRuns===1?``:`s`,` so far`]})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`text-3xl font-semibold tabular-nums tracking-tight`,children:yt(e.avgCostPerSpec)}),(0,q.jsx)(`div`,{className:`text-[11px] text-muted-foreground mt-0.5`,children:`per spec`}),(0,q.jsx)(`div`,{className:`mt-3`,children:(0,q.jsx)(xt,{values:e.sparkline.length>0?e.sparkline:[0]})}),(0,q.jsxs)(`div`,{className:`mt-3 space-y-0.5 text-xs tabular-nums text-muted-foreground`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`span`,{className:`text-foreground font-medium`,children:e.ticketsCreated}),` created · `,e.totalRuns,` runs`]}),(0,q.jsxs)(`div`,{children:[bt(e.avgDurationMs),` avg`]}),(0,q.jsx)(`div`,{className:`truncate`,children:e.dominantModel??`—`})]})]})]})}function Ct({data:e,loading:t}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[220px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let n=e.byMode.find(e=>e.mode===`quick`),r=e.byMode.find(e=>e.mode===`explore`);if(!n||!r)return null;let i=n.avgCostPerSpec&&r.avgCostPerSpec&&n.avgCostPerSpec>0?r.avgCostPerSpec/n.avgCostPerSpec:null,a=i!==null&&n.totalRuns>=1&&r.totalRuns>=5;return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40`,children:[(0,q.jsx)(`div`,{className:`px-4 pt-3 pb-1`,children:(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`Quick vs Explore`})}),(0,q.jsxs)(`div`,{className:`flex divide-x divide-border/40`,children:[(0,q.jsx)(St,{mode:n,label:`Quick`,accentClass:`bg-accent-secondary`}),(0,q.jsx)(St,{mode:r,label:`Explore`,accentClass:`bg-accent-highlight`})]}),a&&(0,q.jsx)(`div`,{className:`px-4 pb-3 -mt-1`,children:(0,q.jsx)(`div`,{className:`text-center text-[11px] text-muted-foreground tabular-nums`,children:(0,q.jsxs)(`span`,{className:`px-2`,children:[`━━━━━━ `,i.toFixed(1),`× more per spec ━━━━━━`]})})})]})}function wt({data:e,loading:t,onSelectModel:n,activeModel:r}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[220px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let i=e.byModel.reduce((e,t)=>e+t.costUsd,0),a=e.byModel.slice(0,5);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3`,children:`Models`}),a.length===0?(0,q.jsx)(`div`,{className:`h-32 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No models recorded.`}):(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:a.map(e=>{let t=i>0?e.costUsd/i*100:0,a=r===e.model;return(0,q.jsx)(`li`,{children:(0,q.jsxs)(`button`,{type:`button`,onClick:()=>n(e.model),className:`w-full text-left group rounded-md px-2 py-1.5 transition-colors ${a?`bg-accent-highlight/10 ring-1 ring-accent-highlight/30`:`hover:bg-accent/30`}`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between text-[12px] mb-1 tabular-nums`,children:[(0,q.jsx)(`span`,{className:`truncate font-medium`,children:e.model}),(0,q.jsxs)(`span`,{className:`text-muted-foreground`,children:[`$`,e.costUsd.toFixed(2),` · `,e.count]})]}),(0,q.jsx)(`div`,{className:`h-1.5 rounded-full bg-background-deep overflow-hidden`,children:(0,q.jsx)(`div`,{className:`h-full ${a?`bg-accent-highlight`:`bg-foreground/40 group-hover:bg-foreground/60`} transition-colors`,style:{width:`${t}%`}})})]})},e.model)})})]})}var Tt={job:`var(--accent-info, #5fa8d3)`,"quick-spec":`var(--accent-secondary, #f7768e)`,"explore-spec":`var(--accent-highlight, #c084fc)`,"ai-edit":`var(--accent-success, #50fa7b)`,smash:`var(--accent-highlight, #c084fc)`};function Et({data:e,loading:t,onSelectPoint:n}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-[260px] rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let r=[`job`,`quick-spec`,`explore-spec`,`ai-edit`,`smash`],i=r.map(t=>({surface:t,points:e.scatter.filter(e=>e.surface===t).map(e=>({id:e.id,x:e.numTurns??Math.round((e.durationMs??0)/1e3),y:e.costUsd,surface:t,ticketId:e.ticketId,startedAt:e.startedAt,raw:e}))})),a=e.scatter.length===0;return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between mb-2`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`Cost vs Turns`}),(0,q.jsx)(`div`,{className:`flex flex-wrap items-center gap-2 text-[10px]`,children:r.map(e=>(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-1`,children:[(0,q.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full`,style:{background:Tt[e]}}),(0,q.jsx)(`span`,{className:`text-muted-foreground`,children:u[e]})]},e))})]}),a?(0,q.jsx)(`div`,{className:`h-40 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No invocations to plot.`}):(0,q.jsx)(`div`,{className:`h-[260px]`,children:(0,q.jsx)(E,{width:`100%`,height:`100%`,children:(0,q.jsxs)(_t,{margin:{top:10,right:10,left:-8,bottom:5},children:[(0,q.jsx)(pe,{strokeDasharray:`2 4`,stroke:`currentColor`,className:`text-border/30`}),(0,q.jsx)(ue,{type:`number`,dataKey:`x`,name:`turns`,tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`,label:{value:`turns`,position:`insideBottomRight`,offset:-2,fontSize:10,fill:`currentColor`}}),(0,q.jsx)(be,{type:`number`,dataKey:`y`,name:`cost`,tick:{fontSize:10},stroke:`currentColor`,className:`text-muted-foreground`,tickFormatter:e=>`$${e.toFixed(e<1?2:0)}`}),(0,q.jsx)(ht,{range:[40,80]}),(0,q.jsx)(A,{cursor:{strokeDasharray:`3 3`},contentStyle:{backgroundColor:`var(--popover)`,border:`1px solid var(--border)`,fontSize:11,borderRadius:6},formatter:(e,t)=>{let n=String(t);return n===`cost`&&typeof e==`number`?[`$${e.toFixed(3)}`,`cost`]:[String(e),n]}}),i.map(e=>(0,q.jsx)(ft,{data:e.points,fill:Tt[e.surface],onClick:e=>{let t=e;t?.raw&&n(t.raw)}},e.surface))]})})})]})}function Dt({data:e,loading:t,onSelectTicket:n}){if(t&&!e)return(0,q.jsx)(`div`,{className:`h-40 rounded-xl border border-border/40 bg-card/40 animate-pulse`});if(!e)return null;let r=e.topTickets;return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider mb-3`,children:`Top tickets`}),r.length===0?(0,q.jsx)(`div`,{className:`h-32 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No ticket activity in this period.`}):(0,q.jsx)(`ul`,{className:`divide-y divide-border/30`,children:r.map((e,t)=>{let r=Object.entries(e.bySurface).filter(([,e])=>e.count>0).map(([e,t])=>`${t.count} ${u[e].toLowerCase()}`).join(` + `),i=e.isUnattributed,a=i?`Unattributed`:e.ticketTitle?`#${e.ticketId} ${e.ticketTitle}`:`deleted ticket #${e.ticketId}`;return(0,q.jsx)(`li`,{children:(0,q.jsxs)(`button`,{type:`button`,onClick:()=>n(e.ticketId),className:`w-full text-left flex items-center justify-between gap-3 py-2 px-1 hover:bg-accent/30 rounded transition-colors ${!e.ticketTitle&&!i?`opacity-50`:``}`,disabled:i,children:[(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-sm truncate`,children:a}),(0,q.jsx)(`div`,{className:`text-[11px] text-muted-foreground truncate`,children:r||`—`})]}),(0,q.jsxs)(`div`,{className:`text-right tabular-nums`,children:[(0,q.jsxs)(`div`,{className:`text-sm font-medium`,children:[`$`,e.totalCostUsd.toFixed(2)]}),(0,q.jsxs)(`div`,{className:`text-[10px] text-muted-foreground`,children:[e.totalRuns,` run`,e.totalRuns===1?``:`s`]})]})]})},`${e.ticketId??`u`}-${t}`)})})]})}function Ot(e){return e==null?`—`:e<.005?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function kt(e){return e==null?`—`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function At(e){return e.surface_ref_id?.startsWith(`contract-refine:`)?!0:e.surface===`explore-spec`&&e.ticket_id!=null&&e.conversation_id!=null&&e.surface_ref_id===e.conversation_id&&e.model==null}function jt(e){let t=new Map;for(let n of e)n.model&&(n.conversation_id&&t.set(`conversation:${n.conversation_id}`,n.model),n.ticket_id!=null&&n.surface===`explore-spec`&&t.set(`ticket:${n.ticket_id}:explore-spec`,n.model),n.ticket_id!=null&&n.surface===`quick-spec`&&t.set(`ticket:${n.ticket_id}:quick-spec`,n.model));return t}function Mt(e,t){if(e.model)return e.model;if(!At(e))return null;if(e.conversation_id){let n=t.get(`conversation:${e.conversation_id}`);if(n)return n}return e.ticket_id==null?null:t.get(`ticket:${e.ticket_id}:${e.surface}`)??null}function Nt({rows:e,loading:t,truncated:n,totalAvailable:r,tableFilters:i,onTableFiltersChange:a}){let[o,s]=(0,K.useState)(null),l=jt(e);return(0,q.jsxs)(`div`,{className:`rounded-xl border border-border/50 bg-card/40 p-4`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3 mb-3`,children:[(0,q.jsx)(`h2`,{className:`text-xs font-medium text-muted-foreground uppercase tracking-wider`,children:`All invocations`}),(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 text-[11px]`,children:[(0,q.jsxs)(`select`,{value:i.status??``,onChange:e=>a({...i,status:e.target.value||void 0}),className:`h-7 px-2 rounded-md bg-background-deep border border-border/60 text-xs`,"aria-label":`Status filter`,children:[(0,q.jsx)(`option`,{value:``,children:`All status`}),(0,q.jsx)(`option`,{value:`success`,children:`Success`}),(0,q.jsx)(`option`,{value:`failed`,children:`Failed`}),(0,q.jsx)(`option`,{value:`aborted`,children:`Aborted`})]}),(0,q.jsx)(`input`,{type:`number`,step:`0.01`,min:`0`,placeholder:`≥ $0.00`,value:i.minCostUsd??``,onChange:e=>{let t=e.target.value===``?void 0:parseFloat(e.target.value);a({...i,minCostUsd:Number.isNaN(t)?void 0:t})},className:`h-7 w-24 px-2 rounded-md bg-background-deep border border-border/60 text-xs tabular-nums`,"aria-label":`Minimum cost filter`})]})]}),t?(0,q.jsx)(`div`,{className:`h-32 rounded bg-card/30 animate-pulse`}):e.length===0?(0,q.jsx)(`div`,{className:`h-32 flex items-center justify-center text-xs text-muted-foreground/70`,children:`No invocations match the current filters.`}):(0,q.jsx)(`div`,{className:`overflow-x-auto`,children:(0,q.jsxs)(`table`,{className:`w-full text-[12px] tabular-nums`,children:[(0,q.jsx)(`thead`,{className:`text-[10px] uppercase tracking-wider text-muted-foreground`,children:(0,q.jsxs)(`tr`,{className:`text-left`,children:[(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Surface`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Ticket`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2 text-right`,children:`Cost`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2 text-right`,children:`Turns`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2 text-right`,children:`Tokens`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Model`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Status`}),(0,q.jsx)(`th`,{className:`font-medium px-2 py-2`,children:`Started`})]})}),(0,q.jsx)(`tbody`,{children:e.map(e=>{let t=e.surface,n=c[t],r=(e.tokens_in??0)+(e.tokens_out??0)+(e.tokens_cache_read??0)+(e.tokens_cache_create??0),i=At(e),a=i?`Contract Layer`:u[t],d=Mt(e,l);return(0,q.jsxs)(`tr`,{onClick:()=>s(o===e.id?null:e.id),className:`border-t border-border/30 hover:bg-accent/30 cursor-pointer`,children:[(0,q.jsx)(`td`,{className:`px-2 py-2`,children:(0,q.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 px-2 h-5 rounded-full text-[10px] font-medium ${n.bg} ${n.text}`,children:[(0,q.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full ${n.dot}`}),a]})}),(0,q.jsx)(`td`,{className:`px-2 py-2 max-w-[260px]`,children:e.ticket_id==null?e.ticket_title?(0,q.jsx)(`span`,{className:`truncate block text-muted-foreground/90 italic`,title:`Provisional Explore title — not yet committed`,children:e.ticket_title}):(0,q.jsx)(`span`,{className:`text-muted-foreground/70`,children:`—`}):(0,q.jsxs)(`span`,{className:`truncate block`,children:[`#`,e.ticket_id,` `,i?(0,q.jsx)(`span`,{className:`text-muted-foreground/90`,children:`Contract Layer refinement`}):e.ticket_title??(0,q.jsx)(`span`,{className:`text-muted-foreground/70 italic`,children:`(deleted)`})]})}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-right font-medium`,children:e.total_cost_usd_estimated===1&&e.total_cost_usd!=null?(0,q.jsxs)(`span`,{title:`Estimated from local pricing table — this provider does not report cost natively.`,className:`text-muted-foreground/90`,children:[`~`,Ot(e.total_cost_usd)]}):Ot(e.total_cost_usd)}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-right`,children:kt(e.num_turns)}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-right`,children:r>0?kt(r):`—`}),(0,q.jsxs)(`td`,{className:`px-2 py-2 max-w-[180px] truncate`,children:[d??`—`,d&&!e.model?(0,q.jsx)(`span`,{className:`ml-1 text-[10px] text-muted-foreground/70`,children:`inferred`}):null]}),(0,q.jsxs)(`td`,{className:`px-2 py-2`,children:[e.status===`success`?(0,q.jsx)(`span`,{className:`text-accent-success/90`,children:`●`}):e.status===`failed`?(0,q.jsx)(`span`,{className:`text-accent-warning`,children:`⚠`}):(0,q.jsx)(`span`,{className:`text-muted-foreground`,children:`○`}),(0,q.jsx)(`span`,{className:`ml-1 text-muted-foreground`,children:e.status})]}),(0,q.jsx)(`td`,{className:`px-2 py-2 text-muted-foreground`,children:e.started_at.slice(0,16).replace(`T`,` `)})]},e.id)})})]})}),n&&(0,q.jsxs)(`div`,{className:`mt-2 text-[11px] text-muted-foreground/80`,children:[`Showing first `,e.length,` of `,r.toLocaleString(),` matching rows.`]})]})}var Pt=[{value:`7d`,label:`7d`},{value:`30d`,label:`30d`},{value:`90d`,label:`90d`},{value:`all`,label:`All`}],Ft=[{value:`all`,label:`All`},{value:`job`,label:`Jobs`},{value:`explore-spec`,label:`Explore`},{value:`quick-spec`,label:`Quick`},{value:`ai-edit`,label:`Refine`},{value:`smash`,label:`SMASH`},{value:`file-summary`,label:`File summaries`}];function $(e){let t=new URLSearchParams;return e.period&&t.set(`period`,e.period),e.from&&t.set(`from`,e.from),e.to&&t.set(`to`,e.to),e.surface&&e.surface.length>0&&t.set(`surface`,e.surface.join(`,`)),e.provider&&e.provider.length>0&&t.set(`provider`,e.provider.join(`,`)),e.model&&e.model.length>0&&t.set(`model`,e.model.join(`,`)),e.status&&t.set(`status`,e.status),typeof e.minCostUsd==`number`&&t.set(`minCostUsd`,String(e.minCostUsd)),typeof e.ticketId==`number`&&t.set(`ticketId`,String(e.ticketId)),t.toString()}function It(){let{activeProjectId:e,projects:t}=p(),[i,a]=m(),c=t.find(t=>t.id===e),l=c?d(c):[`claude`],u=l.length>1,f=i.get(`period`)??`30d`,g=(i.get(`surface`)??``).split(`,`).filter(Boolean),_=(i.get(`provider`)??``).split(`,`).filter(Boolean),v=i.get(`ticketId`),[y,b]=(0,K.useState)({period:f,surface:g.length>0?g:void 0,provider:_.length>0?_:void 0,ticketId:v?Number(v):void 0}),[x,S]=(0,K.useState)(null),[C,w]=(0,K.useState)(!0),[T,E]=(0,K.useState)(null),[D,O]=(0,K.useState)({}),[k,A]=(0,K.useState)(null),j=(0,K.useRef)(new Map),M=(0,K.useRef)(0);(0,K.useEffect)(()=>{let e=new URLSearchParams;e.set(`period`,y.period),y.surface&&y.surface.length>0&&e.set(`surface`,y.surface.join(`,`)),y.provider&&y.provider.length>0&&e.set(`provider`,y.provider.join(`,`)),y.ticketId&&e.set(`ticketId`,String(y.ticketId)),a(e,{replace:!0})},[y.period,y.surface,y.provider,y.ticketId,a]);let N=(0,K.useCallback)(async()=>{if(!e)return;let t=++M.current;E(null);let n=`${e}:${$(y)}`,i=j.current.get(n);i?(S(i),w(!1)):w(!0);try{let e=await fetch(`${r()}/spending?${$(y)}`);if(!e.ok)throw Error(`HTTP ${e.status}`);if(t!==M.current)return;let i=await e.json();j.current.set(n,i),S(i),w(!1)}catch(e){if(t!==M.current)return;E(e.message),w(!1)}},[e,y]),P=(0,K.useCallback)(async()=>{if(!e)return;let t={...y};D.model&&(t.model=[D.model]),D.status&&(t.status=D.status),typeof D.minCostUsd==`number`&&(t.minCostUsd=D.minCostUsd);try{let e=await fetch(`${r()}/invocations?${$(t)}&limit=100`);if(!e.ok)throw Error(`HTTP ${e.status}`);A(await e.json())}catch{A(null)}},[e,y,D]);(0,K.useEffect)(()=>{N()},[N]),(0,K.useEffect)(()=>{P()},[P]);let F=(0,K.useRef)(null),I=o();(0,K.useEffect)(()=>{let t=`analytics-spending`;return I.registerHandler(t,t=>{let n=t;n.type===`spending.invalidated`&&n.projectId===e&&(F.current&&clearTimeout(F.current),F.current=setTimeout(()=>{j.current.clear(),N(),P()},500))}),()=>{I.unregisterHandler(t)}},[I,e,N,P]);function L(e){if(e===`all`){b(e=>({...e,surface:void 0}));return}b(t=>{let n=t.surface??[],r=n.includes(e)?n.filter(t=>t!==e):[...n,e];return{...t,surface:r.length>0?r:void 0}})}function R(e){if(e===`all`){b(e=>({...e,provider:void 0}));return}b(t=>{let n=t.provider??[],r=n.includes(e)?n.filter(t=>t!==e):[...n,e];return{...t,provider:r.length>0?r:void 0}})}let z=y.surface,ee=!z||z.length===0,B=y.provider,te=!B||B.length===0,ne=(0,K.useMemo)(()=>{let e={period:y.period};return y.surface&&y.surface.length>0&&(e.surface=y.surface.join(`,`)),y.provider&&y.provider.length>0&&(e.provider=y.provider.join(`,`)),y.ticketId&&(e.ticketId=String(y.ticketId)),e},[y]),re=x?x.summary.totalRuns===0:!1;return(0,q.jsxs)(`div`,{className:`flex flex-col gap-6 p-4 pb-12`,children:[(0,q.jsxs)(`div`,{className:`sticky top-0 z-10 -mx-4 px-4 py-3 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-b border-border/40`,children:[(0,q.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,q.jsx)(`h1`,{className:`text-base font-semibold tracking-tight`,children:`Analytics`}),y.ticketId&&(0,q.jsxs)(`button`,{type:`button`,onClick:()=>b(e=>({...e,ticketId:void 0})),className:`inline-flex items-center gap-1 h-6 px-2 rounded-full text-[11px] font-medium bg-accent-highlight/15 text-accent-highlight ring-1 ring-accent-highlight/30 hover:bg-accent-highlight/25`,children:[`ticket #`,y.ticketId,` · ✕`]})]}),(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsx)(`div`,{className:`flex items-center gap-1 rounded-md border border-border/60 bg-card/40 p-0.5`,children:Pt.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>b(t=>({...t,period:e.value})),className:`px-2.5 h-6 rounded text-[11px] font-medium transition-colors ${y.period===e.value?`bg-accent text-foreground`:`text-muted-foreground hover:text-foreground`}`,children:e.label},e.value))}),(0,q.jsx)(h,{baseUrl:`${r()}/analytics/export`,params:ne,disabled:re}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>{j.current.clear(),N(),P()},className:`h-7 w-7 inline-flex items-center justify-center rounded-md border border-border/60 bg-card/50 text-muted-foreground hover:text-foreground hover:bg-accent/60`,title:`Refresh`,children:(0,q.jsx)(n,{className:`w-3 h-3`})})]})]}),(0,q.jsx)(`div`,{className:`mt-3 flex flex-wrap items-center gap-1.5`,children:Ft.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>L(e.value),className:`h-7 px-3 rounded-full text-[11px] font-medium transition-all ${(e.value===`all`?ee:z?.includes(e.value)??!1)?`bg-foreground/10 text-foreground ring-1 ring-foreground/20`:`text-muted-foreground hover:text-foreground hover:bg-accent/40`}`,children:e.label},e.value))}),u&&(0,q.jsxs)(`div`,{className:`mt-2 flex flex-wrap items-center gap-1.5`,"data-testid":`analytics-provider-chips`,children:[(0,q.jsx)(`span`,{className:`text-[10px] uppercase tracking-wide text-muted-foreground/70 mr-1`,children:`Engine`}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>R(`all`),className:`h-7 px-3 rounded-full text-[11px] font-medium transition-all ${te?`bg-foreground/10 text-foreground ring-1 ring-foreground/20`:`text-muted-foreground hover:text-foreground hover:bg-accent/40`}`,children:`All`}),l.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>R(e),className:`h-7 px-3 rounded-full text-[11px] font-medium transition-all ${B?.includes(e)??!1?`bg-foreground/10 text-foreground ring-1 ring-foreground/20`:`text-muted-foreground hover:text-foreground hover:bg-accent/40`}`,children:s(e)},e))]})]}),T&&(0,q.jsxs)(`div`,{className:`rounded-lg border border-accent-warning/30 bg-accent-warning/10 p-4 flex items-center justify-between`,children:[(0,q.jsxs)(`p`,{className:`text-sm text-accent-warning`,children:[`Failed to load: `,T]}),(0,q.jsxs)(`button`,{onClick:()=>N(),className:`flex items-center gap-1.5 h-7 px-3 rounded-md text-xs text-accent-warning border border-accent-warning/30 hover:bg-accent-warning/10`,children:[(0,q.jsx)(n,{className:`w-3 h-3`}),`Retry`]})]}),(0,q.jsx)(Ne,{data:x,loading:C}),(0,q.jsx)(ze,{data:x,loading:C}),(0,q.jsx)(vt,{data:x,loading:C}),(0,q.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-4`,children:[(0,q.jsx)(Ct,{data:x,loading:C}),(0,q.jsx)(wt,{data:x,loading:C,onSelectModel:e=>b(t=>({...t,model:[e]})),activeModel:y.model?.[0]})]}),(0,q.jsx)(Et,{data:x,loading:C,onSelectPoint:e=>{O(e=>({...e})),b(t=>({...t,ticketId:e.ticketId??void 0}))}}),(0,q.jsx)(Dt,{data:x,loading:C,onSelectTicket:e=>b(t=>({...t,ticketId:e??void 0}))}),(0,q.jsx)(Nt,{rows:k?.rows??[],loading:C&&!k,truncated:k?.truncated??!1,totalAvailable:k?.totalAvailable??0,tableFilters:D,onTableFiltersChange:O})]})}export{It as default};
|