@av-pi-studio/web-client 0.0.39 → 0.0.41
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/dist/.tsbuildinfo +1 -1
- package/dist/web/assets/{BinaryFallbackViewer-Cpu5Tg1C.js → BinaryFallbackViewer-Cb-P_8V-.js} +2 -2
- package/dist/web/assets/{BinaryFallbackViewer-Cpu5Tg1C.js.map → BinaryFallbackViewer-Cb-P_8V-.js.map} +1 -1
- package/dist/web/assets/{ChatPanel-BqI2xnxv.js → ChatPanel-D_3cLBoK.js} +2 -2
- package/dist/web/assets/ChatPanel-D_3cLBoK.js.map +1 -0
- package/dist/web/assets/{CodeView-B18owi8N.js → CodeView-B1cJEve4.js} +2 -2
- package/dist/web/assets/{CodeView-B18owi8N.js.map → CodeView-B1cJEve4.js.map} +1 -1
- package/dist/web/assets/{FilePanel-BBfL4iba.js → FilePanel-YoyZJ2v2.js} +3 -3
- package/dist/web/assets/{FilePanel-BBfL4iba.js.map → FilePanel-YoyZJ2v2.js.map} +1 -1
- package/dist/web/assets/{ImageViewer-KAEt1ZI8.js → ImageViewer-BvKE7WrT.js} +2 -2
- package/dist/web/assets/{ImageViewer-KAEt1ZI8.js.map → ImageViewer-BvKE7WrT.js.map} +1 -1
- package/dist/web/assets/{MarkdownFileViewer-Cb8Cm1VS.js → MarkdownFileViewer-Ct7fWGmR.js} +2 -2
- package/dist/web/assets/{MarkdownFileViewer-Cb8Cm1VS.js.map → MarkdownFileViewer-Ct7fWGmR.js.map} +1 -1
- package/dist/web/assets/{TerminalPanel-DyLLAPYP.js → TerminalPanel-rKZq5rWo.js} +2 -2
- package/dist/web/assets/{TerminalPanel-DyLLAPYP.js.map → TerminalPanel-rKZq5rWo.js.map} +1 -1
- package/dist/web/assets/{TextViewer-C4U4WLH6.js → TextViewer-BsdUzTN-.js} +2 -2
- package/dist/web/assets/{TextViewer-C4U4WLH6.js.map → TextViewer-BsdUzTN-.js.map} +1 -1
- package/dist/web/assets/{VideoViewer-tThxC8b-.js → VideoViewer-BoA5BwxX.js} +2 -2
- package/dist/web/assets/{VideoViewer-tThxC8b-.js.map → VideoViewer-BoA5BwxX.js.map} +1 -1
- package/dist/web/assets/index-BTP_UxAo.js +3 -0
- package/dist/web/assets/index-BTP_UxAo.js.map +1 -0
- package/dist/web/assets/index-EefWgf31.css +1 -0
- package/dist/web/assets/{use-file-download-BPiZ1x6n.js → use-file-download-CwyNTuhL.js} +2 -2
- package/dist/web/assets/{use-file-download-BPiZ1x6n.js.map → use-file-download-CwyNTuhL.js.map} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/ChatPanel-BqI2xnxv.js.map +0 -1
- package/dist/web/assets/index-BFWpAuBZ.js +0 -3
- package/dist/web/assets/index-BFWpAuBZ.js.map +0 -1
- package/dist/web/assets/index-BMbFIm_9.css +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as d,j as r}from"./vendor-react-BoIQBqDW.js";import{S as c,B as a}from"./index-
|
|
2
|
-
//# sourceMappingURL=MarkdownFileViewer-
|
|
1
|
+
import{r as d,j as r}from"./vendor-react-BoIQBqDW.js";import{S as c,B as a}from"./index-BTP_UxAo.js";import{u as m,C as p}from"./CodeView-B1cJEve4.js";import{M as l}from"./markdown-D9FuaV1m.js";import{p as n}from"./FilePanel-YoyZJ2v2.js";import"./vendor-query-AtKBh_Yt.js";import"./vendor--os7hw7d.js";import"./vendor-markdown-B8HSIhaA.js";import"./vendor-highlight-DCzuSv8g.js";import"./vendor-icons-CX25WOn8.js";import"./vendor-overlays-UwLNGk04.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-DlVCPvLc.js";const x="_wrap_khhx0_1",u="_toolbar_khhx0_6",h="_rendered_khhx0_17",o={wrap:x,toolbar:u,rendered:h};function M({path:s}){const e=m(s),[t,i]=d.useState("preview");return e.isLoading?r.jsxs("div",{className:n.emptyState,children:[r.jsx(c,{size:"sm"})," Loading..."]}):e.isError?r.jsxs("div",{className:n.emptyState,children:["Error: ",e.error instanceof Error?e.error.message:"unknown error"]}):e.data?r.jsxs("div",{className:o.wrap,children:[r.jsxs("div",{className:o.toolbar,children:[r.jsx(a,{size:"xs",variant:t==="preview"?"default":"ghost",onClick:()=>i("preview"),children:"Preview"}),r.jsx(a,{size:"xs",variant:t==="source"?"default":"ghost",onClick:()=>i("source"),children:"Source"})]}),t==="preview"?r.jsx("div",{className:o.rendered,children:r.jsx(l,{text:e.data.content})}):r.jsx(p,{path:s,content:e.data.content})]}):null}export{M as MarkdownFileViewer};
|
|
2
|
+
//# sourceMappingURL=MarkdownFileViewer-Ct7fWGmR.js.map
|
package/dist/web/assets/{MarkdownFileViewer-Cb8Cm1VS.js.map → MarkdownFileViewer-Ct7fWGmR.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkdownFileViewer-
|
|
1
|
+
{"version":3,"file":"MarkdownFileViewer-Ct7fWGmR.js","sources":["../../../src/features/files/MarkdownFileViewer.tsx"],"sourcesContent":["/**\n * MarkdownFileViewer — renders a `.md`/`.mdx` file's content through the app's sanitized\n * Markdown renderer (`timeline/markdown.tsx`, react-markdown + remark-gfm — no\n * `dangerouslySetInnerHTML` of user content), with a Preview/Source toggle since raw markdown is\n * sometimes what you actually want to read (POC_TO_APP_PLAN_UI.md §4.5 follow-up: modular file\n * preview).\n */\n\nimport { useState } from \"react\";\nimport { Button } from \"@pi-studio-ui/components/primitives/Button.js\";\nimport { Spinner } from \"@pi-studio-ui/components/primitives/Spinner.js\";\nimport { useFileRead } from \"@pi-studio-ui/hooks/use-file-read.js\";\nimport { Markdown } from \"@pi-studio-ui/timeline/markdown.js\";\nimport { CodeView } from \"./CodeView.js\";\nimport type { ViewerProps } from \"./viewer-registry.js\";\nimport panelStyles from \"./FilePanel.module.css\";\nimport styles from \"./MarkdownFileViewer.module.css\";\n\ntype Mode = \"preview\" | \"source\";\n\nexport function MarkdownFileViewer({ path }: ViewerProps) {\n const query = useFileRead(path);\n const [mode, setMode] = useState<Mode>(\"preview\");\n\n if (query.isLoading) {\n return (\n <div className={panelStyles.emptyState}>\n <Spinner size=\"sm\" /> Loading...\n </div>\n );\n }\n if (query.isError) {\n return (\n <div className={panelStyles.emptyState}>\n Error: {query.error instanceof Error ? query.error.message : \"unknown error\"}\n </div>\n );\n }\n if (!query.data) return null;\n\n return (\n <div className={styles.wrap}>\n <div className={styles.toolbar}>\n <Button size=\"xs\" variant={mode === \"preview\" ? \"default\" : \"ghost\"} onClick={() => setMode(\"preview\")}>\n Preview\n </Button>\n <Button size=\"xs\" variant={mode === \"source\" ? \"default\" : \"ghost\"} onClick={() => setMode(\"source\")}>\n Source\n </Button>\n </div>\n {mode === \"preview\" ? (\n <div className={styles.rendered}>\n <Markdown text={query.data.content} />\n </div>\n ) : (\n <CodeView path={path} content={query.data.content} />\n )}\n </div>\n );\n}\n"],"names":["MarkdownFileViewer","path","query","useFileRead","mode","setMode","useState","jsxs","panelStyles","jsx","Spinner","styles","Button","Markdown","CodeView"],"mappings":"wmBAoBO,SAASA,EAAmB,CAAE,KAAAC,GAAqB,CACxD,MAAMC,EAAQC,EAAYF,CAAI,EACxB,CAACG,EAAMC,CAAO,EAAIC,EAAAA,SAAe,SAAS,EAEhD,OAAIJ,EAAM,UAENK,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAY,WAC1B,SAAA,CAAAC,EAAAA,IAACC,EAAA,CAAQ,KAAK,IAAA,CAAK,EAAE,aAAA,EACvB,EAGAR,EAAM,QAENK,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAY,WAAY,SAAA,CAAA,UAC9BN,EAAM,iBAAiB,MAAQA,EAAM,MAAM,QAAU,eAAA,EAC/D,EAGCA,EAAM,KAGTK,EAAAA,KAAC,MAAA,CAAI,UAAWI,EAAO,KACrB,SAAA,CAAAJ,EAAAA,KAAC,MAAA,CAAI,UAAWI,EAAO,QACrB,SAAA,CAAAF,EAAAA,IAACG,EAAA,CAAO,KAAK,KAAK,QAASR,IAAS,UAAY,UAAY,QAAS,QAAS,IAAMC,EAAQ,SAAS,EAAG,SAAA,UAExG,EACAI,EAAAA,IAACG,EAAA,CAAO,KAAK,KAAK,QAASR,IAAS,SAAW,UAAY,QAAS,QAAS,IAAMC,EAAQ,QAAQ,EAAG,SAAA,QAAA,CAEtG,CAAA,EACF,EACCD,IAAS,UACRK,MAAC,MAAA,CAAI,UAAWE,EAAO,SACrB,eAACE,EAAA,CAAS,KAAMX,EAAM,KAAK,OAAA,CAAS,EACtC,EAEAO,EAAAA,IAACK,GAAS,KAAAb,EAAY,QAASC,EAAM,KAAK,OAAA,CAAS,CAAA,EAEvD,EAnBsB,IAqB1B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var A=Object.defineProperty;var I=(n,e,t)=>e in n?A(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var g=(n,e,t)=>I(n,typeof e!="symbol"?e+"":e,t);import{r as a,j as l}from"./vendor-react-BoIQBqDW.js";import{x as B,a as F}from"./vendor-terminal-BhzX2_ts.js";import{b as E,a as N,c as T,S as D}from"./index-
|
|
2
|
-
//# sourceMappingURL=TerminalPanel-
|
|
1
|
+
var A=Object.defineProperty;var I=(n,e,t)=>e in n?A(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var g=(n,e,t)=>I(n,typeof e!="symbol"?e+"":e,t);import{r as a,j as l}from"./vendor-react-BoIQBqDW.js";import{x as B,a as F}from"./vendor-terminal-BhzX2_ts.js";import{b as E,a as N,c as T,S as D}from"./index-BTP_UxAo.js";import"./vendor--os7hw7d.js";import"./vendor-query-AtKBh_Yt.js";import"./vendor-icons-CX25WOn8.js";import"./vendor-overlays-UwLNGk04.js";import"./vendor-dnd-D9kA7FgH.js";import"./vendor-highlight-DCzuSv8g.js";import"./vendor-markdown-B8HSIhaA.js";class O{constructor(e){g(this,"subscribers",new Map);g(this,"detach",null);this.daemon=e}start(){this.detach||(this.detach=this.daemon.onTerminalFrame(e=>this.dispatch(e)))}stop(){var e;(e=this.detach)==null||e.call(this),this.detach=null}subscribeSlot(e,t){return this.subscribers.set(e,t),()=>{this.subscribers.get(e)===t&&this.subscribers.delete(e)}}hasSlot(e){return this.subscribers.has(e)}sendInput(e,t){this.daemon.sendBinary(E({opcode:"Input",slot:e,data:t}))}sendResize(e,t,m){this.daemon.sendBinary(E({opcode:"Resize",slot:e,rows:t,cols:m}))}dispatch(e){var m,p,u;const t=this.subscribers.get(e.slot);if(t)switch(e.opcode){case"Output":(m=t.onOutput)==null||m.call(t,e.data);return;case"Snapshot":(p=t.onSnapshot)==null||p.call(t,e.data);return;case"Restore":(u=t.onRestore)==null||u.call(t,e.data);return;default:return}}}const C="_wrap_b74ul_1",P="_terminal_b74ul_11",W="_status_b74ul_18",f={wrap:C,terminal:P,status:W},q=new WeakMap;function G(n){let e=q.get(n);return e||(e=new O(n),e.start(),q.set(n,e)),e}const H={background:"#181b1a",foreground:"#fafafa",cursor:"#a2b4d7",cursorAccent:"#181b1a",selectionBackground:"rgba(255,255,255,0.18)",black:"#18181b",red:"#ef4444",green:"#22c55e",yellow:"#f59e0b",blue:"#3b82f6",magenta:"#a855f7",cyan:"#14b8a6",white:"#d4d4d8",brightBlack:"#52525b",brightRed:"#f87171",brightGreen:"#4ade80",brightYellow:"#fbbf24",brightBlue:"#60a5fa",brightMagenta:"#c084fc",brightCyan:"#2dd4bf",brightWhite:"#fafafa"};function te({tab:n}){const e=n.data,t=N(r=>r.client),p=T(r=>r.activeTabId)===n.id,u=a.useRef(null),w=a.useRef(null),h=a.useRef(null),b=a.useRef(e.slot),S=a.useRef(t);S.current=t;const[c,k]=a.useState(e.slot),[_,v]=a.useState(null),d=a.useRef(!1),R=a.useRef(!1);return a.useEffect(()=>{if(d.current=!0,!t||b.current!==null||R.current)return()=>{d.current=!1};R.current=!0;const r=e.cwd||"~";return t.connection.request("create_terminal_request",{workspaceId:"",cwd:r}).then(s=>{const i=s.terminal.slot;if(!d.current){t.connection.request("kill_terminal_request",{slot:i}).catch(()=>{});return}b.current=i,k(i),T.getState().updateData(n.id,{slot:i})}).catch(s=>{d.current&&v(s instanceof Error?s.message:String(s))}).finally(()=>{R.current=!1}),()=>{d.current=!1}},[t,n.id]),a.useEffect(()=>()=>{const r=b.current;r!==null&&setTimeout(()=>{var s;d.current||(s=S.current)==null||s.connection.request("kill_terminal_request",{slot:r}).catch(()=>{})},0)},[]),a.useEffect(()=>{if(!t||c===null||!u.current)return;const r=new B.Terminal({cursorBlink:!0,fontFamily:"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",fontSize:13,scrollback:5e3,theme:H,allowProposedApi:!0}),s=new F.FitAddon;r.loadAddon(s),r.open(u.current),s.fit(),w.current=r,h.current=s;const i=G(t.connection),j=i.subscribeSlot(c,{onOutput:o=>r.write(o),onSnapshot:o=>{r.clear(),r.write(o)},onRestore:o=>r.write(o)});t.connection.request("subscribe_terminal_request",{slot:c}).catch(o=>{v(o instanceof Error?o.message:String(o))});const y=r.onData(o=>{i.sendInput(c,new TextEncoder().encode(o))}),z=r.onResize(({cols:o,rows:M})=>{i.sendResize(c,M,o)}),x=new ResizeObserver(()=>{s.fit()});return x.observe(u.current),()=>{x.disconnect(),y.dispose(),z.dispose(),j(),t.connection.request("unsubscribe_terminal_request",{slot:c}).catch(()=>{}),r.dispose(),w.current=null,h.current=null}},[t,c]),a.useEffect(()=>{var r;p&&((r=h.current)==null||r.fit())},[p]),_?l.jsx("div",{className:f.wrap,children:l.jsxs("div",{className:f.status,children:["Terminal error: ",_]})}):c===null?l.jsx("div",{className:f.wrap,children:l.jsxs("div",{className:f.status,children:[l.jsx(D,{size:"sm"})," Starting terminal…"]})}):l.jsx("div",{className:f.wrap,children:l.jsx("div",{ref:u,className:f.terminal})})}export{te as TerminalPanel};
|
|
2
|
+
//# sourceMappingURL=TerminalPanel-rKZq5rWo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TerminalPanel-DyLLAPYP.js","sources":["../../../../client/src/terminal-stream-router.ts","../../../src/features/terminal/TerminalPanel.tsx"],"sourcesContent":["import { encodeTerminalFrame, type TerminalFrame } from \"@av-pi-studio/protocol\";\n\nimport type { DaemonClient } from \"./daemon-client.js\";\n\n/**\n * Client-side demux of binary terminal frames to per-slot subscribers, plus outbound input/resize\n * encoding (architecture/client-app-runtime.md § Router; features/terminals.md § Binary stream\n * protocol).\n *\n * Inbound `Output`/`Snapshot`/`Restore` frames are dispatched to the subscriber registered for that\n * `slot`. Outbound `Input`/`Resize` are encoded with the right opcode + slot and sent on the data\n * path.\n */\n\nexport interface TerminalSlotSubscriber {\n /** Live terminal output bytes. */\n onOutput?: (data: Uint8Array) => void;\n /** Full-screen snapshot bytes (sent on (re)subscribe). */\n onSnapshot?: (data: Uint8Array) => void;\n /** Restore snapshot bytes (reflowable/mode-gated). */\n onRestore?: (data: Uint8Array) => void;\n}\n\nexport class TerminalStreamRouter {\n private readonly subscribers = new Map<number, TerminalSlotSubscriber>();\n private detach: (() => void) | null = null;\n\n constructor(private readonly daemon: DaemonClient) {}\n\n /** Begin routing inbound terminal frames. Idempotent. */\n start(): void {\n if (this.detach) return;\n this.detach = this.daemon.onTerminalFrame((frame) => this.dispatch(frame));\n }\n\n /** Stop routing inbound frames (subscribers retained). */\n stop(): void {\n this.detach?.();\n this.detach = null;\n }\n\n /** Register (or replace) the subscriber for a slot. Returns an unsubscribe fn. */\n subscribeSlot(slot: number, subscriber: TerminalSlotSubscriber): () => void {\n this.subscribers.set(slot, subscriber);\n return () => {\n if (this.subscribers.get(slot) === subscriber) this.subscribers.delete(slot);\n };\n }\n\n /** True iff a subscriber is registered for the slot. */\n hasSlot(slot: number): boolean {\n return this.subscribers.has(slot);\n }\n\n // ─── Outbound ─────────────────────────────────────────────────────────────\n\n /** Send raw input bytes to a slot's PTY (opcode `Input = 0x02`). */\n sendInput(slot: number, data: Uint8Array): void {\n this.daemon.sendBinary(encodeTerminalFrame({ opcode: \"Input\", slot, data }));\n }\n\n /** Send a resize (opcode `Resize = 0x03`, JSON `{ rows, cols }` payload). */\n sendResize(slot: number, rows: number, cols: number): void {\n this.daemon.sendBinary(encodeTerminalFrame({ opcode: \"Resize\", slot, rows, cols }));\n }\n\n // ─── Inbound dispatch ───────────────────────────────────────────────────────\n\n private dispatch(frame: TerminalFrame): void {\n const subscriber = this.subscribers.get(frame.slot);\n if (!subscriber) return; // no subscriber for this slot — drop\n switch (frame.opcode) {\n case \"Output\":\n subscriber.onOutput?.(frame.data);\n return;\n case \"Snapshot\":\n subscriber.onSnapshot?.(frame.data);\n return;\n case \"Restore\":\n subscriber.onRestore?.(frame.data);\n return;\n default:\n // Input/Resize are outbound-only; ignore if echoed back.\n return;\n }\n }\n}\n","/**\n * TerminalPanel — @xterm/xterm mount + binary-frame streaming via `TerminalStreamRouter`\n * (POC `initTerminalPanel`, POC_TO_APP_PLAN_UI.md §4.6). Strict upgrade over the POC's 800ms\n * `capture_terminal_request` poll: the daemon pushes `Output`/`Snapshot`/`Restore` binary frames\n * directly over the one shared `DaemonClient` connection, demuxed by slot.\n *\n * Slot lifecycle: created once via `create_terminal_request`, then persisted onto the tab's\n * `TerminalTabData.slot` via `useTabStore.getState().updateData` so switching away and back to\n * this tab (kept mounted-but-hidden by `TabPanelHost`) never recreates the terminal. `TabPanelHost`\n * only unmounts a tab's panel when the tab leaves the store's `tabs[]` (i.e. real tab close, never\n * a tab switch) — this component's true-unmount effect below relies on exactly that invariant to\n * send `kill_terminal_request`, terminating the PTY server-side instead of leaking it forever.\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Terminal } from \"@xterm/xterm\";\nimport { FitAddon } from \"@xterm/addon-fit\";\nimport \"@xterm/xterm/css/xterm.css\";\nimport type { DaemonClient } from \"@av-pi-studio/client\";\nimport { TerminalStreamRouter } from \"@av-pi-studio/client\";\nimport { useConnectionStore } from \"@pi-studio-ui/lib/connection/connection-store.js\";\nimport { useTabStore } from \"@pi-studio-ui/stores/tab-store.js\";\nimport type { Tab, TerminalTabData } from \"@pi-studio-ui/stores/tab-store.js\";\nimport { Spinner } from \"@pi-studio-ui/components/primitives/Spinner.js\";\nimport styles from \"./TerminalPanel.module.css\";\n\nexport interface TerminalPanelProps {\n tab: Tab;\n}\n\ninterface CreateTerminalResponse {\n terminal: { slot: number };\n}\n\n// One TerminalStreamRouter per daemon connection — multiple terminal tabs share it rather than\n// each opening its own frame demuxer over the same socket.\nconst routerByDaemon = new WeakMap<DaemonClient, TerminalStreamRouter>();\n\nfunction routerFor(daemon: DaemonClient): TerminalStreamRouter {\n let router = routerByDaemon.get(daemon);\n if (!router) {\n router = new TerminalStreamRouter(daemon);\n router.start();\n routerByDaemon.set(daemon, router);\n }\n return router;\n}\n\n/** Dark palette matching the app's github-dark-ish default theme (theme/variants.ts \"dark\"). */\nconst TERMINAL_THEME = {\n background: \"#181b1a\",\n foreground: \"#fafafa\",\n cursor: \"#a2b4d7\",\n cursorAccent: \"#181b1a\",\n selectionBackground: \"rgba(255,255,255,0.18)\",\n black: \"#18181b\",\n red: \"#ef4444\",\n green: \"#22c55e\",\n yellow: \"#f59e0b\",\n blue: \"#3b82f6\",\n magenta: \"#a855f7\",\n cyan: \"#14b8a6\",\n white: \"#d4d4d8\",\n brightBlack: \"#52525b\",\n brightRed: \"#f87171\",\n brightGreen: \"#4ade80\",\n brightYellow: \"#fbbf24\",\n brightBlue: \"#60a5fa\",\n brightMagenta: \"#c084fc\",\n brightCyan: \"#2dd4bf\",\n brightWhite: \"#fafafa\",\n};\n\nexport function TerminalPanel({ tab }: TerminalPanelProps) {\n const data = tab.data as TerminalTabData;\n const client = useConnectionStore((s) => s.client);\n const activeTabId = useTabStore((s) => s.activeTabId);\n const isActive = activeTabId === tab.id;\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const terminalRef = useRef<Terminal | null>(null);\n const fitAddonRef = useRef<FitAddon | null>(null);\n const slotRef = useRef<number | null>(data.slot);\n // Mirrors `use-checkout-status.ts`'s convention: kept in sync every render so the unmount-only\n // kill effect below always sends the CURRENT client, never a stale mount-time closure (e.g.\n // after a reconnect swaps in a new `PiStudioClient` instance).\n const clientRef = useRef(client);\n clientRef.current = client;\n\n const [slot, setSlot] = useState<number | null>(data.slot);\n const [error, setError] = useState<string | null>(null);\n\n // ─── Slot lifecycle: create once, persist onto the tab so re-opening reuses it ─────────────\n // React StrictMode double-invokes effects in dev: mount → cleanup → remount, synchronously,\n // on the SAME component instance (refs/state persist across all three phases — this is not\n // three separate mounts). Two things must hold across that: (1) the request fires exactly\n // once, and (2) whether to APPLY the eventual response is decided by whether the component is\n // mounted at RESPONSE time, not by a flag captured at REQUEST time.\n //\n // `requestStartedRef` gives (1): set the instant the request fires and never reset, so the\n // phantom-mount's cleanup-then-remount sees it's already in flight and never fires a second\n // `create_terminal_request` (this is what previously spawned two real PTYs from one Ctrl+T).\n //\n // `isMountedRef` gives (2): flipped true at the START of every effect invocation and false in\n // every cleanup, so it always reflects the LATEST phase. StrictMode's remount happens\n // synchronously, before the request's promise can possibly settle, so by response time\n // `isMountedRef.current` is back to `true` for a StrictMode phantom (correctly applies the\n // slot) — but stays `false` for a genuine fast real close (correctly kills the orphaned PTY\n // instead of leaking it or, as the previous buggy version did, killing a terminal that was\n // never actually torn down).\n const isMountedRef = useRef(false);\n const requestStartedRef = useRef(false);\n useEffect(() => {\n isMountedRef.current = true;\n if (!client || slotRef.current !== null || requestStartedRef.current) {\n return () => {\n isMountedRef.current = false;\n };\n }\n requestStartedRef.current = true;\n\n const cwd = data.cwd || \"~\";\n\n void client.connection\n .request<CreateTerminalResponse>(\"create_terminal_request\", { workspaceId: \"\", cwd })\n .then((res) => {\n const created = res.terminal.slot;\n if (!isMountedRef.current) {\n // A real close happened with no remount after it — kill the PTY that finished\n // spawning after the tab was already gone, instead of leaking it.\n void client.connection.request(\"kill_terminal_request\", { slot: created }).catch(() => {});\n return;\n }\n slotRef.current = created;\n setSlot(created);\n useTabStore.getState().updateData(tab.id, { slot: created });\n })\n .catch((err: unknown) => {\n if (!isMountedRef.current) return;\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => {\n // Reset only after the promise settles — by then StrictMode's synchronous\n // mount→cleanup→remount window has long passed, so this can never reopen the\n // double-fire race. It DOES allow a legitimate retry (e.g. `client` changed because of\n // a reconnect after the first attempt failed) instead of leaving the tab stuck forever.\n requestStartedRef.current = false;\n });\n\n return () => {\n isMountedRef.current = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, tab.id]);\n\n // ─── True unmount only: kill the PTY server-side ───────────────────────────────────────────\n // Runs its cleanup exactly once, when this component itself unmounts (real tab close, per\n // `TabPanelHost`'s \"hidden but alive\" model — a tab switch never unmounts). An empty deps array\n // means React never re-runs the effect body itself; only the cleanup fires, and only on\n // unmount, so this never races the slot-creation effect above or double-kills on a client\n // change. Without this, every closed terminal tab leaked its PTY process forever.\n //\n // For a REATTACH (this tab opened with a non-null `data.slot` from the very first render —\n // `use-terminal-restore.ts`, or the create-effect above once it has resolved) `slotRef.current`\n // is non-null from the start, so StrictMode's synchronous mount→cleanup→remount phantom cycle\n // would fire this cleanup and kill the PTY immediately on mount — unlike a freshly created\n // terminal, where `slotRef.current` is still `null` during that same phantom window (see the\n // create-effect's own comment) and so never hits this path. Deferred via `setTimeout`, exactly\n // like the create-effect's response handler: by the time it fires, StrictMode's remount has\n // already flipped `isMountedRef` back to `true` if this was a phantom unmount, so the kill is\n // skipped; a genuine close never remounts, so `isMountedRef` stays `false` and the kill proceeds.\n useEffect(() => {\n return () => {\n const currentSlot = slotRef.current;\n if (currentSlot === null) return;\n setTimeout(() => {\n if (isMountedRef.current) return; // StrictMode remounted synchronously — not a real close\n void clientRef.current?.connection\n .request(\"kill_terminal_request\", { slot: currentSlot })\n .catch(() => {});\n }, 0);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ─── xterm mount (once slot + container are ready) ─────────────────────────────────────────\n useEffect(() => {\n if (!client || slot === null || !containerRef.current) return;\n\n const terminal = new Terminal({\n cursorBlink: true,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',\n fontSize: 13,\n scrollback: 5000,\n theme: TERMINAL_THEME,\n allowProposedApi: true,\n });\n const fitAddon = new FitAddon();\n terminal.loadAddon(fitAddon);\n terminal.open(containerRef.current);\n fitAddon.fit();\n\n terminalRef.current = terminal;\n fitAddonRef.current = fitAddon;\n\n const router = routerFor(client.connection);\n const unsubscribeSlot = router.subscribeSlot(slot, {\n onOutput: (chunk) => terminal.write(chunk),\n onSnapshot: (chunk) => {\n terminal.clear();\n terminal.write(chunk);\n },\n onRestore: (chunk) => terminal.write(chunk),\n });\n\n void client.connection.request(\"subscribe_terminal_request\", { slot }).catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n });\n\n const dataDisposable = terminal.onData((chunk) => {\n router.sendInput(slot, new TextEncoder().encode(chunk));\n });\n const resizeDisposable = terminal.onResize(({ cols, rows }) => {\n router.sendResize(slot, rows, cols);\n });\n\n const resizeObserver = new ResizeObserver(() => {\n fitAddon.fit();\n });\n resizeObserver.observe(containerRef.current);\n\n return () => {\n resizeObserver.disconnect();\n dataDisposable.dispose();\n resizeDisposable.dispose();\n unsubscribeSlot();\n void client.connection.request(\"unsubscribe_terminal_request\", { slot }).catch(() => {});\n terminal.dispose();\n terminalRef.current = null;\n fitAddonRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, slot]);\n\n // ─── Re-fit whenever this tab becomes the active (visible) one ────────────────────────────\n useEffect(() => {\n if (!isActive) return;\n fitAddonRef.current?.fit();\n }, [isActive]);\n\n if (error) {\n return (\n <div className={styles.wrap}>\n <div className={styles.status}>Terminal error: {error}</div>\n </div>\n );\n }\n\n if (slot === null) {\n return (\n <div className={styles.wrap}>\n <div className={styles.status}>\n <Spinner size=\"sm\" /> Starting terminal…\n </div>\n </div>\n );\n }\n\n return (\n <div className={styles.wrap}>\n <div ref={containerRef} className={styles.terminal} />\n </div>\n );\n}\n"],"names":["TerminalStreamRouter","daemon","__publicField","frame","_a","slot","subscriber","data","encodeTerminalFrame","rows","cols","_b","_c","routerByDaemon","routerFor","router","TERMINAL_THEME","TerminalPanel","tab","client","useConnectionStore","s","isActive","useTabStore","containerRef","useRef","terminalRef","fitAddonRef","slotRef","clientRef","setSlot","useState","error","setError","isMountedRef","requestStartedRef","useEffect","cwd","res","created","err","currentSlot","terminal","Terminal","fitAddon","FitAddon","unsubscribeSlot","chunk","dataDisposable","resizeDisposable","resizeObserver","jsx","styles","jsxs","Spinner"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TerminalPanel-rKZq5rWo.js","sources":["../../../../client/src/terminal-stream-router.ts","../../../src/features/terminal/TerminalPanel.tsx"],"sourcesContent":["import { encodeTerminalFrame, type TerminalFrame } from \"@av-pi-studio/protocol\";\n\nimport type { DaemonClient } from \"./daemon-client.js\";\n\n/**\n * Client-side demux of binary terminal frames to per-slot subscribers, plus outbound input/resize\n * encoding (architecture/client-app-runtime.md § Router; features/terminals.md § Binary stream\n * protocol).\n *\n * Inbound `Output`/`Snapshot`/`Restore` frames are dispatched to the subscriber registered for that\n * `slot`. Outbound `Input`/`Resize` are encoded with the right opcode + slot and sent on the data\n * path.\n */\n\nexport interface TerminalSlotSubscriber {\n /** Live terminal output bytes. */\n onOutput?: (data: Uint8Array) => void;\n /** Full-screen snapshot bytes (sent on (re)subscribe). */\n onSnapshot?: (data: Uint8Array) => void;\n /** Restore snapshot bytes (reflowable/mode-gated). */\n onRestore?: (data: Uint8Array) => void;\n}\n\nexport class TerminalStreamRouter {\n private readonly subscribers = new Map<number, TerminalSlotSubscriber>();\n private detach: (() => void) | null = null;\n\n constructor(private readonly daemon: DaemonClient) {}\n\n /** Begin routing inbound terminal frames. Idempotent. */\n start(): void {\n if (this.detach) return;\n this.detach = this.daemon.onTerminalFrame((frame) => this.dispatch(frame));\n }\n\n /** Stop routing inbound frames (subscribers retained). */\n stop(): void {\n this.detach?.();\n this.detach = null;\n }\n\n /** Register (or replace) the subscriber for a slot. Returns an unsubscribe fn. */\n subscribeSlot(slot: number, subscriber: TerminalSlotSubscriber): () => void {\n this.subscribers.set(slot, subscriber);\n return () => {\n if (this.subscribers.get(slot) === subscriber) this.subscribers.delete(slot);\n };\n }\n\n /** True iff a subscriber is registered for the slot. */\n hasSlot(slot: number): boolean {\n return this.subscribers.has(slot);\n }\n\n // ─── Outbound ─────────────────────────────────────────────────────────────\n\n /** Send raw input bytes to a slot's PTY (opcode `Input = 0x02`). */\n sendInput(slot: number, data: Uint8Array): void {\n this.daemon.sendBinary(encodeTerminalFrame({ opcode: \"Input\", slot, data }));\n }\n\n /** Send a resize (opcode `Resize = 0x03`, JSON `{ rows, cols }` payload). */\n sendResize(slot: number, rows: number, cols: number): void {\n this.daemon.sendBinary(encodeTerminalFrame({ opcode: \"Resize\", slot, rows, cols }));\n }\n\n // ─── Inbound dispatch ───────────────────────────────────────────────────────\n\n private dispatch(frame: TerminalFrame): void {\n const subscriber = this.subscribers.get(frame.slot);\n if (!subscriber) return; // no subscriber for this slot — drop\n switch (frame.opcode) {\n case \"Output\":\n subscriber.onOutput?.(frame.data);\n return;\n case \"Snapshot\":\n subscriber.onSnapshot?.(frame.data);\n return;\n case \"Restore\":\n subscriber.onRestore?.(frame.data);\n return;\n default:\n // Input/Resize are outbound-only; ignore if echoed back.\n return;\n }\n }\n}\n","/**\n * TerminalPanel — @xterm/xterm mount + binary-frame streaming via `TerminalStreamRouter`\n * (POC `initTerminalPanel`, POC_TO_APP_PLAN_UI.md §4.6). Strict upgrade over the POC's 800ms\n * `capture_terminal_request` poll: the daemon pushes `Output`/`Snapshot`/`Restore` binary frames\n * directly over the one shared `DaemonClient` connection, demuxed by slot.\n *\n * Slot lifecycle: created once via `create_terminal_request`, then persisted onto the tab's\n * `TerminalTabData.slot` via `useTabStore.getState().updateData` so switching away and back to\n * this tab (kept mounted-but-hidden by `TabPanelHost`) never recreates the terminal. `TabPanelHost`\n * only unmounts a tab's panel when the tab leaves the store's `tabs[]` (i.e. real tab close, never\n * a tab switch) — this component's true-unmount effect below relies on exactly that invariant to\n * send `kill_terminal_request`, terminating the PTY server-side instead of leaking it forever.\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Terminal } from \"@xterm/xterm\";\nimport { FitAddon } from \"@xterm/addon-fit\";\nimport \"@xterm/xterm/css/xterm.css\";\nimport type { DaemonClient } from \"@av-pi-studio/client\";\nimport { TerminalStreamRouter } from \"@av-pi-studio/client\";\nimport { useConnectionStore } from \"@pi-studio-ui/lib/connection/connection-store.js\";\nimport { useTabStore } from \"@pi-studio-ui/stores/tab-store.js\";\nimport type { Tab, TerminalTabData } from \"@pi-studio-ui/stores/tab-store.js\";\nimport { Spinner } from \"@pi-studio-ui/components/primitives/Spinner.js\";\nimport styles from \"./TerminalPanel.module.css\";\n\nexport interface TerminalPanelProps {\n tab: Tab;\n}\n\ninterface CreateTerminalResponse {\n terminal: { slot: number };\n}\n\n// One TerminalStreamRouter per daemon connection — multiple terminal tabs share it rather than\n// each opening its own frame demuxer over the same socket.\nconst routerByDaemon = new WeakMap<DaemonClient, TerminalStreamRouter>();\n\nfunction routerFor(daemon: DaemonClient): TerminalStreamRouter {\n let router = routerByDaemon.get(daemon);\n if (!router) {\n router = new TerminalStreamRouter(daemon);\n router.start();\n routerByDaemon.set(daemon, router);\n }\n return router;\n}\n\n/** Dark palette matching the app's github-dark-ish default theme (theme/variants.ts \"dark\"). */\nconst TERMINAL_THEME = {\n background: \"#181b1a\",\n foreground: \"#fafafa\",\n cursor: \"#a2b4d7\",\n cursorAccent: \"#181b1a\",\n selectionBackground: \"rgba(255,255,255,0.18)\",\n black: \"#18181b\",\n red: \"#ef4444\",\n green: \"#22c55e\",\n yellow: \"#f59e0b\",\n blue: \"#3b82f6\",\n magenta: \"#a855f7\",\n cyan: \"#14b8a6\",\n white: \"#d4d4d8\",\n brightBlack: \"#52525b\",\n brightRed: \"#f87171\",\n brightGreen: \"#4ade80\",\n brightYellow: \"#fbbf24\",\n brightBlue: \"#60a5fa\",\n brightMagenta: \"#c084fc\",\n brightCyan: \"#2dd4bf\",\n brightWhite: \"#fafafa\",\n};\n\nexport function TerminalPanel({ tab }: TerminalPanelProps) {\n const data = tab.data as TerminalTabData;\n const client = useConnectionStore((s) => s.client);\n const activeTabId = useTabStore((s) => s.activeTabId);\n const isActive = activeTabId === tab.id;\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const terminalRef = useRef<Terminal | null>(null);\n const fitAddonRef = useRef<FitAddon | null>(null);\n const slotRef = useRef<number | null>(data.slot);\n // Mirrors `use-checkout-status.ts`'s convention: kept in sync every render so the unmount-only\n // kill effect below always sends the CURRENT client, never a stale mount-time closure (e.g.\n // after a reconnect swaps in a new `PiStudioClient` instance).\n const clientRef = useRef(client);\n clientRef.current = client;\n\n const [slot, setSlot] = useState<number | null>(data.slot);\n const [error, setError] = useState<string | null>(null);\n\n // ─── Slot lifecycle: create once, persist onto the tab so re-opening reuses it ─────────────\n // React StrictMode double-invokes effects in dev: mount → cleanup → remount, synchronously,\n // on the SAME component instance (refs/state persist across all three phases — this is not\n // three separate mounts). Two things must hold across that: (1) the request fires exactly\n // once, and (2) whether to APPLY the eventual response is decided by whether the component is\n // mounted at RESPONSE time, not by a flag captured at REQUEST time.\n //\n // `requestStartedRef` gives (1): set the instant the request fires and never reset, so the\n // phantom-mount's cleanup-then-remount sees it's already in flight and never fires a second\n // `create_terminal_request` (this is what previously spawned two real PTYs from one Ctrl+T).\n //\n // `isMountedRef` gives (2): flipped true at the START of every effect invocation and false in\n // every cleanup, so it always reflects the LATEST phase. StrictMode's remount happens\n // synchronously, before the request's promise can possibly settle, so by response time\n // `isMountedRef.current` is back to `true` for a StrictMode phantom (correctly applies the\n // slot) — but stays `false` for a genuine fast real close (correctly kills the orphaned PTY\n // instead of leaking it or, as the previous buggy version did, killing a terminal that was\n // never actually torn down).\n const isMountedRef = useRef(false);\n const requestStartedRef = useRef(false);\n useEffect(() => {\n isMountedRef.current = true;\n if (!client || slotRef.current !== null || requestStartedRef.current) {\n return () => {\n isMountedRef.current = false;\n };\n }\n requestStartedRef.current = true;\n\n const cwd = data.cwd || \"~\";\n\n void client.connection\n .request<CreateTerminalResponse>(\"create_terminal_request\", { workspaceId: \"\", cwd })\n .then((res) => {\n const created = res.terminal.slot;\n if (!isMountedRef.current) {\n // A real close happened with no remount after it — kill the PTY that finished\n // spawning after the tab was already gone, instead of leaking it.\n void client.connection.request(\"kill_terminal_request\", { slot: created }).catch(() => {});\n return;\n }\n slotRef.current = created;\n setSlot(created);\n useTabStore.getState().updateData(tab.id, { slot: created });\n })\n .catch((err: unknown) => {\n if (!isMountedRef.current) return;\n setError(err instanceof Error ? err.message : String(err));\n })\n .finally(() => {\n // Reset only after the promise settles — by then StrictMode's synchronous\n // mount→cleanup→remount window has long passed, so this can never reopen the\n // double-fire race. It DOES allow a legitimate retry (e.g. `client` changed because of\n // a reconnect after the first attempt failed) instead of leaving the tab stuck forever.\n requestStartedRef.current = false;\n });\n\n return () => {\n isMountedRef.current = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, tab.id]);\n\n // ─── True unmount only: kill the PTY server-side ───────────────────────────────────────────\n // Runs its cleanup exactly once, when this component itself unmounts (real tab close, per\n // `TabPanelHost`'s \"hidden but alive\" model — a tab switch never unmounts). An empty deps array\n // means React never re-runs the effect body itself; only the cleanup fires, and only on\n // unmount, so this never races the slot-creation effect above or double-kills on a client\n // change. Without this, every closed terminal tab leaked its PTY process forever.\n //\n // For a REATTACH (this tab opened with a non-null `data.slot` from the very first render —\n // `use-terminal-restore.ts`, or the create-effect above once it has resolved) `slotRef.current`\n // is non-null from the start, so StrictMode's synchronous mount→cleanup→remount phantom cycle\n // would fire this cleanup and kill the PTY immediately on mount — unlike a freshly created\n // terminal, where `slotRef.current` is still `null` during that same phantom window (see the\n // create-effect's own comment) and so never hits this path. Deferred via `setTimeout`, exactly\n // like the create-effect's response handler: by the time it fires, StrictMode's remount has\n // already flipped `isMountedRef` back to `true` if this was a phantom unmount, so the kill is\n // skipped; a genuine close never remounts, so `isMountedRef` stays `false` and the kill proceeds.\n useEffect(() => {\n return () => {\n const currentSlot = slotRef.current;\n if (currentSlot === null) return;\n setTimeout(() => {\n if (isMountedRef.current) return; // StrictMode remounted synchronously — not a real close\n void clientRef.current?.connection\n .request(\"kill_terminal_request\", { slot: currentSlot })\n .catch(() => {});\n }, 0);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ─── xterm mount (once slot + container are ready) ─────────────────────────────────────────\n useEffect(() => {\n if (!client || slot === null || !containerRef.current) return;\n\n const terminal = new Terminal({\n cursorBlink: true,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',\n fontSize: 13,\n scrollback: 5000,\n theme: TERMINAL_THEME,\n allowProposedApi: true,\n });\n const fitAddon = new FitAddon();\n terminal.loadAddon(fitAddon);\n terminal.open(containerRef.current);\n fitAddon.fit();\n\n terminalRef.current = terminal;\n fitAddonRef.current = fitAddon;\n\n const router = routerFor(client.connection);\n const unsubscribeSlot = router.subscribeSlot(slot, {\n onOutput: (chunk) => terminal.write(chunk),\n onSnapshot: (chunk) => {\n terminal.clear();\n terminal.write(chunk);\n },\n onRestore: (chunk) => terminal.write(chunk),\n });\n\n void client.connection.request(\"subscribe_terminal_request\", { slot }).catch((err: unknown) => {\n setError(err instanceof Error ? err.message : String(err));\n });\n\n const dataDisposable = terminal.onData((chunk) => {\n router.sendInput(slot, new TextEncoder().encode(chunk));\n });\n const resizeDisposable = terminal.onResize(({ cols, rows }) => {\n router.sendResize(slot, rows, cols);\n });\n\n const resizeObserver = new ResizeObserver(() => {\n fitAddon.fit();\n });\n resizeObserver.observe(containerRef.current);\n\n return () => {\n resizeObserver.disconnect();\n dataDisposable.dispose();\n resizeDisposable.dispose();\n unsubscribeSlot();\n void client.connection.request(\"unsubscribe_terminal_request\", { slot }).catch(() => {});\n terminal.dispose();\n terminalRef.current = null;\n fitAddonRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, slot]);\n\n // ─── Re-fit whenever this tab becomes the active (visible) one ────────────────────────────\n useEffect(() => {\n if (!isActive) return;\n fitAddonRef.current?.fit();\n }, [isActive]);\n\n if (error) {\n return (\n <div className={styles.wrap}>\n <div className={styles.status}>Terminal error: {error}</div>\n </div>\n );\n }\n\n if (slot === null) {\n return (\n <div className={styles.wrap}>\n <div className={styles.status}>\n <Spinner size=\"sm\" /> Starting terminal…\n </div>\n </div>\n );\n }\n\n return (\n <div className={styles.wrap}>\n <div ref={containerRef} className={styles.terminal} />\n </div>\n );\n}\n"],"names":["TerminalStreamRouter","daemon","__publicField","frame","_a","slot","subscriber","data","encodeTerminalFrame","rows","cols","_b","_c","routerByDaemon","routerFor","router","TERMINAL_THEME","TerminalPanel","tab","client","useConnectionStore","s","isActive","useTabStore","containerRef","useRef","terminalRef","fitAddonRef","slotRef","clientRef","setSlot","useState","error","setError","isMountedRef","requestStartedRef","useEffect","cwd","res","created","err","currentSlot","terminal","Terminal","fitAddon","FitAddon","unsubscribeSlot","chunk","dataDisposable","resizeDisposable","resizeObserver","jsx","styles","jsxs","Spinner"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e}from"./vendor-react-BoIQBqDW.js";import{S as i}from"./index-
|
|
2
|
-
//# sourceMappingURL=TextViewer-
|
|
1
|
+
import{j as e}from"./vendor-react-BoIQBqDW.js";import{S as i}from"./index-BTP_UxAo.js";import{u as s,C as n}from"./CodeView-B1cJEve4.js";import{p as o}from"./FilePanel-YoyZJ2v2.js";import"./vendor-query-AtKBh_Yt.js";import"./vendor--os7hw7d.js";import"./vendor-markdown-B8HSIhaA.js";import"./vendor-highlight-DCzuSv8g.js";import"./vendor-icons-CX25WOn8.js";import"./vendor-overlays-UwLNGk04.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-DlVCPvLc.js";function E({path:t}){const r=s(t);return r.isLoading?e.jsxs("div",{className:o.emptyState,children:[e.jsx(i,{size:"sm"})," Loading..."]}):r.isError?e.jsxs("div",{className:o.emptyState,children:["Error: ",r.error instanceof Error?r.error.message:"unknown error"]}):r.data?e.jsx(n,{path:t,content:r.data.content}):null}export{E as TextViewer};
|
|
2
|
+
//# sourceMappingURL=TextViewer-BsdUzTN-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextViewer-
|
|
1
|
+
{"version":3,"file":"TextViewer-BsdUzTN-.js","sources":["../../../src/features/files/TextViewer.tsx"],"sourcesContent":["/**\n * TextViewer — the default viewer for source/text files: fetches the UTF-8 preview via\n * `useFileRead` and renders it through `CodeView` (line gutter + Shiki highlighting). Registered\n * in `viewer-registry.ts` as the fallback for any file not claimed by a more specific viewer.\n */\n\nimport { Spinner } from \"@pi-studio-ui/components/primitives/Spinner.js\";\nimport { useFileRead } from \"@pi-studio-ui/hooks/use-file-read.js\";\nimport { CodeView } from \"./CodeView.js\";\nimport type { ViewerProps } from \"./viewer-registry.js\";\nimport styles from \"./FilePanel.module.css\";\n\nexport function TextViewer({ path }: ViewerProps) {\n const query = useFileRead(path);\n\n if (query.isLoading) {\n return (\n <div className={styles.emptyState}>\n <Spinner size=\"sm\" /> Loading...\n </div>\n );\n }\n if (query.isError) {\n return (\n <div className={styles.emptyState}>\n Error: {query.error instanceof Error ? query.error.message : \"unknown error\"}\n </div>\n );\n }\n if (!query.data) return null;\n return <CodeView path={path} content={query.data.content} />;\n}\n"],"names":["TextViewer","path","query","useFileRead","jsxs","styles","jsx","Spinner","CodeView"],"mappings":"2cAYO,SAASA,EAAW,CAAE,KAAAC,GAAqB,CAChD,MAAMC,EAAQC,EAAYF,CAAI,EAE9B,OAAIC,EAAM,UAENE,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAO,WACrB,SAAA,CAAAC,EAAAA,IAACC,EAAA,CAAQ,KAAK,IAAA,CAAK,EAAE,aAAA,EACvB,EAGAL,EAAM,QAENE,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAO,WAAY,SAAA,CAAA,UACzBH,EAAM,iBAAiB,MAAQA,EAAM,MAAM,QAAU,eAAA,EAC/D,EAGCA,EAAM,WACHM,EAAA,CAAS,KAAAP,EAAY,QAASC,EAAM,KAAK,QAAS,EADlC,IAE1B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as o}from"./vendor-react-BoIQBqDW.js";import{S as t}from"./index-
|
|
2
|
-
//# sourceMappingURL=VideoViewer-
|
|
1
|
+
import{j as o}from"./vendor-react-BoIQBqDW.js";import{S as t}from"./index-BTP_UxAo.js";import{u as a}from"./use-file-download-CwyNTuhL.js";import{p as e}from"./FilePanel-YoyZJ2v2.js";import"./vendor-query-AtKBh_Yt.js";import"./vendor--os7hw7d.js";import"./vendor-markdown-B8HSIhaA.js";import"./vendor-highlight-DCzuSv8g.js";import"./vendor-icons-CX25WOn8.js";import"./vendor-overlays-UwLNGk04.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-DlVCPvLc.js";const n="_wrap_1c9y4_1",m="_video_1c9y4_10",i={wrap:n,video:m};function S({path:s}){const r=a(s);return r.isLoading?o.jsxs("div",{className:e.emptyState,children:[o.jsx(t,{size:"sm"})," Loading video..."]}):r.isError?o.jsxs("div",{className:e.emptyState,children:["Error: ",r.error instanceof Error?r.error.message:"unknown error"]}):r.data?o.jsx("div",{className:i.wrap,children:o.jsx("video",{className:i.video,src:r.data.objectUrl,controls:!0})}):null}export{S as VideoViewer};
|
|
2
|
+
//# sourceMappingURL=VideoViewer-BoA5BwxX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoViewer-
|
|
1
|
+
{"version":3,"file":"VideoViewer-BoA5BwxX.js","sources":["../../../src/features/files/VideoViewer.tsx"],"sourcesContent":["/**\n * VideoViewer — renders a binary video file via the file-transfer binary download\n * (`useFileDownload`) into a native `<video>` element (POC_TO_APP_PLAN_UI.md §4.5 follow-up:\n * modular file preview).\n */\n\nimport { Spinner } from \"@pi-studio-ui/components/primitives/Spinner.js\";\nimport { useFileDownload } from \"@pi-studio-ui/hooks/use-file-download.js\";\nimport type { ViewerProps } from \"./viewer-registry.js\";\nimport panelStyles from \"./FilePanel.module.css\";\nimport styles from \"./VideoViewer.module.css\";\n\nexport function VideoViewer({ path }: ViewerProps) {\n const query = useFileDownload(path);\n\n if (query.isLoading) {\n return (\n <div className={panelStyles.emptyState}>\n <Spinner size=\"sm\" /> Loading video...\n </div>\n );\n }\n if (query.isError) {\n return (\n <div className={panelStyles.emptyState}>\n Error: {query.error instanceof Error ? query.error.message : \"unknown error\"}\n </div>\n );\n }\n if (!query.data) return null;\n\n return (\n <div className={styles.wrap}>\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- arbitrary local file, no caption track available */}\n <video className={styles.video} src={query.data.objectUrl} controls />\n </div>\n );\n}\n"],"names":["VideoViewer","path","query","useFileDownload","jsxs","panelStyles","jsx","Spinner","styles"],"mappings":"4gBAYO,SAASA,EAAY,CAAE,KAAAC,GAAqB,CACjD,MAAMC,EAAQC,EAAgBF,CAAI,EAElC,OAAIC,EAAM,UAENE,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAY,WAC1B,SAAA,CAAAC,EAAAA,IAACC,EAAA,CAAQ,KAAK,IAAA,CAAK,EAAE,mBAAA,EACvB,EAGAL,EAAM,QAENE,EAAAA,KAAC,MAAA,CAAI,UAAWC,EAAY,WAAY,SAAA,CAAA,UAC9BH,EAAM,iBAAiB,MAAQA,EAAM,MAAM,QAAU,eAAA,EAC/D,EAGCA,EAAM,WAGR,MAAA,CAAI,UAAWM,EAAO,KAErB,eAAC,QAAA,CAAM,UAAWA,EAAO,MAAO,IAAKN,EAAM,KAAK,UAAW,SAAQ,GAAC,EACtE,EANsB,IAQ1B"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ChatPanel-D_3cLBoK.js","assets/vendor-react-BoIQBqDW.js","assets/vendor-query-AtKBh_Yt.js","assets/vendor-icons-CX25WOn8.js","assets/markdown-D9FuaV1m.js","assets/vendor-highlight-DCzuSv8g.js","assets/vendor-markdown-B8HSIhaA.js","assets/vendor--os7hw7d.js","assets/markdown-BQwXm0MF.css","assets/DiffView-DlVCPvLc.js","assets/DiffView-CRbeRztO.css","assets/vendor-overlays-UwLNGk04.js","assets/vendor-dnd-D9kA7FgH.js","assets/ChatPanel-CTnpkb2U.css","assets/FilePanel-YoyZJ2v2.js","assets/FilePanel-DIInFr3h.css","assets/TerminalPanel-rKZq5rWo.js","assets/vendor-terminal-BhzX2_ts.js","assets/vendor-terminal-DYP7pi_n.css","assets/TerminalPanel-BQj62G6N.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
var En=Object.defineProperty;var Rn=(t,e,n)=>e in t?En(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var I=(t,e,n)=>Rn(t,typeof e!="symbol"?e+"":e,n);import{r as v,j as i,d as qn}from"./vendor-react-BoIQBqDW.js";import{Q as Mn,a as Bn,u as zt,b as $n,c as Re,d as An}from"./vendor-query-AtKBh_Yt.js";import{A as l,B as u,C as A,D as Ht,E as q,F as qe,G as ne,H as B,I as w,J as D,K as O,L as Ke,M as _e,N as pe}from"./vendor--os7hw7d.js";import{L as Dn,P as Fn,a as On,b as Pn,c as zn,E as Wt,C as ht,d as Lt,F as Hn,e as Ut,f as Kt,S as Gt,G as Wn,g as Ln,M as Vt,X as rt,h as Ee,i as Jt,j as Un,k as Yt,U as Kn,R as Gn,l as Xt,m as Vn,n as Jn,o as Yn,D as Xn,p as Qn,A as Zn}from"./vendor-icons-CX25WOn8.js";import{R as Ge,T as Ve,P as Je,C as Ye,I as G,S as at,D as es,a as ts,b as ns,c as ss,d as St,e as it}from"./vendor-overlays-UwLNGk04.js";import{u as os,a as rs,D as as,c as is,S as cs,h as ls,P as ds,b as us,C as ps}from"./vendor-dnd-D9kA7FgH.js";import{_ as mt}from"./vendor-highlight-DCzuSv8g.js";import"./vendor-markdown-B8HSIhaA.js";(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))s(o);new MutationObserver(o=>{for(const r of o)if(r.type==="childList")for(const a of r.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&s(a)}).observe(document,{childList:!0,subtree:!0});function n(o){const r={};return o.integrity&&(r.integrity=o.integrity),o.referrerPolicy&&(r.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?r.credentials="include":o.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function s(o){if(o.ep)return;o.ep=!0;const r=n(o);fetch(o.href,r)}})();const fs=new Mn;function Qt(t){const e=t.trim().replace(/^#/,""),n=e.length===3?e.split("").map(s=>s+s).join(""):e;if(n.length!==6||/[^0-9a-fA-F]/.test(n))throw new Error(`Invalid hex color: ${t}`);return{r:parseInt(n.slice(0,2),16),g:parseInt(n.slice(2,4),16),b:parseInt(n.slice(4,6),16)}}function hs(t){return Math.max(0,Math.min(255,Math.round(t)))}function ms({r:t,g:e,b:n}){const s=o=>hs(o).toString(16).padStart(2,"0");return`#${s(t)}${s(e)}${s(n)}`}function gs(t){const{r:e,g:n,b:s}=Qt(t),o=r=>{const a=r/255;return a<=.03928?a/12.92:((a+.055)/1.055)**2.4};return .2126*o(e)+.7152*o(n)+.0722*o(s)}function gt(t,e="#18181b",n="#ffffff"){return gs(t)>.45?e:n}function _s(t,e){const{r:n,g:s,b:o}=Qt(t),r=Math.max(0,Math.min(1,e));return ms({r:n+(255-n)*r,g:s+(255-s)*r,b:o+(255-o)*r})}function De(t){const e=t.trim().replace(/^#/,"");return(e.length===3||e.length===6)&&!/[^0-9a-fA-F]/.test(e)}const L=(t,e,n,s,o,r,a,c,d,m,f)=>({50:t,100:e,200:n,300:s,400:o,500:r,600:a,700:c,800:d,900:m,950:f}),x={zinc:L("#fafafa","#f4f4f5","#e4e4e7","#d4d4d8","#a1a1aa","#71717a","#52525b","#3f3f46","#27272a","#18181b","#09090b"),gray:L("#f9fafb","#f3f4f6","#e5e7eb","#d1d5db","#9ca3af","#6b7280","#4b5563","#374151","#1f2937","#111827","#030712"),slate:L("#f8fafc","#f1f5f9","#e2e8f0","#cbd5e1","#94a3b8","#64748b","#475569","#334155","#1e293b","#0f172a","#020617"),blue:L("#eff6ff","#dbeafe","#bfdbfe","#93c5fd","#60a5fa","#3b82f6","#2563eb","#1d4ed8","#1e40af","#1e3a8a","#172554"),green:L("#f0fdf4","#dcfce7","#bbf7d0","#86efac","#4ade80","#22c55e","#16a34a","#15803d","#166534","#14532d","#052e16"),red:L("#fef2f2","#fee2e2","#fecaca","#fca5a5","#f87171","#ef4444","#dc2626","#b91c1c","#991b1b","#7f1d1d","#450a0a"),teal:L("#f0fdfa","#ccfbf1","#99f6e4","#5eead4","#2dd4bf","#14b8a6","#0d9488","#0f766e","#115e59","#134e4a","#042f2e"),amber:L("#fffbeb","#fef3c7","#fde68a","#fcd34d","#fbbf24","#f59e0b","#d97706","#b45309","#92400e","#78350f","#451a03"),yellow:L("#fefce8","#fef9c3","#fef08a","#fde047","#facc15","#eab308","#ca8a04","#a16207","#854d0e","#713f12","#422006"),purple:L("#faf5ff","#f3e8ff","#e9d5ff","#d8b4fe","#c084fc","#a855f7","#9333ea","#7e22ce","#6b21a8","#581c87","#3b0764"),orange:L("#fff7ed","#ffedd5","#fed7aa","#fdba74","#fb923c","#f97316","#ea580c","#c2410c","#9a3412","#7c2d12","#431407"),white:"#ffffff",black:"#000000"},ys={statusSuccess:"#16a34a",statusDanger:"#dc2626",statusWarning:"#f59e0b",statusMerged:"#9333ea"},bs={statusSuccess:"#15803d",statusDanger:"#b91c1c",statusWarning:"#d97706",statusMerged:"#7c3aed"};function ws(){return{keyword:x.purple[300],string:x.green[300],number:x.orange[300],boolean:x.orange[300],comment:x.zinc[500],function:x.blue[300],variable:x.zinc[200],type:x.teal[300],class:x.amber[300],constant:x.orange[300],operator:x.zinc[400],punctuation:x.zinc[400],tag:x.red[300],attribute:x.amber[300],property:x.blue[200],regexp:x.teal[300],escape:x.orange[200],heading:x.blue[300],link:x.blue[400],deleted:x.red[400],inserted:x.green[400]}}function Ss(){return{keyword:x.purple[700],string:x.green[700],number:x.orange[700],boolean:x.orange[700],comment:x.zinc[500],function:x.blue[700],variable:x.zinc[800],type:x.teal[700],class:x.amber[700],constant:x.orange[700],operator:x.zinc[600],punctuation:x.zinc[600],tag:x.red[700],attribute:x.amber[700],property:x.blue[700],regexp:x.teal[700],escape:x.orange[700],heading:x.blue[700],link:x.blue[600],deleted:x.red[700],inserted:x.green[700]}}function Zt(t,e,n){return{background:t,foreground:e,cursor:n,cursorAccent:t,selectionBackground:"rgba(255,255,255,0.18)",black:x.zinc[900],red:x.red[500],green:x.green[500],yellow:x.amber[500],blue:x.blue[500],magenta:x.purple[500],cyan:x.teal[500],white:x.zinc[300],brightBlack:x.zinc[600],brightRed:x.red[400],brightGreen:x.green[400],brightYellow:x.amber[400],brightBlue:x.blue[400],brightMagenta:x.purple[400],brightCyan:x.teal[400],brightWhite:x.zinc[50]}}function xe(t){const e=x.zinc[50],n=gt(t.accent);return{surface0:t.surface0,surface1:t.surface1,surface2:t.surface2,surface3:t.surface3,surface4:t.surface4,surfaceDiffEmpty:t.surfaceDiffEmpty,surfaceSidebar:t.surfaceSidebar,surfaceSidebarHover:t.surfaceSidebarHover,surfaceWorkspace:t.surface1,foreground:e,foregroundMuted:t.mutedForeground,accent:t.accent,accentBright:t.accentBright,accentForeground:n,destructive:t.destructive,destructiveForeground:x.white,success:t.accent,successForeground:x.white,border:t.border,borderAccent:t.borderAccent,...ys,diffAddition:x.green[400],diffDeletion:x.red[500],scrollbarHandle:t.scrollbarHandle,background:t.surface0,popover:t.surface2,popoverForeground:e,primary:t.accent,secondary:t.surface2,muted:t.surface2,mutedForeground:t.mutedForeground,input:t.surface2,ring:t.accent,palette:x,syntax:ws(),terminal:Zt(t.surface0,e,t.accent)}}function xs(){const t="#1a1a1e",e="#253e6f";return{surface0:"#ffffff",surface1:"#fafafa",surface2:"#f4f4f5",surface3:"#e4e4e7",surface4:"#d4d4d8",surfaceDiffEmpty:"#f6f6f6",surfaceSidebar:"#f4f4f5",surfaceSidebarHover:"#e9e9ec",surfaceWorkspace:"#ffffff",foreground:t,foregroundMuted:"#71717a",accent:e,accentBright:"#2f4f8e",accentForeground:gt(e),destructive:"#b04138",destructiveForeground:"#ffffff",success:e,successForeground:"#ffffff",border:"#e4e4e7",borderAccent:"#ececf1",...bs,diffAddition:"#15803d",diffDeletion:"#b91c1c",scrollbarHandle:"#3f3f46",background:"#ffffff",popover:"#ffffff",popoverForeground:t,primary:e,secondary:"#f4f4f5",muted:"#f4f4f5",mutedForeground:"#71717a",input:"#f4f4f5",ring:e,palette:x,syntax:Ss(),terminal:{...Zt("#ffffff",t,e),selectionBackground:"rgba(0,0,0,0.15)",white:"#ffffff",brightWhite:"#fafafa"}}}const vs={light:"#ffffff",dark:"#3b62b0",zinc:"#808080",midnight:"#4A6BA8",claude:"#D97757",ghostty:"#8caaee"},en=["light","dark","zinc","midnight","claude","ghostty"];function ks(t){if(t==="light")return xs();switch(t){case"dark":return xe({surface0:"#181B1A",surface1:"#1E2120",surface2:"#272A29",surface3:"#434645",surface4:"#595B5B",surfaceDiffEmpty:"#252827",surfaceSidebar:"#141716",surfaceSidebarHover:"#1c1f1e",mutedForeground:"#A1A5A4",scrollbarHandle:"#717574",border:"#252B2A",borderAccent:"#2f3135",accent:"#2e5cb8",accentBright:"#a2b4d7",destructive:"#c64f43"});case"zinc":return xe({surface0:"#18181b",surface1:"#1f1f22",surface2:"#27272a",surface3:"#3f3f46",surface4:"#52525b",surfaceDiffEmpty:"#242427",surfaceSidebar:"#131316",surfaceSidebarHover:"#1b1b1e",mutedForeground:"#a1a1aa",scrollbarHandle:"#71717a",border:"#27272a",borderAccent:"#303036",accent:"#e4e4e7",accentBright:"#fafafa",destructive:"#c44a4a"});case"midnight":return xe({surface0:"#161820",surface1:"#1c1e27",surface2:"#252731",surface3:"#3c3e4c",surface4:"#535564",surfaceDiffEmpty:"#222430",surfaceSidebar:"#121420",surfaceSidebarHover:"#1a1c28",mutedForeground:"#9a9db0",scrollbarHandle:"#6b6e82",border:"#242636",borderAccent:"#2e3040",accent:"#3b6fcf",accentBright:"#7eaaeb",destructive:"#c44a52"});case"claude":return xe({surface0:"#1f1f1e",surface1:"#262523",surface2:"#2f2d2b",surface3:"#4a4745",surface4:"#605d5b",surfaceDiffEmpty:"#2a2826",surfaceSidebar:"#1a1918",surfaceSidebarHover:"#222120",mutedForeground:"#ada9a5",scrollbarHandle:"#78746f",border:"#2c2a27",borderAccent:"#36332f",accent:"#d97757",accentBright:"#e89a7f",destructive:"#cf513e"});case"ghostty":return xe({surface0:"#282c34",surface1:"#2f333d",surface2:"#383c48",surface3:"#4a4f5e",surface4:"#5b6175",surfaceDiffEmpty:"#323643",surfaceSidebar:"#21252d",surfaceSidebarHover:"#292d36",mutedForeground:"#c8ccd8",scrollbarHandle:"#a0a4b2",border:"#353a47",borderAccent:"#3f4454",accent:"#89b4fa",accentBright:"#b4d0fc",destructive:"#c44a55"})}}const tn={};for(const t of en){const e=t==="light"?"light":"dark";tn[t]={name:t,colorScheme:e,colors:ks(t),swatch:vs[t]}}const Is=tn,js={0:0,1:4,"1.5":6,2:8,3:12,4:16,6:24,8:32,12:48,16:64,20:80,24:96,32:128},nn={xs:12,code:12,sm:14,base:16,lg:18,xl:20,"2xl":22,"3xl":26,"4xl":34},Cs={normal:"400",medium:"500",semibold:"600",bold:"700"},Ts={none:0,sm:2,base:4,md:6,lg:8,xl:12,"2xl":16,full:9999},Ns={0:0,1:1,2:2},Es={0:0,50:.5,100:1},Rs={xs:12,sm:14,md:16,lg:20},qs={diff:22},sn='system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',on='ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace';function Ms(t){const e=t==="dark"?"rgba(0,0,0,0.55)":"rgba(24,24,27,0.12)";return{sm:{color:e,offsetX:0,offsetY:1,radius:2,elevation:1},md:{color:e,offsetX:0,offsetY:3,radius:8,elevation:4},lg:{color:e,offsetX:0,offsetY:10,radius:24,elevation:12}}}function rn(t){const e=Is[t];return{name:t,colorScheme:e.colorScheme,colors:e.colors,spacing:js,fontSize:{...nn},fontFamily:{ui:sn,mono:on},lineHeight:{...qs},iconSize:Rs,fontWeight:Cs,borderRadius:Ts,borderWidth:Ns,opacity:Es,shadow:Ms(e.colorScheme),swatch:e.swatch}}const Bs=16,$s=10,As=24;function Ds(t,e){const n=e.themeName??t.name,s=rn(n),o=e.uiFont&&e.uiFont.trim()!==""?e.uiFont:sn,r=e.monoFont&&e.monoFont.trim()!==""?e.monoFont:on;let a={...s.fontSize};if(e.fontSize!=null){const d=Math.max($s,Math.min(As,e.fontSize))/Bs,m=["xs","code","sm","base","lg","xl","2xl","3xl","4xl"];for(const f of m){const b=nn[f];a[f]=Math.round(b*d)}}return{...s,fontSize:a,fontFamily:{ui:o,mono:r}}}function Fs(t){return rn(t)}const Os="dark";function Ps(t){const e={};zs(t.colors,e);for(const[n,s]of Object.entries(t.spacing))e[`--pi-spacing-${n}`]=`${s}px`;for(const[n,s]of Object.entries(t.fontSize))e[`--pi-font-size-${n}`]=`${s}px`;e["--pi-font-ui"]=t.fontFamily.ui,e["--pi-font-mono"]=t.fontFamily.mono,e["--pi-line-height-diff"]=`${t.lineHeight.diff}px`;for(const[n,s]of Object.entries(t.iconSize))e[`--pi-icon-size-${n}`]=`${s}px`;for(const[n,s]of Object.entries(t.fontWeight))e[`--pi-font-weight-${n}`]=String(s);for(const[n,s]of Object.entries(t.borderRadius))e[`--pi-radius-${n}`]=s===9999?"9999px":`${s}px`;for(const[n,s]of Object.entries(t.borderWidth))e[`--pi-border-width-${n}`]=`${s}px`;for(const[n,s]of Object.entries(t.opacity))e[`--pi-opacity-${n}`]=String(s);for(const[n,s]of Object.entries(t.shadow))if(typeof s=="string")e[`--pi-shadow-${n}`]=s;else if(s&&typeof s=="object"){const o=s;e[`--pi-shadow-${n}`]=`${o.offsetX}px ${o.offsetY}px ${o.radius}px ${o.color}`}return e["--pi-color-scheme"]=t.colorScheme,e}function zs(t,e){const{palette:n,syntax:s,terminal:o,...r}=t;for(const[a,c]of Object.entries(r))typeof c=="string"&&(e[`--pi-color-${a}`]=c);s&&Hs(s,e),o&&(e["--pi-terminal-bg"]=o.background,e["--pi-terminal-fg"]=o.foreground)}function Hs(t,e){for(const[n,s]of Object.entries(t))typeof s=="string"&&(e[`--syntax-${Ws(n)}`]=s)}function Ws(t){return t.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function Ls(t){if(typeof document>"u")return;const e=document.documentElement.style;for(const[s,o]of Object.entries(t))e.setProperty(s,o);const n=t["--pi-color-scheme"];n&&document.documentElement.style.setProperty("color-scheme",n)}function Us(t){const e=Ps(t);Ls(e)}const ve=l().min(1,"Asset path must not be empty"),Ks=u({accent:l().refine(De,{message:"accent must be a valid #rrggbb hex color"}),accentBright:l().refine(De,{message:"accentBright must be a valid #rrggbb hex color"}).optional(),accentForeground:l().refine(De,{message:"accentForeground must be a valid #rrggbb hex color"}).optional(),swatch:l().refine(De,{message:"swatch must be a valid #rrggbb hex color"}).optional()}),Gs=u({logoLight:ve,logoDark:ve,logoMark:ve.optional(),icon:ve,splash:ve.optional()}),Vs=u({docs:l().url().optional(),support:l().url().optional(),issues:l().url().optional(),website:l().url().optional()}).optional(),Js=u({copyright:l().optional(),companyName:l().optional()}).optional();u({productName:l().min(1,"productName is required"),shortName:l().optional(),tagline:l().optional(),colors:Ks,assets:Gs,links:Vs,legal:Js});function Ys(t){const e=t.accent,n=t.accentBright??_s(e,.35),s=t.accentForeground??gt(e),o=t.swatch??e;return{accent:e,accentBright:n,accentForeground:s,swatch:o}}function Xs(t,e){return{...t,colors:{...t.colors,accent:e.accent,accentBright:e.accentBright,accentForeground:e.accentForeground,primary:e.accent,ring:e.accent},swatch:e.swatch}}const xt="pi-studio-appearance";function Qs(t,e){let n=c(t),s=null;function o(f){return f==="system"?typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":f}function r(f,b){const h=o(f),S=Fs(h);let g=Ds(S,{...b,themeName:h});if(e!=null&&e.colors){const _=Ys(e.colors);g=Xs(g,_)}return g}function a(){const f=JSON.stringify({mode:n.mode,settings:n.settings});t.set(xt,f)}function c(f){const b=f.get(xt);let h=Os,S={};if(b)try{const _=JSON.parse(b);_.mode&&(en.includes(_.mode)||_.mode==="system")&&(h=_.mode),_.settings&&typeof _.settings=="object"&&(S=_.settings)}catch{}const g=r(h,S);return{mode:h,settings:S,resolvedTheme:g}}function d(){n={...n,resolvedTheme:r(n.mode,n.settings)},a()}const m={getState(){return n},setMode(f){n={...n,mode:f},d(),m.apply()},updateSettings(f){n={...n,settings:{...n.settings,...f}},d(),m.apply()},apply(){Us(n.resolvedTheme)},listen(){if(typeof window>"u")return()=>{};const f=window.matchMedia("(prefers-color-scheme: dark)"),b=()=>{n.mode==="system"&&(d(),m.apply())};return f.addEventListener("change",b),s=()=>f.removeEventListener("change",b),s}};return m}function Zs({store:t,brandConfig:e,children:n}){const s=v.useRef(null);return s.current||(s.current=Qs(t,e),s.current.apply()),v.useEffect(()=>s.current.listen(),[]),i.jsx(i.Fragment,{children:n})}const eo={get(t){var e;try{return((e=globalThis.localStorage)==null?void 0:e.getItem(t))??null}catch{return null}},set(t,e){var n;try{(n=globalThis.localStorage)==null||n.setItem(t,e)}catch{}}};function to({children:t}){return i.jsx(Zs,{store:eo,children:i.jsx(Bn,{client:fs,children:t})})}const no="_btn_1chbg_4",so="_secondary_1chbg_44",oo="_outline_1chbg_53",ro="_ghost_1chbg_62",ao="_destructive_1chbg_72",io="_iconOnly_1chbg_82",co="_loadingSpinner_1chbg_89",lo="_piSpin_1chbg_1",Fe={btn:no,default:"_default_1chbg_35",secondary:so,outline:oo,ghost:ro,destructive:ao,iconOnly:io,loadingSpinner:co,piSpin:lo},vt={xs:28,sm:32,md:36,lg:40},uo={xs:12,sm:14,md:16,lg:20},kt={xs:8,sm:10,md:12,lg:16},po={xs:12,sm:13,md:14,lg:15};function fo(t){const{disabled:e,loading:n}=t;return e||n?{opacity:.5,isGhostHover:!1}:{opacity:1,isGhostHover:!1}}function F({variant:t="default",size:e="md",loading:n=!1,disabled:s=!1,leftIcon:o,trailing:r,iconOnly:a=!1,children:c,style:d,className:m,...f}){const{opacity:b}=fo({disabled:s??!1,loading:n}),h=s||n,S=uo[e];return i.jsxs("button",{className:A(Fe.btn,Fe[t],a&&Fe.iconOnly,m),disabled:h,"aria-busy":n||void 0,style:{minHeight:vt[e],paddingLeft:a?void 0:kt[e],paddingRight:a?void 0:kt[e],fontSize:po[e],opacity:b,...a?{width:vt[e]}:{},...d},...f,children:[n?i.jsx(Dn,{className:Fe.loadingSpinner,size:S,"aria-hidden":!0}):o?i.jsx("span",{"aria-hidden":!0,style:{display:"flex",alignItems:"center",flexShrink:0},children:o}):null,c,r&&!n&&i.jsx("span",{"aria-hidden":!0,style:{display:"flex",alignItems:"center",flexShrink:0},children:r})]})}const ho="_input_a7qyq_3",mo="_textarea_a7qyq_32",ct={input:ho,textarea:mo},Ue=v.forwardRef(function({className:e,...n},s){return i.jsx("input",{ref:s,className:A(ct.input,e),...n})}),Wd=v.forwardRef(function({className:e,...n},s){return i.jsx("textarea",{ref:s,className:A(ct.input,ct.textarea,e),...n})}),an=l().datetime({offset:!0});l().uuid();l().regex(/^[A-Za-z0-9_-]+$/,"expected base64url");const Ne=Ht([q(),an]),go=qe(["mobile","browser","cli","mcp"]),_o=u({type:w("hello"),clientId:l(),clientType:go,protocolVersion:q(),appVersion:l().optional(),capabilities:ne(l(),B()).optional()}),yo=u({status:w("server_info"),serverId:l(),hostname:l().optional(),version:l().optional(),capabilities:ne(l(),D()),features:ne(l(),D())}),bo=u({type:w("status"),payload:yo}),wo=u({type:w("ping"),requestId:l(),clientSentAt:Ne.optional()}),So=u({type:w("pong"),requestId:l(),clientSentAt:Ne.optional(),serverReceivedAt:Ne,serverSentAt:Ne}),cn=qe(["initializing","idle","running","error","closed"]),Xe=u({mimeType:l().optional(),data:l().optional()}).passthrough(),xo=u({prs:O(D()).optional(),issues:O(D()).optional()}).passthrough(),vo=u({provider:l(),cwd:l(),modeId:l().optional(),model:l().optional(),modelProvider:l().optional(),thinkingOptionId:l().optional(),featureValues:ne(l(),D()).optional(),title:l().nullable().optional(),approvalPolicy:l().optional(),sandboxMode:l().optional(),networkAccess:B().optional(),webSearch:B().optional(),extra:u({pi:D().optional()}).passthrough().optional(),systemPrompt:l().optional(),mcpServers:ne(l(),D()).optional()}),ko=u({type:w("create_agent_request"),requestId:l(),config:vo,env:ne(l(),l()).optional(),workspaceId:l().optional(),worktreeName:l().optional(),initialPrompt:l().optional(),clientMessageId:l().optional(),outputSchema:ne(l(),D()).optional(),images:O(Xe).optional(),attachments:xo.optional(),git:D().optional(),worktree:D().optional(),autoArchive:B().optional(),labels:ne(l(),l()).default({})}),Io=u({type:w("create_agent_response"),requestId:l(),payload:u({agentId:l()}).passthrough()}),jo=u({type:w("agent_update"),agentId:l(),status:cn.optional(),title:l().nullable().optional(),labels:ne(l(),l()).optional()}),Co=u({type:w("agent_status"),agentId:l(),status:cn}),To=u({type:w("agent_list"),agents:O(u({id:l()}).passthrough())}),No=u({type:w("agent_deleted"),agentId:l()}),Eo=u({type:w("agent_archived"),agentId:l(),archivedAt:an.optional()}),ln=Ke("kind",[u({kind:w("shell"),command:l().optional(),output:l().optional()}),u({kind:w("read"),path:l().optional(),output:l().optional()}),u({kind:w("edit"),path:l().optional(),diff:l().optional(),output:l().optional()}),u({kind:w("write"),path:l().optional(),output:l().optional()}),u({kind:w("search"),query:l().optional(),output:l().optional()}),u({kind:w("fetch"),url:l().optional(),output:l().optional()}),u({kind:w("task"),description:l().optional(),output:l().optional()})]),Ro=Ke("kind",[u({kind:w("user_message"),messageId:l().optional(),text:l().optional(),images:O(Xe).optional()}),u({kind:w("assistant_message"),messageId:l().optional(),text:l().optional()}),u({kind:w("reasoning"),text:l().optional()}),u({kind:w("tool_call"),callId:l().optional(),tool:ln,status:l().optional()}),u({kind:w("turn_started"),turnId:l().optional()}),u({kind:w("turn_completed"),turnId:l().optional()}),u({kind:w("turn_failed"),turnId:l().optional(),error:l().optional()}),u({kind:w("turn_canceled"),turnId:l().optional()}),u({kind:w("error"),message:l().optional()}),u({kind:w("queue_update"),steering:O(l()).optional(),followUp:O(l()).optional()})]),qo=u({type:w("agent_stream"),agentId:l(),seq:q().optional(),timestamp:Ne.optional(),event:Ro}),Mo=qe(["before","after"]),Bo=u({start:q(),end:q()}),$o=u({type:w("fetch_agent_timeline_request"),requestId:l(),agentId:l(),cursor:l().nullable().optional(),direction:Mo,limit:q().optional()}),Ao=u({type:w("fetch_agent_timeline_response"),requestId:l(),agentId:l().optional(),items:O(D()),seqStart:q(),seqEnd:q(),sourceSeqRanges:O(Bo),collapsed:B(),hasNewer:B(),startCursor:l().nullable().optional(),endCursor:l().nullable().optional()}),Do=u({type:w("agent_permission_request"),requestId:l(),agentId:l(),toolName:l().optional(),tool:ln.optional(),action:D().optional(),responses:O(l()).optional()}),Fo=u({type:w("agent_permission_resolved"),requestId:l(),agentId:l(),decision:l().optional()}),Oo=u({type:w("agent.permission.respond.request"),requestId:l(),permissionRequestId:l(),response:D()}),Po=u({type:w("agent.permission.respond.response"),requestId:l(),payload:u({resolved:B()}).passthrough()}),zo=u({type:w("respond_to_permission"),requestId:l(),permissionRequestId:l(),response:D()}),dn=qe(["conversation","files","both"]),Ho=u({type:w("agent.rewind.request"),requestId:l(),agentId:l(),messageId:l(),mode:dn}).passthrough(),Wo=u({type:w("agent.rewind.response"),requestId:l(),payload:u({agentId:l(),messageId:l(),mode:dn,truncatedAt:l().optional()}).passthrough()}).passthrough(),Lo=u({input:q().optional(),output:q().optional(),cacheRead:q().optional(),cacheWrite:q().optional(),total:q().optional()}).passthrough(),Uo=u({tokens:q().nullable().optional(),contextWindow:q().optional(),percent:q().nullable().optional()}).passthrough(),Ko=u({type:w("agent_session_stats_request"),requestId:l(),agentId:l()}).passthrough(),Go=u({type:w("agent_session_stats_response"),requestId:l(),payload:u({sessionId:l().optional(),sessionFile:l().optional(),userMessages:q().optional(),assistantMessages:q().optional(),toolCalls:q().optional(),toolResults:q().optional(),totalMessages:q().optional(),tokens:Lo.optional(),cost:q().optional(),contextUsage:Uo.optional(),model:l().optional()}).passthrough()}).passthrough(),Vo=u({type:w("agent_compact_request"),requestId:l(),agentId:l(),customInstructions:l().optional()}).passthrough(),Jo=u({type:w("agent_compact_response"),requestId:l(),payload:u({summary:l().optional(),firstKeptEntryId:l().optional(),tokensBefore:q().optional(),details:D().optional()}).passthrough()}).passthrough(),Yo=u({type:w("agent_new_session_request"),requestId:l(),agentId:l()}).passthrough(),Xo=u({type:w("agent_new_session_response"),requestId:l(),payload:u({cancelled:B()}).passthrough()}).passthrough(),Qo=u({type:w("agent_switch_session_request"),requestId:l(),agentId:l(),sessionPath:l()}).passthrough(),Zo=u({type:w("agent_switch_session_response"),requestId:l(),payload:u({cancelled:B()}).passthrough()}).passthrough(),er=u({type:w("agent_fork_request"),requestId:l(),agentId:l(),entryId:l()}).passthrough(),tr=u({type:w("agent_fork_response"),requestId:l(),payload:u({text:l(),cancelled:B()}).passthrough()}).passthrough(),nr=u({type:w("agent_fork_messages_request"),requestId:l(),agentId:l()}).passthrough(),sr=u({type:w("agent_fork_messages_response"),requestId:l(),payload:u({messages:O(u({entryId:l(),text:l()}).passthrough())}).passthrough()}).passthrough(),or=u({type:w("agent_clone_request"),requestId:l(),agentId:l()}).passthrough(),rr=u({type:w("agent_clone_response"),requestId:l(),payload:u({cancelled:B()}).passthrough()}).passthrough(),ar=u({type:w("agent_set_session_name_request"),requestId:l(),agentId:l(),name:l()}).passthrough(),ir=u({type:w("agent_set_session_name_response"),requestId:l(),payload:u({}).passthrough().optional()}).passthrough(),cr=u({type:w("agent_export_html_request"),requestId:l(),agentId:l(),outputPath:l().optional()}).passthrough(),lr=u({type:w("agent_export_html_response"),requestId:l(),payload:u({path:l()}).passthrough()}).passthrough(),dr=u({type:w("agent_set_model_request"),requestId:l(),agentId:l(),provider:l(),modelId:l()}).passthrough(),ur=u({type:w("agent_set_model_response"),requestId:l(),payload:u({}).passthrough()}).passthrough(),pr=u({type:w("agent_cycle_model_request"),requestId:l(),agentId:l()}).passthrough(),fr=u({type:w("agent_cycle_model_response"),requestId:l(),payload:u({model:D().nullable().optional(),thinkingLevel:l().optional(),isScoped:B().optional()}).passthrough()}).passthrough(),hr=u({type:w("agent_last_assistant_text_request"),requestId:l(),agentId:l()}).passthrough(),mr=u({type:w("agent_last_assistant_text_response"),requestId:l(),payload:u({text:l().nullable()}).passthrough()}).passthrough(),gr=u({type:w("steer_agent_request"),requestId:l(),agentId:l(),message:l(),images:O(Xe).optional(),clientMessageId:l().optional()}).passthrough(),_r=u({type:w("steer_agent_response"),requestId:l(),agentId:l(),ok:B()}).passthrough(),yr=u({type:w("follow_up_agent_request"),requestId:l(),agentId:l(),message:l(),images:O(Xe).optional(),clientMessageId:l().optional()}).passthrough(),br=u({type:w("follow_up_agent_response"),requestId:l(),agentId:l(),ok:B()}).passthrough(),wr=u({type:w("rpc_error"),requestId:l(),code:l().optional(),message:l().optional(),error:l().optional()}),Sr=Ke("type",[ko,Io,jo,Co,To,No,Eo,qo,$o,Ao,Do,Fo,Oo,Po,zo,Ho,Wo,Ko,Go,Vo,Jo,Yo,Xo,Qo,Zo,er,tr,nr,sr,or,rr,ar,ir,cr,lr,dr,ur,pr,fr,hr,mr,gr,_r,yr,br,wr]),xr=u({type:l()}).passthrough(),vr=u({type:w("session"),message:Ht([Sr,xr])});Ke("type",[_o,bo,wo,So,vr]);const he={Output:1,Input:2,Resize:3,Snapshot:4,Restore:5},kr=Object.fromEntries(Object.entries(he).map(([t,e])=>[e,t])),un=u({rows:q().int().nonnegative(),cols:q().int().nonnegative()});class je extends Error{constructor(e){super(e),this.name="TerminalFrameError"}}const Ir=new TextEncoder,jr=new TextDecoder;function Cr(t){if(!Number.isInteger(t)||t<0||t>255)throw new je(`slot must be an integer 0–255, got ${t}`)}function ke(t,e,n){const s=new Uint8Array(2+n.length);return s[0]=t,s[1]=e,s.set(n,2),s}function Ld(t){switch(Cr(t.slot),t.opcode){case"Output":return ke(he.Output,t.slot,t.data);case"Input":return ke(he.Input,t.slot,t.data);case"Snapshot":return ke(he.Snapshot,t.slot,t.data);case"Restore":return ke(he.Restore,t.slot,t.data);case"Resize":{const e=JSON.stringify(un.parse({rows:t.rows,cols:t.cols}));return ke(he.Resize,t.slot,Ir.encode(e))}}}function Tr(t){if(t.length<2)throw new je(`frame too short: ${t.length} bytes (need ≥ 2)`);const e=t[0],n=t[1],s=kr[e];if(!s)throw new je(`unknown terminal opcode 0x${e.toString(16)}`);const o=t.subarray(2);if(s==="Resize"){let r;try{r=JSON.parse(jr.decode(o))}catch{throw new je("resize payload is not valid JSON")}const a=un.safeParse(r);if(!a.success)throw new je("resize payload is not { rows, cols }");return{opcode:"Resize",slot:n,rows:a.data.rows,cols:a.data.cols}}return{opcode:s,slot:n,data:o.slice()}}const ge={Begin:16,Chunk:17,End:18,Error:19},Nr=Object.fromEntries(Object.entries(ge).map(([t,e])=>[e,t])),pn=u({transferId:l(),fileName:l().optional(),mimeType:l().optional(),totalBytes:q().int().nonnegative().optional()});class Ce extends Error{constructor(e){super(e),this.name="FileTransferFrameError"}}const It=new TextEncoder,jt=new TextDecoder;function Er(t){if(!Number.isInteger(t)||t<0||t>255)throw new Ce(`stream must be an integer 0–255, got ${t}`)}function Oe(t,e,n){const s=new Uint8Array(2+n.length);return s[0]=t,s[1]=e,s.set(n,2),s}function tt(t){switch(Er(t.stream),t.opcode){case"Begin":return Oe(ge.Begin,t.stream,It.encode(JSON.stringify(pn.parse(t.meta))));case"Chunk":return Oe(ge.Chunk,t.stream,t.data);case"End":return Oe(ge.End,t.stream,new Uint8Array([t.ok?1:0]));case"Error":return Oe(ge.Error,t.stream,It.encode(t.message))}}function Rr(t){if(t.length<2)throw new Ce(`frame too short: ${t.length} bytes (need ≥ 2)`);const e=t[0],n=t[1],s=Nr[e];if(!s)throw new Ce(`unknown file-transfer opcode 0x${e.toString(16)}`);const o=t.subarray(2);switch(s){case"Begin":{let r;try{r=JSON.parse(jt.decode(o))}catch{throw new Ce("begin payload is not valid JSON")}const a=pn.safeParse(r);if(!a.success)throw new Ce("begin payload is not a valid transfer header");return{opcode:"Begin",stream:n,meta:a.data}}case"Chunk":return{opcode:"Chunk",stream:n,data:o.slice()};case"End":return{opcode:"End",stream:n,ok:(o[0]??1)!==0};case"Error":return{opcode:"Error",stream:n,message:jt.decode(o)}}}function qr(t){try{return Rr(t)}catch{return null}}const Mr=l().regex(/^[a-z][a-z0-9-]*$/,"invalid provider id"),Br=qe(["safe","moderate","dangerous","planning"]),$r=u({supportsStreaming:B(),supportsSessionPersistence:B(),supportsDynamicModes:B(),supportsMcpServers:B(),supportsReasoningStream:B(),supportsToolInvocations:B(),supportsRewindConversation:B().optional(),supportsRewindFiles:B().optional(),supportsRewindBoth:B().optional(),supportsSteering:B().optional()}).passthrough(),Ar=u({id:l(),label:l().optional(),description:l().optional(),icon:l().optional(),colorTier:Br});u({id:Mr,label:l(),description:l().optional(),extends:l().optional(),modes:O(Ar),capabilities:$r});function lt(t){return typeof t=="string"?t:t instanceof Uint8Array||Buffer.isBuffer(t)?t.toString("utf8"):String(t??"")}function fn(t){let e=null;const n={onMessage:null,onClose:null,onError:null,get isOpen(){return e!==null&&e.readyState===1},connect(s){return new Promise((o,r)=>{const a=t??(()=>new WebSocket(s));try{e=t?a(s):new WebSocket(s)}catch(c){r(c);return}e.onopen=()=>o(),e.onerror=c=>{var d;(e==null?void 0:e.readyState)!==1&&r(c),(d=n.onError)==null||d.call(n,c)},e.onclose=c=>{var d;(d=n.onClose)==null||d.call(n,c.code,lt(c.reason))},e.onmessage=c=>{var m,f,b,h;const{data:d}=c;d instanceof ArrayBuffer||d instanceof Uint8Array?(m=n.onMessage)==null||m.call(n,d):typeof d=="string"?(f=n.onMessage)==null||f.call(n,d):typeof Blob<"u"&&d instanceof Blob?(b=n.onMessage)==null||b.call(n,d):Buffer.isBuffer(d)&&((h=n.onMessage)==null||h.call(n,d.buffer.slice(d.byteOffset,d.byteOffset+d.byteLength)))}})},sendText(s){e==null||e.send(s)},sendBinary(s){e==null||e.send(s)},close(s=1e3,o=""){e==null||e.close(s,o),e=null}};return n}const Te="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function hn(t){let e="";for(let n=0;n<t.length;n+=3){const s=t[n],o=n+1<t.length,r=n+2<t.length,a=o?t[n+1]:0,c=r?t[n+2]:0;e+=Te[s>>2],e+=Te[(s&3)<<4|a>>4],e+=o?Te[(a&15)<<2|c>>6]:"=",e+=r?Te[c&63]:"="}return e}function mn(t){const e=t.replace(/=+$/,""),n=[];let s=0,o=0;for(const r of e){const a=Te.indexOf(r);if(a===-1)throw new Error(`invalid base64 character: ${JSON.stringify(r)}`);s=s<<6|a,o+=6,o>=8&&(o-=8,n.push(s>>o&255))}return new Uint8Array(n)}function Dr(t){try{const e=JSON.parse(t);return!e||typeof e.type!="string"?null:e}catch{return null}}const We=24;function gn(t,e){const n=_e.randomBytes(We),s=_e.box.after(t,n,e),o=new Uint8Array(n.length+s.length);return o.set(n,0),o.set(s,n.length),hn(o)}function _n(t,e){let n;try{n=mn(t)}catch{return null}if(n.length<We)return null;const s=n.slice(0,We),o=n.slice(We);return _e.box.open.after(o,s,e)}function Fr(t,e){return gn(new TextEncoder().encode(t),e)}function Or(t,e){const n=_n(t,e);return n?new TextDecoder().decode(n):null}function Pr(t,e,n,s,o,r){let a=!1;return n.onClose(c=>{var d;a=!0,(d=s.onClose)==null||d.call(s,c)}),{handleAppFrame(c){var f,b;if(a)return;const d=o();if(!r()||!d)return;const m=Or(c.frame,d);if(m===null){(f=s.onAuthError)==null||f.call(s,new Error(`relay ${t} channel: message failed authentication`));return}(b=s.onMessage)==null||b.call(s,m)},handleBinaryFrame(c){var f,b;if(a)return;const d=o();if(!r()||!d)return;const m=_n(c.frame,d);if(m===null){(f=s.onAuthError)==null||f.call(s,new Error(`relay ${t} channel: binary message failed authentication`));return}(b=s.onBinaryMessage)==null||b.call(s,m)},send(c){if(a)throw new Error(`relay ${t} channel: cannot send after close()`);const d=o();if(!r()||!d)throw new Error(`relay ${t} channel: cannot send before the E2EE handshake completes`);n.send(JSON.stringify({type:"e2ee_app",frame:Fr(c,d)}))},sendBinary(c){if(a)throw new Error(`relay ${t} channel: cannot send after close()`);const d=o();if(!r()||!d)throw new Error(`relay ${t} channel: cannot send before the E2EE handshake completes`);n.send(JSON.stringify({type:"e2ee_bin",frame:gn(c,d)}))},close(){a||(a=!0,n.close())}}}function zr(t){const{transport:e,attachment:n,daemonPublicKey:s}=t,o=t.events??{},r=_e.box.keyPair(),a=_e.box.before(s,r.secretKey);let c=!1;const d=Pr("client",n,e,o,()=>a,()=>c);return e.onMessage(m=>{var b;const f=Dr(m);if(f){if(f.type==="e2ee_ready"){if(c)return;c=!0,(b=o.onReady)==null||b.call(o);return}if(f.type==="e2ee_app"){d.handleAppFrame(f);return}f.type==="e2ee_bin"&&d.handleBinaryFrame(f)}}),e.send(JSON.stringify({type:"e2ee_hello",ephemeralPublicKey:hn(r.publicKey)})),{role:"client",attachment:n,get ready(){return c},send:d.send,sendBinary:d.sendBinary,close:d.close}}const Hr=16;function Wr(t){const e=_e.hash(t);let n="";for(let s=0;s<Hr;s++)n+=e[s].toString(16).padStart(2,"0");return n}function Lr(t){const e=t.useTls?"wss":"ws",n=t.endpoint.replace(/^(?:https?|wss?):\/\//,"").replace(/\/+$/,"");return`${e}://${n}`}function Ur(t){let e=null,n=null;const s=t.sessionId??Wr(t.daemonPublicKey),o={onMessage:null,onClose:null,onError:null,get isOpen(){return e!==null&&e.readyState===1&&n!==null&&n.ready},connect(r){return new Promise((a,c)=>{const d=t.factory??(()=>new WebSocket(r));try{e=t.factory?d(r):new WebSocket(r)}catch(h){c(h);return}const m=e,f=[],b=[];m.onopen=()=>{m.send(JSON.stringify({type:"relay_register",sessionId:s})),n=zr({transport:{send:h=>m.send(h),onMessage:h=>f.push(h),onClose:h=>b.push(h),close:()=>m.close()},attachment:{sessionId:s},daemonPublicKey:t.daemonPublicKey,events:{onReady:()=>a(),onMessage:h=>{var S;return(S=o.onMessage)==null?void 0:S.call(o,h)},onBinaryMessage:h=>{var S;return(S=o.onMessage)==null?void 0:S.call(o,h.slice().buffer)},onAuthError:h=>{var S;return(S=o.onError)==null?void 0:S.call(o,h)}}})},m.onerror=h=>{var S;m.readyState!==1&&c(h),(S=o.onError)==null||S.call(o,h)},m.onclose=h=>{var S;for(const g of b)g(lt(h.reason));(S=o.onClose)==null||S.call(o,h.code,lt(h.reason))},m.onmessage=h=>{const{data:S}=h;if(typeof S=="string")for(const g of f)g(S)}})},sendText(r){if(!n||!n.ready)throw new Error("relay transport: cannot send before the E2EE handshake completes");n.send(r)},sendBinary(r){if(!n||!n.ready)throw new Error("relay transport: cannot send before the E2EE handshake completes");n.sendBinary(r)},close(r=1e3,a=""){n==null||n.close(),n=null,e==null||e.close(r,a),e=null}};return o}function Kr(t){const e=t.indexOf("#"),n=e===-1?t:t.slice(e+1),s=new URLSearchParams(n),o=s.get("offer");if(!o)return null;let r;try{r=mn(o)}catch{return null}const a=s.get("relay");if(a){const d={endpoint:a,useTls:s.get("relayTls")==="1"};return{publicKeyB64:o,publicKey:r,relay:d}}const c=s.get("host")??void 0;return{publicKeyB64:o,publicKey:r,...c?{host:c}:{}}}const Gr=1;function dt(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`id-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}class Vr extends Error{constructor(e,n,s){super(e),this.requestId=n,this.code=s,this.name="RpcError"}}class Ct extends Error{constructor(e){super(`RPC ${e} timed out`),this.requestId=e,this.name="RpcTimeoutError"}}class Jr{constructor(e){I(this,"transport");I(this,"rpcTimeoutMs");I(this,"now");I(this,"_state","idle");I(this,"_serverId",null);I(this,"_features",{});I(this,"_serverCapabilities",{});I(this,"pending",new Map);I(this,"sessionHandlers",new Set);I(this,"terminalHandlers",new Set);I(this,"fileTransferHandlers",new Set);I(this,"stateHandlers",new Set);I(this,"helloResolve",null);I(this,"helloReject",null);this.options=e,this.transport=e.transport??fn(),this.rpcTimeoutMs=e.rpcTimeoutMs??3e4,this.now=e.now??(()=>Date.now()),this.transport.onMessage=n=>this.handleIncoming(n),this.transport.onClose=(n,s)=>this.handleClose(n,s),this.transport.onError=()=>{}}get state(){return this._state}get serverId(){return this._serverId}get features(){return this._features}get serverCapabilities(){return this._serverCapabilities}hasFeature(e){return!!this._features[e]}async connect(){this.setState("connecting"),await this.transport.connect(this.options.url);const e=new Promise((s,o)=>{this.helloResolve=s,this.helloReject=o});this.transport.sendText(JSON.stringify({type:"hello",clientId:this.options.clientId,clientType:this.options.clientType,protocolVersion:this.options.protocolVersion??Gr,appVersion:this.options.appVersion,capabilities:this.options.capabilities}));const n=await e;return this._serverId=n.serverId,this._features=n.features,this._serverCapabilities=n.capabilities,this.setState("open"),n}close(e=1e3,n=""){this.setState("closing"),this.transport.close(e,n)}request(e,n={},s){const o=n.requestId??dt();return new Promise((r,a)=>{const c=s??this.rpcTimeoutMs,d=c>0?setTimeout(()=>{this.pending.delete(o),a(new Ct(o))},c):null;this.pending.set(o,{resolve:m=>r(m),reject:a,timer:d}),this.sendSession({type:e,...n,requestId:o})})}sendSession(e){this.transport.sendText(JSON.stringify({type:"session",message:e}))}sendBinary(e){this.transport.sendBinary(e)}ping(e=1e4){const n=dt();return new Promise((s,o)=>{const r=e>0?setTimeout(()=>{this.pending.delete(n),o(new Ct(n))},e):null;this.pending.set(n,{resolve:()=>s(),reject:o,timer:r}),this.transport.sendText(JSON.stringify({type:"ping",requestId:n,clientSentAt:this.now()}))})}onSessionMessage(e){return this.sessionHandlers.add(e),()=>this.sessionHandlers.delete(e)}onTerminalFrame(e){return this.terminalHandlers.add(e),()=>this.terminalHandlers.delete(e)}onFileTransferFrame(e){return this.fileTransferHandlers.add(e),()=>this.fileTransferHandlers.delete(e)}onStateChange(e){return this.stateHandlers.add(e),()=>this.stateHandlers.delete(e)}setState(e){if(this._state!==e){this._state=e;for(const n of this.stateHandlers)n(e)}}handleClose(e,n){this.helloReject&&(this.helloReject(new Error(`socket closed during handshake: ${n}`)),this.helloResolve=null,this.helloReject=null);for(const[,s]of this.pending)s.timer&&clearTimeout(s.timer),s.reject(new Error(`socket closed: ${n}`));this.pending.clear(),this.setState("closed")}handleIncoming(e){if(typeof e=="string"){this.handleTextFrame(e);return}if(e instanceof ArrayBuffer){this.handleBinaryFrame(new Uint8Array(e));return}typeof e.arrayBuffer=="function"&&e.arrayBuffer().then(n=>this.handleBinaryFrame(new Uint8Array(n)))}handleBinaryFrame(e){const n=e[0];if(n!==void 0&&Object.values(ge).includes(n)){const r=qr(e);if(!r)return;for(const a of this.fileTransferHandlers)a(r);return}const o=Tr(e);for(const r of this.terminalHandlers)r(o)}handleTextFrame(e){let n;try{n=JSON.parse(e)}catch{return}const s=n;switch(s.type){case"status":this.handleStatus(s);return;case"pong":this.resolvePending(s.requestId,void 0);return;case"ping":this.transport.sendText(JSON.stringify({type:"pong",requestId:s.requestId,serverReceivedAt:this.now(),serverSentAt:this.now()}));return;case"session":this.handleSession(s.message);return;default:return}}handleStatus(e){const n=e.payload;(n==null?void 0:n.status)==="server_info"&&this.helloResolve&&(this.helloResolve(n),this.helloResolve=null,this.helloReject=null)}handleSession(e){if(!e||typeof e!="object")return;const n=e;if(n.type==="rpc_error"&&typeof n.requestId=="string"){const s=this.pending.get(n.requestId);s&&(s.timer&&clearTimeout(s.timer),this.pending.delete(n.requestId),s.reject(new Vr(n.message??n.error??"RPC failed",n.requestId,n.code)));return}if(typeof n.requestId=="string"&&this.pending.has(n.requestId)){const s="payload"in n?n.payload:n;this.resolvePending(n.requestId,s)}for(const s of this.sessionHandlers)s(e)}resolvePending(e,n){const s=this.pending.get(e);s&&(s.timer&&clearTimeout(s.timer),this.pending.delete(e),s.resolve(n))}}class Yr{constructor(e){this.daemon=e}get connection(){return this.daemon}async createAgent(e){return await this.daemon.request("create_agent_request",{...e})}agent(e){return new Qr(this.daemon,e)}workspace(e){return new Zr(this.daemon,e)}get providers(){return new ea(this.daemon)}onAgentUpdate(e){return this.daemon.onSessionMessage(n=>{n.type==="agent_update"&&e(n)})}onWorkspaceUpdate(e){return this.daemon.onSessionMessage(n=>{n.type==="workspace_update"&&e(n)})}}class Xr{constructor(e,n){this.daemon=e,this.agentId=n}fetch(e={}){return this.daemon.request("fetch_agent_timeline_request",{agentId:this.agentId,cursor:e.cursor,direction:e.direction,limit:e.limit})}subscribe(e){return this.daemon.onSessionMessage(n=>{const s=n;s.type==="agent_stream"&&s.agentId===this.agentId&&s.event&&e(s.event)})}}class Qr{constructor(e,n){I(this,"timeline");this.daemon=e,this.agentId=n,this.timeline=new Xr(e,n)}send(e,n={}){return this.daemon.request("send_agent_prompt",{agentId:this.agentId,prompt:e,clientMessageId:n.clientMessageId,images:n.images})}run(e,n){return this.send(e,n)}interrupt(){return this.daemon.request("interrupt_agent",{agentId:this.agentId})}steer(e,n={}){return this.daemon.request("steer_agent_request",{agentId:this.agentId,message:e,clientMessageId:n.clientMessageId,images:n.images})}followUp(e,n={}){return this.daemon.request("follow_up_agent_request",{agentId:this.agentId,message:e,clientMessageId:n.clientMessageId,images:n.images})}update(e){return this.daemon.request("update_agent",{agentId:this.agentId,...e})}resume(){return this.daemon.request("resume_agent",{agentId:this.agentId})}archive(){return this.daemon.request("archive_agent",{agentId:this.agentId})}delete(){return this.daemon.request("delete_agent",{agentId:this.agentId})}onUpdate(e){return this.daemon.onSessionMessage(n=>{const s=n;s.type==="agent_update"&&s.agentId===this.agentId&&e(s)})}sessionStats(){return this.daemon.request("agent_session_stats_request",{agentId:this.agentId})}compact(e){return this.daemon.request("agent_compact_request",{agentId:this.agentId,customInstructions:e})}newSession(){return this.daemon.request("agent_new_session_request",{agentId:this.agentId})}switchSession(e){return this.daemon.request("agent_switch_session_request",{agentId:this.agentId,sessionPath:e})}fork(e){return this.daemon.request("agent_fork_request",{agentId:this.agentId,entryId:e})}forkMessages(){return this.daemon.request("agent_fork_messages_request",{agentId:this.agentId})}clone(){return this.daemon.request("agent_clone_request",{agentId:this.agentId})}setSessionName(e){return this.daemon.request("agent_set_session_name_request",{agentId:this.agentId,name:e})}exportHtml(e){return this.daemon.request("agent_export_html_request",{agentId:this.agentId,outputPath:e})}setModel(e,n){return this.daemon.request("agent_set_model_request",{agentId:this.agentId,provider:e,modelId:n})}cycleModel(){return this.daemon.request("agent_cycle_model_request",{agentId:this.agentId})}lastAssistantText(){return this.daemon.request("agent_last_assistant_text_request",{agentId:this.agentId})}}class Zr{constructor(e,n){this.daemon=e,this.workspaceId=n}onUpdate(e){return this.daemon.onSessionMessage(n=>{const s=n;s.type==="workspace_update"&&s.workspaceId===this.workspaceId&&e(s)})}}class ea{constructor(e){this.daemon=e}listProviders(){return this.daemon.request("list_providers",{})}listModels(e){return this.daemon.request("list_provider_models",{provider:e})}listModes(e){return this.daemon.request("list_provider_modes",{provider:e})}resolveDefaultModel(e,n){return this.daemon.request("resolve_default_model",{provider:e,...n?{cwd:n}:{}})}refreshSnapshot(){return this.daemon.request("providers.snapshot.refresh.request",{})}}const Tt=32*1024;function ta(t){const e=t.reduce((o,r)=>o+r.length,0),n=new Uint8Array(e);let s=0;for(const o of t)n.set(o,s),s+=o.length;return n}class na{constructor(e){I(this,"pending",new Map);I(this,"nextStream",1);I(this,"detach",null);this.daemon=e}start(){this.detach||(this.detach=this.daemon.onFileTransferFrame(e=>this.dispatch(e)))}stop(){var e;(e=this.detach)==null||e.call(this),this.detach=null;for(const[n,s]of this.pending)s.reject(new Error("file transfer router stopped")),this.pending.delete(n)}async download(e){const n=await this.daemon.request("file_download_token_request",{path:e});if(!n.ok||!n.token)throw new Error(n.error??"failed to issue download token");const s=this.nextStream++,o=new Promise((a,c)=>{this.pending.set(s,{chunks:[],meta:{},resolve:a,reject:c})}),r=await this.daemon.request("file_download_request",{token:n.token,stream:s});if(!r.ok)throw this.pending.delete(s),new Error(r.error??"download request failed");return o}async upload(e,n){const s=dt(),o=await this.daemon.request("file_upload_request",{path:e,transferId:s});if(!o.ok||o.stream===void 0)throw new Error(o.error??"upload request failed");const r=o.stream;this.daemon.sendBinary(tt({opcode:"Begin",stream:r,meta:{transferId:s}}));for(let a=0;a<n.length;a+=Tt){const c=n.subarray(a,a+Tt);this.daemon.sendBinary(tt({opcode:"Chunk",stream:r,data:c}))}this.daemon.sendBinary(tt({opcode:"End",stream:r,ok:!0}))}dispatch(e){const n=this.pending.get(e.stream);if(n)switch(e.opcode){case"Begin":n.meta.fileName=e.meta.fileName,n.meta.mimeType=e.meta.mimeType;return;case"Chunk":n.chunks.push(e.data);return;case"End":this.pending.delete(e.stream),e.ok?n.resolve({bytes:ta(n.chunks),...n.meta}):n.reject(new Error("download failed"));return;case"Error":this.pending.delete(e.stream),n.reject(new Error(e.message));return}}}class sa{constructor(e,n={}){I(this,"initialDelayMs");I(this,"maxDelayMs");I(this,"factor");I(this,"jitter");I(this,"maxAttempts");I(this,"setTimer");I(this,"clearTimer");I(this,"random");I(this,"attempt",0);I(this,"timer",null);I(this,"active",!1);I(this,"detachState",null);I(this,"reconnectedHandlers",new Set);I(this,"failedHandlers",new Set);this.daemon=e,this.initialDelayMs=n.initialDelayMs??500,this.maxDelayMs=n.maxDelayMs??3e4,this.factor=n.factor??2,this.jitter=n.jitter??.2,this.maxAttempts=n.maxAttempts??Number.POSITIVE_INFINITY,this.setTimer=n.setTimer??((s,o)=>setTimeout(s,o)),this.clearTimer=n.clearTimer??(s=>clearTimeout(s)),this.random=n.random??Math.random}delayForAttempt(e){const n=Math.min(this.maxDelayMs,this.initialDelayMs*this.factor**(e-1)),s=n*this.jitter*(this.random()*2-1);return Math.max(0,Math.round(n+s))}onReconnected(e){return this.reconnectedHandlers.add(e),()=>this.reconnectedHandlers.delete(e)}onReconnectFailed(e){return this.failedHandlers.add(e),()=>this.failedHandlers.delete(e)}start(){this.active||(this.active=!0,this.detachState=this.daemon.onStateChange(e=>{e==="closed"&&this.active&&this.scheduleReconnect(),e==="open"&&(this.attempt=0)}))}stop(){var e;this.active=!1,this.timer&&this.clearTimer(this.timer),this.timer=null,(e=this.detachState)==null||e.call(this),this.detachState=null}get attemptCount(){return this.attempt}scheduleReconnect(){if(!this.active||this.attempt>=this.maxAttempts)return;this.attempt+=1;const e=this.delayForAttempt(this.attempt);this.timer=this.setTimer(()=>{this.timer=null,this.tryReconnect()},e)}async tryReconnect(){if(!this.active)return;const e=this.attempt;try{await this.daemon.connect();for(const n of this.reconnectedHandlers)n({attempt:e,serverId:this.daemon.serverId})}catch(n){for(const s of this.failedHandlers)s(n,e);this.scheduleReconnect()}}}function Nt(t){const e=t.trim();if(e==="")return e;const n=e.match(/^([a-z][a-z0-9+.-]*):\/\//i);if(!n)return`ws://${e.replace(/\/+$/,"")}`;const s=n[1].toLowerCase(),o=e.slice(n[0].length).replace(/\/+$/,"");switch(s){case"http":return`ws://${o}`;case"https":return`wss://${o}`;case"ws":case"wss":return`${s}://${o}`;default:return e}}function oa(t){const e=Kr(t);return e!=null&&e.relay?{mode:"relay",url:Lr(e.relay),daemonPublicKey:e.publicKey}:e!=null&&e.host?{mode:"direct",url:Nt(e.host)}:{mode:"direct",url:Nt(t)}}function ra(){return"web-"+Math.random().toString(36).slice(2,10)}const C=pe()((t,e)=>({status:"idle",serverInfo:null,error:null,daemon:null,client:null,reconnection:null,async connect(n){e().disconnect();const s=oa(n.url);let o;s.mode==="relay"?o=Ur({daemonPublicKey:s.daemonPublicKey}):n.password&&(o=fn(d=>new WebSocket(d,[`pi-studio.bearer.${n.password}`])));const r=new Jr({url:s.url,clientId:n.clientId??ra(),clientType:"browser",capabilities:{},transport:o,rpcTimeoutMs:1800*1e3}),a=new Yr(r),c=new sa(r);r.onStateChange(d=>t({status:d})),c.onReconnected(()=>t({error:null})),c.onReconnectFailed(d=>{t({error:d instanceof Error?d.message:String(d)})}),t({daemon:r,client:a,reconnection:c,error:null,status:"connecting"});try{const d=await r.connect();t({serverInfo:d}),c.start()}catch(d){throw t({error:d instanceof Error?d.message:String(d)}),d}},disconnect(){const{daemon:n,reconnection:s}=e();s==null||s.stop(),n==null||n.close(),t({status:"idle",serverInfo:null,daemon:null,client:null,reconnection:null})}})),aa=100,ia=480,ca=220,la=280;function Pe(t){return Math.min(ia,Math.max(aa,t))}const k=pe()(t=>({host:"ws://127.0.0.1:6767",password:"",cwd:"~",cwdPickerOpen:!1,sessionMenu:null,fileMenu:null,rightSidebarTab:"files",collapsedWorkspaces:new Set,leftSidebarCollapsed:!1,rightSidebarCollapsed:!1,leftSidebarWidth:ca,rightSidebarWidth:la,setHost:e=>t({host:e}),setPassword:e=>t({password:e}),setCwd:e=>t({cwd:e}),openCwdPicker:()=>t({cwdPickerOpen:!0}),closeCwdPicker:()=>t({cwdPickerOpen:!1}),openSessionMenu:(e,n,s)=>t({sessionMenu:{sessionId:e,x:n,y:s}}),closeSessionMenu:()=>t({sessionMenu:null}),openFileMenu:(e,n,s,o)=>t({fileMenu:{path:e,isDirectory:n,x:s,y:o}}),closeFileMenu:()=>t({fileMenu:null}),setRightSidebarTab:e=>t({rightSidebarTab:e}),toggleWorkspaceCollapsed:e=>t(n=>{const s=new Set(n.collapsedWorkspaces);return s.has(e)?s.delete(e):s.add(e),{collapsedWorkspaces:s}}),toggleLeftSidebar:()=>t(e=>({leftSidebarCollapsed:!e.leftSidebarCollapsed})),toggleRightSidebar:()=>t(e=>({rightSidebarCollapsed:!e.rightSidebarCollapsed})),setLeftSidebarWidth:e=>t({leftSidebarWidth:Pe(e)}),setRightSidebarWidth:e=>t({rightSidebarWidth:Pe(e)}),resizeLeftSidebar:e=>t(n=>({leftSidebarWidth:Pe(n.leftSidebarWidth+e)})),resizeRightSidebar:e=>t(n=>({rightSidebarWidth:Pe(n.rightSidebarWidth+e)}))})),da="_wrap_emmus_1",ua="_dot_emmus_8",pa="_open_emmus_15",fa="_connecting_emmus_18",ha="_closed_emmus_21",ma="_idle_emmus_22",ga="_closing_emmus_23",nt={wrap:da,dot:ua,open:pa,connecting:fa,closed:ha,idle:ma,closing:ga},_a={idle:"disconnected",connecting:"connecting…",open:"connected",closing:"disconnecting…",closed:"disconnected"};function ya(){const t=C(n=>n.status),e=C(n=>n.error);return i.jsxs("span",{className:nt.wrap,title:e??void 0,children:[i.jsx("span",{className:A(nt.dot,nt[t])}),_a[t]??t]})}const ba="_toolbar_i9hmh_1",wa="_brand_i9hmh_10",Sa="_version_i9hmh_16",xa="_sep_i9hmh_22",va="_host_i9hmh_28",ka="_password_i9hmh_31",Ia="_sidebarToggles_i9hmh_34",le={toolbar:ba,brand:wa,version:Sa,sep:xa,host:va,password:ka,sidebarToggles:Ia};function ja(){const t=C(h=>h.status),e=C(h=>h.connect),n=C(h=>h.disconnect),s=k(h=>h.host),o=k(h=>h.setHost),r=k(h=>h.password),a=k(h=>h.setPassword),c=k(h=>h.leftSidebarCollapsed),d=k(h=>h.toggleLeftSidebar),m=k(h=>h.rightSidebarCollapsed),f=k(h=>h.toggleRightSidebar),b=t==="open"||t==="connecting";return i.jsxs("div",{className:le.toolbar,children:[i.jsx("span",{className:le.brand,children:"Pi-Studio"}),i.jsxs("span",{className:le.version,children:["v","0.0.41"]}),i.jsx(ya,{}),i.jsx("div",{className:le.sep}),i.jsx(Ue,{className:le.host,value:s,onChange:h=>o(h.target.value),placeholder:"host:port, ws://…/http://…, or a pasted pairing link",disabled:b}),i.jsx(Ue,{className:le.password,type:"password",value:r,onChange:h=>a(h.target.value),placeholder:"password",disabled:b}),t==="open"||t==="connecting"||t==="closing"?i.jsx(F,{size:"sm",onClick:()=>n(),children:"Disconnect"}):i.jsx(F,{size:"sm",variant:"default",onClick:()=>void e({url:s,password:r||void 0}),children:"Connect"}),i.jsxs("div",{className:le.sidebarToggles,children:[i.jsx(F,{size:"sm",variant:"ghost",iconOnly:!0,title:c?"Show sessions sidebar":"Hide sessions sidebar",onClick:()=>d(),children:c?i.jsx(Fn,{size:16}):i.jsx(On,{size:16})}),i.jsx(F,{size:"sm",variant:"ghost",iconOnly:!0,title:m?"Show files/changes sidebar":"Hide files/changes sidebar",onClick:()=>f(),children:m?i.jsx(Pn,{size:16}):i.jsx(zn,{size:16})})]})]})}const ut={rows:[],streamingAssistantIndex:null,streamingReasoningIndex:null,toolIndexByCallId:{}};let Et=0;function re(){return Et+=1,`row-${Et}`}function Ca(t){switch(t.kind){case"shell":return t.command??"";case"read":case"write":return t.path??"";case"edit":return t.path??"";case"search":return t.query??"";case"fetch":return t.url??"";case"task":return t.description??"";default:return""}}function Ta(t,e){return t??`${e.kind}:${Ca(e)}`}function Na(t){return{...t,streamingAssistantIndex:null,streamingReasoningIndex:null}}function Ea(t,e){var r;const n=t.rows.slice();let s=t.streamingAssistantIndex;if(s===null||((r=n[s])==null?void 0:r.kind)!=="assistant"){const a={kind:"assistant",id:re(),text:"",streaming:!0};n.push(a),s=n.length-1}const o=n[s];return!o||o.kind!=="assistant"?t:(n[s]={...o,text:o.text+e},{...t,rows:n,streamingAssistantIndex:s,streamingReasoningIndex:null})}function Ra(t,e){var r;const n=t.rows.slice();let s=t.streamingReasoningIndex;if(s===null||((r=n[s])==null?void 0:r.kind)!=="reasoning"){const a={kind:"reasoning",id:re(),text:"",streaming:!0};n.push(a),s=n.length-1}const o=n[s];return!o||o.kind!=="reasoning"?t:(n[s]={...o,text:o.text+e},{...t,rows:n,streamingReasoningIndex:s,streamingAssistantIndex:null})}function qa(t,e){if(t.kind!==e.kind)return e;const n={...t};for(const[s,o]of Object.entries(e))o!==void 0&&o!==""&&(n[s]=o);return n}function Ma(t,e){var c;const n=Ta(e.callId,e.tool),s=e.status==="completed"||e.status==="error"?e.status:"running",o=t.toolIndexByCallId[n],r=t.rows.slice();if(o!==void 0&&((c=r[o])==null?void 0:c.kind)==="tool"){const d=r[o];return d.kind!=="tool"?t:(r[o]={...d,tool:qa(d.tool,e.tool),status:s},{...t,rows:r,streamingAssistantIndex:null,streamingReasoningIndex:null})}const a={kind:"tool",id:re(),callId:n,tool:e.tool,status:s};return r.push(a),{...t,rows:r,toolIndexByCallId:{...t.toolIndexByCallId,[n]:r.length-1},streamingAssistantIndex:null,streamingReasoningIndex:null}}function _t(t){const e=t.rows.slice();if(t.streamingAssistantIndex!==null){const n=e[t.streamingAssistantIndex];(n==null?void 0:n.kind)==="assistant"&&(e[t.streamingAssistantIndex]={...n,streaming:!1})}if(t.streamingReasoningIndex!==null){const n=e[t.streamingReasoningIndex];(n==null?void 0:n.kind)==="reasoning"&&(e[t.streamingReasoningIndex]={...n,streaming:!1})}return{...t,rows:e,streamingAssistantIndex:null,streamingReasoningIndex:null}}function Ba(t,e){const n=_t(t),s={kind:"error",id:re(),text:e||"turn failed"};return{...n,rows:[...n.rows,s]}}function $a(t){const e=_t(t),n={kind:"system",id:re(),text:"(canceled)"};return{...e,rows:[...e.rows,n]}}function Aa(t,e){const n={kind:"error",id:re(),text:e||"error"};return{...t,rows:[...t.rows,n]}}function Da(t,e,n,s){if(s!==void 0){const r=t.rows.findIndex(a=>a.kind==="user"&&a.pending&&a.clientMessageId===s);if(r!==-1){const a=t.rows.slice(),c=a[r];if((c==null?void 0:c.kind)==="user")return a[r]={...c,text:e,images:n,pending:!1},{...t,rows:a}}}const o={kind:"user",id:re(),text:e,images:n,clientMessageId:s};return{...t,rows:[...t.rows,o]}}function Fa(t,e){let n=!1;const s=t.rows.map(o=>o.kind!=="user"||!o.queued||e.includes(o.text)?o:(n=!0,{...o,queued:!1}));return n?{...t,rows:s}:t}function yn(t,e){switch(e.kind){case"turn_started":return Na(t);case"user_message":return Da(t,e.text??"",e.images,e.messageId);case"assistant_message":return Ea(t,e.text??"");case"reasoning":return Ra(t,e.text??"");case"tool_call":return Ma(t,e);case"turn_completed":return _t(t);case"turn_failed":return Ba(t,e.error);case"turn_canceled":return $a(t);case"error":return Aa(t,e.message);case"queue_update":return Fa(t,e.steering??[]);default:return t}}function Oa(t,e,n,s,o){const r={kind:"user",id:re(),text:n,images:s,clientMessageId:e,pending:!0,queued:o};return{...t,rows:[...t.rows,r]}}function Pa(t,e){const n=t.rows.findIndex(r=>r.kind==="user"&&r.pending&&r.clientMessageId===e);if(n===-1)return t;const s=t.rows.slice(),o=s[n];return(o==null?void 0:o.kind)!=="user"?t:(s[n]={...o,pending:!1,failed:!0},{...t,rows:s})}let Rt=0;function za(){return Rt+=1,`s-${Date.now().toString(36)}-${Rt}`}const T=pe()((t,e)=>({sessions:{},order:[],activeSessionId:null,createSession(n){const s=za(),o={id:s,agentId:null,title:"New chat",status:"idle",cwd:n,timeline:ut,userMessageCount:0};return t(r=>({sessions:{...r.sessions,[s]:o},order:[s,...r.order],activeSessionId:s})),s},hydrate(n){t(s=>s.sessions[n.id]?s:{sessions:{...s.sessions,[n.id]:n},order:[...s.order,n.id]})},bindAgent(n,s){t(o=>{const r=o.sessions[n];return r?{sessions:{...o.sessions,[n]:{...r,agentId:s}}}:o})},setStatus(n,s){t(o=>{const r=o.sessions[n];return r?{sessions:{...o.sessions,[n]:{...r,status:s}}}:o})},setStatusByAgentId(n,s){const o=e().findByAgentId(n);o&&e().setStatus(o.id,s)},setModel(n,s,o){t(r=>{const a=r.sessions[n];return a?{sessions:{...r.sessions,[n]:{...a,model:s,modelProvider:o}}}:r})},setModelByAgentId(n,s,o){const r=e().findByAgentId(n);r&&e().setModel(r.id,s,o)},setTitle(n,s){t(o=>{const r=o.sessions[n];return r?{sessions:{...o.sessions,[n]:{...r,title:s}}}:o})},setCwd(n,s){t(o=>{const r=o.sessions[n];return r?{sessions:{...o.sessions,[n]:{...r,cwd:s}}}:o})},applyStreamEvent(n,s){t(o=>{const r=o.sessions[n];if(!r)return o;const a=yn(r.timeline,s);let c=r.title;if(s.kind==="turn_completed"&&c==="New chat"){const d=a.rows.slice().reverse().find(m=>m.kind==="assistant");d&&d.kind==="assistant"&&d.text&&(c=d.text.slice(0,40)+(d.text.length>40?"…":""))}return{sessions:{...o.sessions,[n]:{...r,timeline:a,title:c}}}})},addOptimisticUserMessage(n,s,o,r,a){t(c=>{const d=c.sessions[n];if(!d)return c;const m=Oa(d.timeline,s,o,r,a);return{sessions:{...c.sessions,[n]:{...d,timeline:m,userMessageCount:d.userMessageCount+1}}}})},markUserMessageFailed(n,s){t(o=>{const r=o.sessions[n];if(!r)return o;const a=Pa(r.timeline,s);return{sessions:{...o.sessions,[n]:{...r,timeline:a}}}})},activate(n){t({activeSessionId:n})},remove(n){t(s=>{const{[n]:o,...r}=s.sessions,a=s.order.filter(d=>d!==n),c=s.activeSessionId===n?a[0]??null:s.activeSessionId;return{sessions:r,order:a,activeSessionId:c}})},findByAgentId(n){return Object.values(e().sessions).find(s=>s.agentId===n)}})),qt=new WeakMap;function Ha(t,e="pi"){const n=qt.get(t);if(n)return n;const s=t.providers.resolveDefaultModel(e).then(o=>({model:o.model,modelProvider:o.modelProvider})).catch(()=>({}));return qt.set(t,s),s}const Le=new Map;function bn(t,e){const n=T.getState().sessions[e];if(!n)return Promise.reject(new Error(`unknown session: ${e}`));if(n.agentId)return Promise.resolve(n.agentId);const s=Le.get(e);if(s)return s;const o=(async()=>{if(!n.model){const d=await Ha(t),m=T.getState().sessions[e];d.model&&m&&!m.model&&T.getState().setModel(e,d.model,d.modelProvider)}const r=T.getState().sessions[e];if(!r)throw new Error(`unknown session: ${e}`);const a={provider:"pi",cwd:r.cwd||"~"};r.model&&(a.model=r.model),r.modelProvider&&(a.modelProvider=r.modelProvider);const c=await t.createAgent({config:a,labels:{}});return T.getState().bindAgent(e,c.agentId),c.agentId})();return Le.set(e,o),o.finally(()=>Le.delete(e)),o}async function Wa(t,e){var o;const n=T.getState().sessions[e];if(!n||n.userMessageCount>0||n.timeline.rows.length>0)return!1;await((o=Le.get(e))==null?void 0:o.catch(()=>{}));const s=T.getState().sessions[e];return s?(s.agentId&&t&&await t.agent(s.agentId).delete().catch(()=>{}),T.getState().remove(e),!0):!1}function st(t,e){return t.filter(n=>n.workspaceCwd===e)}function ze(t){(t==null?void 0:t.kind)==="chat"&&T.getState().activate(t.data.sessionId)}const E=pe()((t,e)=>({tabs:[],activeTabId:null,activeWorkspaceCwd:null,lastActiveTabByWorkspace:{},open(n){const s=e().tabs.find(o=>o.id===n.id);if(s){e().activate(s.id);return}t(o=>({tabs:[...o.tabs,n],activeTabId:n.id,activeWorkspaceCwd:n.workspaceCwd,lastActiveTabByWorkspace:{...o.lastActiveTabByWorkspace,[n.workspaceCwd]:n.id}})),ze(n)},close(n){let s;t(o=>{const r=o.tabs.find(f=>f.id===n);if(!r)return o;const a=o.tabs.findIndex(f=>f.id===n),c=o.tabs.filter(f=>f.id!==n);let d=o.activeTabId;const m={...o.lastActiveTabByWorkspace};if(d===n){const f=st(c,r.workspaceCwd),b=Math.min(a,f.length-1),h=f[b];d=(h==null?void 0:h.id)??null,s=h}if(m[r.workspaceCwd]===n){const f=st(c,r.workspaceCwd)[0];f?m[r.workspaceCwd]=f.id:delete m[r.workspaceCwd]}return{tabs:c,activeTabId:d,lastActiveTabByWorkspace:m}}),ze(s)},activate(n){let s;t(o=>{const r=o.tabs.find(a=>a.id===n);return r?(s=r,{activeTabId:n,activeWorkspaceCwd:r.workspaceCwd,lastActiveTabByWorkspace:{...o.lastActiveTabByWorkspace,[r.workspaceCwd]:n}}):o}),ze(s)},switchWorkspace(n){let s;t(o=>{var m;const r=st(o.tabs,n),a=o.lastActiveTabByWorkspace[n],d=a&&r.some(f=>f.id===a)?a:((m=r[0])==null?void 0:m.id)??null;return s=r.find(f=>f.id===d),{activeWorkspaceCwd:n,activeTabId:d,lastActiveTabByWorkspace:d?{...o.lastActiveTabByWorkspace,[n]:d}:o.lastActiveTabByWorkspace}}),ze(s)},reorder(n,s){t(o=>{const r=o.tabs.findIndex(m=>m.id===n),a=o.tabs.findIndex(m=>m.id===s);if(r===-1||a===-1||r===a)return o;const c=o.tabs.slice(),[d]=c.splice(r,1);return d?(c.splice(a,0,d),{tabs:c}):o})},updateLabel(n,s){t(o=>({tabs:o.tabs.map(r=>r.id===n?{...r,label:s}:r)}))},updateData(n,s){t(o=>({tabs:o.tabs.map(r=>r.id===n?{...r,data:{...r.data,...s}}:r)}))}})),Q={chat:t=>`chat-${t}`,file:t=>`file-${t}`,diff:(t,e)=>`diff-${t}${e?"-staged":""}`,terminal:t=>`term-${t}`};let ot=0;function wn(t){ot+=1,E.getState().open({id:Q.terminal(`new-${ot}`),kind:"terminal",label:`Terminal ${ot}`,closable:!0,data:{slot:null,cwd:t},workspaceCwd:t})}function yt(t){const e=T.getState().createSession(t);E.getState().open({id:Q.chat(e),kind:"chat",label:"New chat",closable:!0,data:{sessionId:e},workspaceCwd:t});const n=C.getState().client;n&&bn(n,e).catch(()=>{})}function pt(t){const e=E.getState().tabs.find(s=>s.id===t);if(E.getState().close(t),(e==null?void 0:e.kind)!=="chat")return;const{sessionId:n}=e.data;Wa(C.getState().client,n)}const oe=pe()(t=>({rootPath:"",expanded:new Set,expandedByRoot:new Map,draft:null,setRoot:e=>t(n=>{const s=new Map(n.expandedByRoot);n.rootPath&&s.set(n.rootPath,n.expanded);const o=s.get(e),r=new Set(o);return r.add(e),{rootPath:e,expanded:r,expandedByRoot:s,draft:null}}),toggle:e=>t(n=>{if(e===n.rootPath)return n;const s=new Set(n.expanded);s.has(e)?s.delete(e):s.add(e);const o=new Map(n.expandedByRoot);return o.set(n.rootPath,s),{expanded:s,expandedByRoot:o}}),startDraft:(e,n)=>t(s=>{const o=new Set(s.expanded);o.add(e);const r=new Map(s.expandedByRoot);return s.rootPath&&r.set(s.rootPath,o),{draft:{parentPath:e,kind:n},expanded:o,expandedByRoot:r}}),cancelDraft:()=>t({draft:null})}));let me=null;const ft=new Set;function La(t){return ft.add(t),()=>ft.delete(t)}async function Qe(t){var e;if(me)return me;try{const n=await t.connection.request("file_explorer_request",{path:"/home"}),o=(((e=n.result)==null?void 0:e.entries)??n.entries??[]).find(r=>r.kind==="directory"||r.type==="directory");me="/home/"+((o==null?void 0:o.name)||"user")}catch{return"/tmp"}for(const n of ft)n(me);return me}function Ua(){return me}async function Ka(t,e){return e==="~"||e.startsWith("~/")?await Qe(t)+e.slice(1):e}function bt(){const t=C(o=>o.client),e=C(o=>o.status),[n,s]=v.useState(Ua());return v.useEffect(()=>La(s),[]),v.useEffect(()=>{!t||e!=="open"||n||Qe(t)},[t,e,n]),n}const Ga="_dot_gfh8u_3",Va="_spinner_gfh8u_16",Mt={dot:Ga,spinner:Va};function Ja(t){const{status:e,requiresAttention:n,attentionReason:s,showInactive:o}=t;if(!e)return null;if(n)switch(s){case"permission":return"statusWarning";case"error":return"statusDanger";case"finished":default:return"statusSuccess"}switch(e){case"running":case"queued":return"accent";case"waiting":return"statusWarning";case"finished":return"statusSuccess";case"error":return"statusDanger";case"idle":case"archived":return o?"foregroundMuted":null}}const Bt=8,Ya={accent:"var(--pi-color-accent)",statusSuccess:"var(--pi-color-statusSuccess)",statusDanger:"var(--pi-color-statusDanger)",statusWarning:"var(--pi-color-statusWarning)",foregroundMuted:"var(--pi-color-foregroundMuted)"};function Xa({className:t,...e}){const n=Ja(e);if(!n)return null;const s=e.status==="running"&&!e.requiresAttention,o=s?"var(--pi-color-accentBright, #a2b4d7)":Ya[n]??"currentColor";return i.jsx("span",{className:`${s?Mt.spinner:Mt.dot}${t?` ${t}`:""}`,style:s?{borderTopColor:o,borderRightColor:o}:{width:Bt,height:Bt,backgroundColor:o},role:"presentation"})}const Qa={initializing:"queued",idle:"idle",running:"running",error:"error",closed:"finished"};function Za(t){return Qa[t]??"idle"}const ei="_wrap_14der_1",ti="_header_14der_7",ni="_list_14der_23",si="_item_14der_28",oi="_active_14der_37",ri="_title_14der_41",ai="_meta_14der_50",ii="_menuBtn_14der_58",ci="_workspaceGroup_14der_76",li="_workspaceHeader_14der_79",di="_workspaceChevron_14der_92",ui="_workspaceIcon_14der_103",pi="_workspaceLabel_14der_107",fi="_workspaceCount_14der_113",hi="_newSessionBtn_14der_118",mi="_workspaceSessions_14der_130",gi="_emptyState_14der_133",$={wrap:ei,header:ti,list:ni,item:si,active:oi,title:ri,meta:ai,menuBtn:ii,workspaceGroup:ci,workspaceHeader:li,workspaceChevron:di,workspaceIcon:ui,workspaceLabel:pi,workspaceCount:fi,newSessionBtn:hi,workspaceSessions:mi,emptyState:gi};function _i({session:t,active:e,onSelect:n,onOpenMenu:s}){return i.jsxs("div",{className:A($.item,e&&$.active),onClick:n,onContextMenu:o=>{o.preventDefault(),s(o.clientX,o.clientY)},children:[i.jsxs("div",{className:$.title,children:[i.jsx(Xa,{status:Za(t.status),showInactive:!0}),i.jsx("span",{children:t.title})]}),i.jsxs("div",{className:$.meta,children:[t.cwd||"~"," · ",t.agentId?t.agentId.slice(0,8):"new"," ·"," ",t.userMessageCount," msgs"]}),i.jsx("button",{type:"button",className:$.menuBtn,title:"Actions",onClick:o=>{o.stopPropagation();const r=o.currentTarget.getBoundingClientRect();s(r.left,r.bottom)},children:i.jsx(Wt,{size:14})})]})}const yi="_trigger_42hju_1",bi="_content_42hju_12",wi="_item_42hju_21",Si="_danger_42hju_38",xi="_sep_42hju_41",Z={trigger:yi,content:bi,item:wi,danger:Si,sep:xi};function vi(){const t=k(g=>g.sessionMenu),e=k(g=>g.closeSessionMenu),n=C(g=>g.client),s=v.useRef(null),[o,r]=v.useState(!1);v.useEffect(()=>{r(t!==null)},[t]);const a=T(g=>t?g.sessions[t.sessionId]:void 0);if(!t)return null;const c=!!(a!=null&&a.agentId)&&(a==null?void 0:a.status)==="running";function d(g){r(g),g||e()}function m(){if(!a)return;const g=window.prompt("Rename:",a.title);if(g!=null&&g.trim()){const _=g.trim();T.getState().setTitle(a.id,_),E.getState().updateLabel(Q.chat(a.id),_),a.agentId&&(n==null||n.agent(a.agentId).update({title:_}).catch(()=>{}))}e()}function f(){a!=null&&a.agentId&&(n==null||n.agent(a.agentId).interrupt().catch(()=>{})),e()}function b(g){T.getState().remove(g),E.getState().close(Q.chat(g))}async function h(){if(a){if(!window.confirm("Archive this agent? It can be resumed later."))return e();if(e(),!a.agentId){b(a.id);return}if(!n){window.alert("Not connected — cannot archive remotely.");return}try{await n.agent(a.agentId).archive(),b(a.id)}catch(g){window.alert(`Failed to archive: ${g instanceof Error?g.message:String(g)}`)}}}async function S(){if(a){if(!window.confirm("Permanently delete this agent? This cannot be undone."))return e();if(e(),!a.agentId){b(a.id);return}if(!n){window.alert("Not connected — cannot delete remotely.");return}try{await n.agent(a.agentId).delete(),b(a.id)}catch(g){window.alert(`Failed to delete: ${g instanceof Error?g.message:String(g)}`)}}}return i.jsxs(Ge,{open:o,onOpenChange:d,modal:!1,children:[i.jsx(Ve,{asChild:!0,children:i.jsx("button",{ref:s,type:"button",className:Z.trigger,style:{left:t.x,top:t.y},"aria-hidden":!0,tabIndex:-1})}),i.jsx(Je,{children:i.jsxs(Ye,{className:Z.content,align:"start",sideOffset:2,children:[i.jsx(G,{className:Z.item,onSelect:m,children:"Rename"}),i.jsx(G,{className:Z.item,disabled:!c,onSelect:f,children:"Stop agent"}),i.jsx(at,{className:Z.sep}),i.jsx(G,{className:`${Z.item} ${Z.danger}`,onSelect:h,children:"Archive"}),i.jsx(G,{className:`${Z.item} ${Z.danger}`,onSelect:S,children:"Delete permanently"})]})})]})}function ki({label:t,cwd:e,sessionCount:n,collapsed:s,onToggleCollapsed:o,onNewSession:r}){return i.jsxs("div",{className:$.workspaceHeader,onClick:o,title:e,children:[i.jsx("button",{type:"button",className:$.workspaceChevron,"aria-label":s?"Expand workspace":"Collapse workspace",onClick:a=>{a.stopPropagation(),o()},children:s?i.jsx(ht,{size:13}):i.jsx(Lt,{size:13})}),i.jsx(Hn,{size:13,className:A($.workspaceIcon)}),i.jsx("span",{className:$.workspaceLabel,children:t}),i.jsx("span",{className:$.workspaceCount,children:n}),i.jsx(F,{size:"xs",variant:"ghost",iconOnly:!0,title:"New conversation",className:$.newSessionBtn,onClick:a=>{a.stopPropagation(),r()},children:i.jsx(Ut,{size:13})})]})}function ye(t,e){return e&&(t==="~"||t.startsWith("~/"))?e+t.slice(1):t}function Sn(t,e,n){const s=new Map;for(const o of t){const r=e[o];if(!r)continue;const a=ye(r.cwd||"~",n),c=s.get(a);c?c.push(r):s.set(a,[r])}return Array.from(s,([o,r])=>({cwd:o,sessions:r}))}function Ii(t){return!t||t==="~"?"~":t.split("/").filter(Boolean).pop()||t}function ji(){const t=T(_=>_.order),e=T(_=>_.sessions),n=T(_=>_.activeSessionId),s=T(_=>_.activate),o=E(_=>_.open),r=C(_=>_.status),a=k(_=>_.openSessionMenu),c=k(_=>_.setCwd),d=k(_=>_.openCwdPicker),m=k(_=>_.collapsedWorkspaces),f=k(_=>_.toggleWorkspaceCollapsed),b=bt();function h(_){const y=ye(_||"~",b);yt(y)}function S(_){s(_);const y=e[_],M=ye((y==null?void 0:y.cwd)||"~",b);y!=null&&y.cwd&&c(y.cwd),o({id:Q.chat(_),kind:"chat",label:(y==null?void 0:y.title)??"Chat",closable:!0,data:{sessionId:_},workspaceCwd:M})}const g=Sn(t,e,b);return i.jsxs("div",{className:$.wrap,children:[i.jsxs("div",{className:$.header,children:[i.jsx("h3",{children:"Workspaces"}),i.jsx(F,{size:"xs",variant:"ghost",iconOnly:!0,title:r!=="open"?"Connect to open a workspace":"Open a workspace folder",disabled:r!=="open",onClick:()=>d(),children:i.jsx(Kt,{size:14})})]}),i.jsxs("div",{className:$.list,children:[g.length===0&&i.jsx("div",{className:$.emptyState,children:r!=="open"?"Not connected":"No workspaces — open a folder to start"}),g.map(_=>{const y=m.has(_.cwd);return i.jsxs("div",{className:$.workspaceGroup,children:[i.jsx(ki,{label:Ii(_.cwd),cwd:_.cwd,sessionCount:_.sessions.length,collapsed:y,onToggleCollapsed:()=>f(_.cwd),onNewSession:()=>h(_.cwd)}),!y&&i.jsx("div",{className:$.workspaceSessions,children:_.sessions.map(M=>i.jsx(_i,{session:M,active:M.id===n,onSelect:()=>S(M.id),onOpenMenu:(V,j)=>a(M.id,V,j)},M.id))})]},_.cwd)})]}),i.jsx(vi,{})]})}const Ci="_strip_8jveh_1",Ti="_tab_8jveh_10",Ni="_active_8jveh_26",Ei="_icon_8jveh_30",Ri="_label_8jveh_35",qi="_close_8jveh_40",Mi="_newTab_8jveh_50",Bi="_content_8jveh_73",$i="_item_8jveh_82",Ai="_itemIcon_8jveh_96",H={strip:Ci,tab:Ti,active:Ni,icon:Ei,label:Ri,close:qi,newTab:Mi,content:Bi,item:$i,itemIcon:Ai},Di={chat:Vt,file:Ln,diff:Wn,terminal:Gt};function Fi({tab:t}){const e=E(f=>f.activeTabId),n=E(f=>f.activate),s=Di[t.kind],{attributes:o,listeners:r,setNodeRef:a,transform:c,transition:d,isDragging:m}=us({id:t.id});return i.jsxs("div",{ref:a,className:A(H.tab,t.id===e&&H.active),style:{transform:ps.Transform.toString(c),transition:d,opacity:m?.5:1},onClick:()=>n(t.id),onAuxClick:f=>{f.button===1&&t.closable&&pt(t.id)},title:t.label,...o,...r,children:[i.jsx("span",{className:H.icon,children:i.jsx(s,{size:13})}),i.jsx("span",{className:H.label,children:t.label}),t.closable&&i.jsx("span",{className:H.close,onClick:f=>{f.stopPropagation(),pt(t.id)},children:i.jsx(rt,{size:12})})]})}function Oi({workspaceCwd:t}){const e=t??"~";return i.jsxs(Ge,{children:[i.jsx(Ve,{asChild:!0,children:i.jsx("button",{type:"button",className:H.newTab,title:"New tab",disabled:!t,children:i.jsx(Ut,{size:14})})}),i.jsx(Je,{children:i.jsxs(Ye,{className:H.content,align:"start",sideOffset:4,children:[i.jsxs(G,{className:H.item,onSelect:()=>yt(e),children:[i.jsx(Vt,{size:13,className:H.itemIcon}),"New chat"]}),i.jsxs(G,{className:H.item,onSelect:()=>wn(e),children:[i.jsx(Gt,{size:13,className:H.itemIcon}),"New terminal"]})]})})]})}function Pi(){const t=E(a=>a.tabs),e=E(a=>a.activeWorkspaceCwd),n=E(a=>a.reorder),s=t.filter(a=>a.workspaceCwd===e),o=os(rs(ds,{activationConstraint:{distance:4}}));function r(a){const{active:c,over:d}=a;!d||c.id===d.id||n(String(c.id),String(d.id))}return i.jsxs("div",{className:H.strip,children:[i.jsx(as,{sensors:o,collisionDetection:is,onDragEnd:r,children:i.jsx(cs,{items:s.map(a=>a.id),strategy:ls,children:s.map(a=>i.jsx(Fi,{tab:a},a.id))})}),i.jsx(Oi,{workspaceCwd:e})]})}const zi="_spinner_1tgzp_3",Hi={spinner:zi},Wi={xs:12,sm:16,md:20,lg:24},Li={xs:1,sm:2,md:2,lg:3};function xn({size:t="md",color:e="currentColor",className:n,"aria-label":s="Loading"}){const o=typeof t=="number"?t:Wi[t],r=typeof t=="number"?2:Li[t];return i.jsx("span",{className:`${Hi.spinner}${n?` ${n}`:""}`,role:"status","aria-label":s,style:{width:o,height:o,borderWidth:r,color:e}})}const Ui=v.lazy(()=>mt(()=>import("./ChatPanel-D_3cLBoK.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13])).then(t=>({default:t.ChatPanel}))),$t=v.lazy(()=>mt(()=>import("./FilePanel-YoyZJ2v2.js").then(t=>t.F),__vite__mapDeps([14,1,7,6,5,2,9,10,15])).then(t=>({default:t.FilePanel}))),Ki=v.lazy(()=>mt(()=>import("./TerminalPanel-rKZq5rWo.js"),__vite__mapDeps([16,1,17,18,7,6,5,2,3,11,12,19])).then(t=>({default:t.TerminalPanel}))),Gi={chat:Ui,file:$t,diff:$t,terminal:Ki},Vi="_area_z7u01_1",Ji="_panel_z7u01_7",Yi="_active_z7u01_14",Xi="_empty_z7u01_17",Qi="_emptyStack_z7u01_25",Zi="_emptyTitle_z7u01_35",ec="_emptyHint_z7u01_39",ee={area:Vi,panel:Ji,active:Yi,empty:Xi,emptyStack:Qi,emptyTitle:Zi,emptyHint:ec};function tc(){const t=E(a=>a.tabs),e=E(a=>a.activeTabId),n=E(a=>a.activeWorkspaceCwd),s=C(a=>a.status),o=k(a=>a.openCwdPicker),r=t.some(a=>a.workspaceCwd===n);return n===null?i.jsx("div",{className:ee.area,children:i.jsxs("div",{className:ee.emptyStack,children:[i.jsx("div",{className:ee.emptyTitle,children:"No workspace open"}),i.jsx("div",{className:ee.emptyHint,children:"Open a project folder to start a chat."}),i.jsx(F,{size:"sm",variant:"secondary",leftIcon:i.jsx(Kt,{size:14}),disabled:s!=="open",title:s!=="open"?"Connect to open a workspace":"Open a workspace folder",onClick:()=>o(),children:"Open Workspace"})]})}):r?i.jsx("div",{className:ee.area,children:t.map(a=>{const c=Gi[a.kind];return i.jsx("div",{className:A(ee.panel,a.id===e&&ee.active),children:i.jsx(v.Suspense,{fallback:i.jsx(xn,{size:"md"}),children:i.jsx(c,{tab:a})})},a.id)})}):i.jsx("div",{className:ee.area,children:i.jsx("div",{className:ee.empty,children:"No open tabs in this workspace"})})}const Me={fileRead:t=>["file","read",t],fileDownload:t=>["file","download",t],fileDiff:(t,e,n)=>["file","diff",t,e,n],explorer:t=>["explorer",t],agentList:()=>["agents","list"],providerModels:t=>["providers","models",t],agentTimeline:t=>["agents","timeline",t]};function nc(t){const e=t.kind==="directory"||t.type==="directory"?"directory":"file";return{name:t.name??"",kind:e,size:t.size,mtimeMs:t.mtimeMs}}function sc(t){return t.slice().sort((e,n)=>e.kind!==n.kind?e.kind==="directory"?-1:1:e.name.localeCompare(n.name))}async function vn(t,e){const s=(await t.connection.request("file_explorer_request",{path:e})).result;if(!s||s.ok===!1)throw new Error(s&&"error"in s?s.error:"explorer request failed");const o="entries"in s?s.entries??[]:[];return{path:s.resolvedPath??e,entries:sc(o.map(nc))}}function oc(t,e=!0){const n=C(s=>s.client);return zt({queryKey:Me.explorer(t),queryFn:()=>{if(!n)throw new Error("not connected");return vn(n,t)},enabled:!!n&&!!t&&e})}function rc(t){const e=C(o=>o.client),n=v.useMemo(()=>Array.from(t),[t]),s=$n({queries:n.map(o=>({queryKey:Me.explorer(o),queryFn:()=>{if(!e)throw new Error("not connected");return vn(e,o)},enabled:!!e&&!!o}))});return v.useMemo(()=>{const o=new Map;return n.forEach((r,a)=>{const c=s[a];o.set(r,{listing:c==null?void 0:c.data,isLoading:!!(c!=null&&c.isLoading),isError:!!(c!=null&&c.isError),error:c==null?void 0:c.error})}),o},[n,s])}const At=new WeakMap;function Dt(t){let e=At.get(t);return e||(e=new na(t),e.start(),At.set(t,e)),e}function ac(t,e,n){const s=new Blob([Uint8Array.from(t)],{type:n||"application/octet-stream"}),o=URL.createObjectURL(s),r=document.createElement("a");r.href=o,r.download=e,r.rel="noopener",document.body.appendChild(r),r.click(),r.remove(),setTimeout(()=>URL.revokeObjectURL(o),0)}function kn(){const t=C(o=>o.daemon),e=Re(),n=v.useCallback(async(o,r)=>{if(!t)throw new Error("not connected");const a=o?`${o}/${r.name}`:r.name,c=new Uint8Array(await r.arrayBuffer());await Dt(t).upload(a,c),await e.invalidateQueries({queryKey:["explorer"]})},[t,e]),s=v.useCallback(async o=>{if(!t)throw new Error("not connected");const r=await Dt(t).download(o);ac(r.bytes,r.fileName||o.split("/").pop()||"download",r.mimeType)},[t]);return{upload:n,saveToDisk:s}}function ic(t,e){return t.endsWith("/")?`${t}${e}`:`${t}/${e}`}function In(t,e,n,s,o,r){var c;(r==null?void 0:r.parentPath)===e&&t.push({kind:"draft",path:`${e}::draft`,depth:n,draftKind:r.kind,parentPath:e});const a=o.get(e);if(!a||a.isLoading){t.push({kind:"loading",path:e,depth:n});return}if(a.isError){const d=a.error instanceof Error?a.error.message:"failed to load";t.push({kind:"error",path:e,depth:n,message:d});return}for(const d of((c=a.listing)==null?void 0:c.entries)??[])cc(t,e,d,n,s,o,r)}function cc(t,e,n,s,o,r,a){const c=ic(e,n.name);if(n.kind!=="directory"){t.push({kind:"file",path:c,name:n.name,depth:s});return}const d=o.has(c);t.push({kind:"directory",path:c,name:n.name,depth:s,expanded:d}),d&&In(t,c,s+1,o,r,a)}function lc(t,e,n,s){if(!t)return[];const o=[];return In(o,t,0,e,n,s),o}const dc="_container_1098n_1",uc="_header_1098n_7",pc="_uploadButton_1098n_14",fc="_hiddenInput_1098n_33",hc="_status_1098n_36",mc="_statusError_1098n_37",gc="_rowAction_1098n_50",_c="_item_1098n_65",yc="_dropOverlay_1098n_68",bc="_list_1098n_83",wc="_chevronSlot_1098n_102",Sc="_chevron_1098n_102",xc="_chevronOpen_1098n_113",vc="_icon_1098n_116",kc="_name_1098n_123",Ic="_dirName_1098n_128",jc="_statusRow_1098n_134",Cc="_statusRowError_1098n_145",Tc="_emptyState_1098n_148",Nc="_draftInput_1098n_154",N={container:dc,header:uc,uploadButton:pc,hiddenInput:fc,status:hc,statusError:mc,rowAction:gc,item:_c,dropOverlay:yc,list:bc,chevronSlot:wc,chevron:Sc,chevronOpen:xc,icon:vc,name:kc,dirName:Ic,statusRow:jc,statusRowError:Cc,emptyState:Tc,draftInput:Nc};function Ec({draftKind:t,indentStyle:e,onSubmit:n,onCancel:s}){const[o,r]=v.useState("");return i.jsxs("div",{className:N.item,style:e,onClick:a=>a.stopPropagation(),children:[i.jsx("span",{className:N.chevronSlot}),i.jsx("span",{className:N.icon,children:t==="directory"?i.jsx(Ee,{size:14}):i.jsx(Jt,{size:14})}),i.jsx("input",{className:N.draftInput,autoFocus:!0,spellCheck:!1,placeholder:t==="directory"?"New folder":"New file",value:o,onChange:a=>r(a.target.value),onKeyDown:a=>{if(a.key==="Enter"){a.preventDefault();const c=o.trim();c?n(c):s()}else a.key==="Escape"&&(a.preventDefault(),s())},onBlur:s})]})}const Rc=14;function qc({row:t,onToggle:e,onOpenFile:n,onContextMenu:s,onSubmitDraft:o,onCancelDraft:r}){const a={paddingLeft:8+t.depth*Rc};if(t.kind==="loading")return i.jsx("div",{className:N.statusRow,style:a,children:"Loading…"});if(t.kind==="error")return i.jsx("div",{className:A(N.statusRow,N.statusRowError),style:a,children:t.message??"failed to load"});if(t.kind==="draft")return i.jsx(Ec,{draftKind:t.draftKind,indentStyle:a,onSubmit:d=>o(t.parentPath,d),onCancel:r});const c=t.kind==="directory";return i.jsxs("div",{className:N.item,style:a,onClick:()=>c?e(t.path):n(t.path),onContextMenu:d=>{d.preventDefault(),s(t.path,c,d.clientX,d.clientY)},children:[i.jsx("span",{className:N.chevronSlot,children:c&&i.jsx(ht,{size:12,className:A(N.chevron,t.expanded&&N.chevronOpen)})}),i.jsx("span",{className:N.icon,children:c?i.jsx(Ee,{size:14}):i.jsx(Jt,{size:14})}),i.jsx("span",{className:c?N.dirName:N.name,children:t.name}),i.jsx("button",{type:"button",className:N.rowAction,title:"Actions",onClick:d=>{d.stopPropagation();const m=d.currentTarget.getBoundingClientRect();s(t.path,c,m.left,m.bottom)},children:i.jsx(Wt,{size:12})})]})}const Mc="_trigger_ngv1a_1",Bc="_content_ngv1a_12",$c="_item_ngv1a_21",Ac="_danger_ngv1a_34",Dc="_sep_ngv1a_37",te={trigger:Mc,content:Bc,item:$c,danger:Ac,sep:Dc};function Fc(){const t=k(g=>g.fileMenu),e=k(g=>g.closeFileMenu),n=C(g=>g.client),s=oe(g=>g.startDraft),{saveToDisk:o}=kn(),r=Re(),a=v.useRef(null),[c,d]=v.useState(!1);if(v.useEffect(()=>{d(t!==null)},[t]),!t)return null;const m=t.path.split("/").pop()||t.path;function f(g){d(g),g||e()}async function b(){if(t){e();try{await o(t.path)}catch(g){window.alert(`Failed to download: ${g instanceof Error?g.message:String(g)}`)}}}async function h(){if(!t)return;const g=t.isDirectory?"folder (and everything inside it)":"file";if(!window.confirm(`Permanently delete this ${g}? "${m}" — this cannot be undone.`))return e();if(e(),!n){window.alert("Not connected — cannot delete remotely.");return}try{const _=await n.connection.request("file_delete_request",{path:t.path});if(!_.ok)throw new Error(_.error??"delete failed");await r.invalidateQueries({queryKey:["explorer"]})}catch(_){window.alert(`Failed to delete: ${_ instanceof Error?_.message:String(_)}`)}}function S(g){if(!t)return;const _=t.isDirectory?t.path:t.path.split("/").slice(0,-1).join("/")||"/";e(),s(_,g)}return i.jsxs(Ge,{open:c,onOpenChange:f,modal:!1,children:[i.jsx(Ve,{asChild:!0,children:i.jsx("button",{ref:a,type:"button",className:te.trigger,style:{left:t.x,top:t.y},"aria-hidden":!0,tabIndex:-1})}),i.jsx(Je,{children:i.jsxs(Ye,{className:te.content,align:"start",sideOffset:2,children:[i.jsx(G,{className:te.item,onSelect:()=>S("file"),children:"New File"}),i.jsx(G,{className:te.item,onSelect:()=>S("directory"),children:"New Folder"}),i.jsx(at,{className:te.sep}),!t.isDirectory&&i.jsxs(i.Fragment,{children:[i.jsx(G,{className:te.item,onSelect:b,children:"Download"}),i.jsx(at,{className:te.sep})]}),i.jsx(G,{className:`${te.item} ${te.danger}`,onSelect:h,children:"Delete"})]})})]})}const Oc={empty_path:"Choose a folder first.",invalid_name:'Invalid name — cannot be empty or contain "/".',exists:"An item with that name already exists here.",not_found:"That folder no longer exists.",not_a_directory:"That path is not a folder.",unreadable:"That folder is not readable."};async function jn(t,e,n,s){const o=await t.connection.request("file_create_request",{path:e,name:n,kind:s});if(!o.ok){const r=o.error??"";throw new Error(Oc[r]??r??"Failed to create")}return o.path??(e.endsWith("/")?`${e}${n}`:`${e}/${n}`)}const Pc=24;function zc(){const t=C(p=>p.client),e=oe(p=>p.rootPath),n=oe(p=>p.expanded),s=oe(p=>p.setRoot),o=oe(p=>p.toggle),r=oe(p=>p.draft),a=oe(p=>p.startDraft),c=oe(p=>p.cancelDraft),d=E(p=>p.activeWorkspaceCwd),m=E(p=>p.open),{upload:f}=kn(),b=k(p=>p.openFileMenu),h=Re(),[S,g]=v.useState(null),[_,y]=v.useState(!1),[M,V]=v.useState(null),j=v.useRef(null),Be=v.useRef(null),be=v.useRef(null);v.useEffect(()=>{if(!t)return;const p=d||"~";be.current!==p&&(be.current=p,Ka(t,p).then(R=>s(R)))},[t,d,s]);const fe=rc(n),ae=v.useMemo(()=>lc(e,n,fe,r),[e,n,fe,r]),ie=An({count:ae.length,getScrollElement:()=>Be.current,estimateSize:()=>Pc,overscan:12,getItemKey:p=>{var R;return((R=ae[p])==null?void 0:R.path)??p}});function ce(p){m({id:Q.file(p),kind:"file",label:p.split("/").pop()||p,closable:!0,data:{path:p},workspaceCwd:d||"~"})}async function Ze(p,R){const P=(r==null?void 0:r.kind)??"file";if(c(),!!t)try{const W=await jn(t,p,R,P);await h.invalidateQueries({queryKey:Me.explorer(p)}),g({text:`Created ${W}`,error:!1}),P==="file"&&ce(W)}catch(W){g({text:W instanceof Error?W.message:"Failed to create",error:!0})}}async function we(p,R){var Ae;if(!R.length||!p)return;const P=(Ae=fe.get(p))==null?void 0:Ae.listing,W=new Set((P==null?void 0:P.entries.map(J=>J.name))??[]),Se=R.filter(J=>W.has(J.name));if(Se.length>0){const J=Se.map(Nn=>Nn.name).join(", ");if(!window.confirm(`Overwrite ${Se.length>1?"these files":"this file"}? ${J}`))return}g({text:`Uploading ${R.length} file${R.length>1?"s":""}…`,error:!1});try{for(const J of R)await f(p,J);g({text:`Uploaded ${R.length} file${R.length>1?"s":""}`,error:!1})}catch(J){g({text:`Upload failed: ${J instanceof Error?J.message:"unknown"}`,error:!0})}}function $e(p){p.preventDefault(),y(!1);const R=M??e;V(null);const P=Array.from(p.dataTransfer.files);we(R,P)}function et(p){p.dataTransfer.types.includes("Files")&&(p.preventDefault(),y(!0))}return t?i.jsxs("div",{className:N.container,onDragOver:et,onDragLeave:()=>y(!1),onDrop:$e,children:[i.jsxs("div",{className:N.header,children:[i.jsx("button",{type:"button",className:N.uploadButton,onClick:()=>a(e,"file"),disabled:!e,title:"New file in workspace root",children:i.jsx(Un,{size:12})}),i.jsx("button",{type:"button",className:N.uploadButton,onClick:()=>a(e,"directory"),disabled:!e,title:"New folder in workspace root",children:i.jsx(Yt,{size:12})}),i.jsxs("button",{type:"button",className:N.uploadButton,onClick:()=>{var p;return(p=j.current)==null?void 0:p.click()},disabled:!e,title:"Upload files to the workspace root",children:[i.jsx(Kn,{size:12}),i.jsx("span",{children:"Upload"})]}),i.jsx("input",{ref:j,type:"file",multiple:!0,className:N.hiddenInput,onChange:p=>{we(e,Array.from(p.target.files??[])),p.target.value=""}})]}),S&&i.jsx("div",{className:S.error?N.statusError:N.status,children:S.text}),i.jsxs("div",{className:N.list,ref:Be,children:[ae.length===0&&i.jsx("div",{className:N.emptyState,children:"No files loaded"}),i.jsx("div",{style:{position:"relative",height:ie.getTotalSize()},children:ie.getVirtualItems().map(p=>{const R=ae[p.index];return R?i.jsx("div",{"data-index":p.index,style:{position:"absolute",top:0,left:0,width:"100%",height:p.size,transform:`translateY(${p.start}px)`},onDragEnter:()=>{R.kind==="directory"&&V(R.path)},children:i.jsx(qc,{row:R,onToggle:o,onOpenFile:ce,onContextMenu:(P,W,Se,Ae)=>b(P,W,Se,Ae),onSubmitDraft:(P,W)=>void Ze(P,W),onCancelDraft:c})},p.key):null})})]}),_&&i.jsx("div",{className:N.dropOverlay,children:"Drop to upload"}),i.jsx(Fc,{})]}):i.jsx("div",{className:N.emptyState,children:"Connect to browse files"})}const Ft={available:!1,branch:null,upstream:null,ahead:0,behind:0,detached:!1,conflictCount:0},X=pe()(t=>({subscribedCwd:null,changes:[],...Ft,setSubscribedCwd:e=>t({subscribedCwd:e}),applyProjection:e=>{if(!e||!e.available){t({changes:[],...Ft});return}const n=[];for(const s of e.staged)n.push({path:s.path,status:s.indexStatus==="A"?"added":s.indexStatus==="D"?"deleted":"modified",staged:!0});for(const s of e.unstaged)n.push({path:s.path,status:s.worktreeStatus==="D"?"deleted":"modified",staged:!1});for(const s of e.untracked)n.push({path:s,status:"added",staged:!1});t({changes:n,available:!0,branch:e.branch,upstream:e.upstream,ahead:e.ahead,behind:e.behind,detached:e.detached,conflictCount:e.conflicted.length})}})),Hc="_list_1pgby_1",Wc="_summary_1pgby_4",Lc="_item_1pgby_11",Uc="_badge_1pgby_23",Kc="_added_1pgby_30",Gc="_modified_1pgby_34",Vc="_deleted_1pgby_38",Jc="_name_1pgby_42",Yc="_emptyState_1pgby_47",de={list:Hc,summary:Wc,item:Lc,badge:Uc,added:Kc,modified:Gc,deleted:Vc,name:Jc,emptyState:Yc},Xc={added:"A",modified:"M",deleted:"D"};function Qc(){const e=E(r=>r.activeWorkspaceCwd)||"~",n=X(r=>r.changes),s=E(r=>r.open);function o(r,a){s({id:Q.diff(r,a),kind:"diff",label:r.split("/").pop()||r,closable:!0,data:{path:r,staged:a},workspaceCwd:e})}return n.length===0?i.jsx("div",{className:de.emptyState,children:"No changes detected"}):i.jsxs("div",{className:de.list,children:[i.jsxs("div",{className:de.summary,children:[n.length," changed file",n.length===1?"":"s"]}),n.map((r,a)=>i.jsxs("div",{className:de.item,onClick:()=>o(r.path,r.staged),children:[i.jsx("span",{className:A(de.badge,de[r.status]),children:Xc[r.status]}),i.jsx("span",{className:de.name,children:r.path})]},`${r.path}-${r.staged}-${a}`))]})}const Zc="_wrap_r37ok_1",el="_tabBar_r37ok_7",tl="_tabBtn_r37ok_13",nl="_active_r37ok_26",sl="_refreshBtn_r37ok_30",ol="_content_r37ok_34",se={wrap:Zc,tabBar:el,tabBtn:tl,active:nl,refreshBtn:sl,content:ol};function rl(){const t=k(c=>c.rightSidebarTab),e=k(c=>c.setRightSidebarTab),s=E(c=>c.activeWorkspaceCwd)||"~",o=C(c=>c.client),r=Re();function a(){r.invalidateQueries({queryKey:["explorer"]}),o&&s&&o.connection.request("checkout_refresh_request",{cwd:s}).catch(()=>{})}return i.jsxs("div",{className:se.wrap,children:[i.jsxs("div",{className:se.tabBar,children:[i.jsx("button",{type:"button",className:A(se.tabBtn,t==="files"&&se.active),onClick:()=>e("files"),children:"Files"}),i.jsx("button",{type:"button",className:A(se.tabBtn,t==="changes"&&se.active),onClick:()=>e("changes"),children:"Changes"}),i.jsx(F,{size:"xs",variant:"ghost",iconOnly:!0,title:"Refresh",className:se.refreshBtn,onClick:a,children:i.jsx(Gn,{size:13})})]}),i.jsx("div",{className:se.content,children:t==="files"?i.jsx(zc,{}):i.jsx(Qc,{})})]})}const Cn=pe()(t=>({bySession:{},setStats(e,n){t(s=>({bySession:{...s.bySession,[e]:{...s.bySession[e],...n}}}))},clear(e){t(n=>{const{[e]:s,...o}=n.bySession;return{bySession:o}})}})),al=12e3;function il(t,e){return t==="running"&&e!=="running"}function Ot(t,e){var s,o,r,a,c,d;const n={};((s=e.contextUsage)==null?void 0:s.tokens)!=null&&(n.contextTokens=e.contextUsage.tokens),((o=e.contextUsage)==null?void 0:o.contextWindow)!==void 0&&(n.contextWindow=e.contextUsage.contextWindow),((r=e.contextUsage)==null?void 0:r.percent)!=null&&(n.contextPercent=e.contextUsage.percent),((a=e.tokens)==null?void 0:a.total)!==void 0&&(n.totalTokens=e.tokens.total),((c=e.tokens)==null?void 0:c.input)!==void 0&&(n.inputTokens=e.tokens.input),((d=e.tokens)==null?void 0:d.output)!==void 0&&(n.outputTokens=e.tokens.output),e.cost!==void 0&&(n.cost=e.cost),e.model!==void 0&&(n.model=e.model,T.getState().setModel(t,e.model)),Cn.getState().setStats(t,n)}function cl(t){const e=C(c=>c.client),n=C(c=>c.status),s=T(c=>{var d;return t?((d=c.sessions[t])==null?void 0:d.agentId)??null:null}),o=T(c=>{var d;return t?(d=c.sessions[t])==null?void 0:d.status:void 0}),r=v.useRef(!1),a=v.useRef(void 0);v.useEffect(()=>{if(n!=="open"||!e||!t||!s)return;let c=!1;const d=async()=>{if(!r.current){r.current=!0;try{const f=await e.agent(s).sessionStats();c||Ot(t,f)}catch{}finally{r.current=!1}}};d();const m=setInterval(()=>void d(),al);return()=>{c=!0,clearInterval(m)}},[n,e,t,s]),v.useEffect(()=>{const c=a.current;a.current=o,il(c,o)&&(n!=="open"||!e||!t||!s||(r.current=!1,e.agent(s).sessionStats().then(d=>Ot(t,d)).catch(()=>{})))},[o,n,e,t,s])}function ll(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="checkout_status_update"&&"cwd"in t&&typeof t.cwd=="string"&&"projection"in t&&typeof t.projection=="object"&&t.projection!==null}function dl(t){const e=C(r=>r.client),n=X(r=>r.applyProjection),s=X(r=>r.setSubscribedCwd),o=v.useRef(e);return o.current=e,v.useEffect(()=>{if(!e||!t)return;let r=!1;e.connection.request("checkout_status_subscribe",{cwd:t}).catch(()=>{}),s(t);const a=e.connection.onSessionMessage(c=>{if(r)return;const d=c;ll(d)&&d.cwd===t&&n(d.projection)});return e.connection.request("checkout_refresh_request",{cwd:t}).catch(()=>{}),()=>{r=!0,a(),e.connection.request("checkout_status_unsubscribe",{cwd:t}).catch(()=>{}),s(null)}},[e,t,n,s]),{refresh(){const r=o.current;!r||!t||r.connection.request("checkout_refresh_request",{cwd:t}).catch(()=>{})}}}const wt="--";function Ie(t){return t===void 0?wt:t<1e3?String(t):t<1e6?`${(t/1e3).toFixed(1)}k`:`${(t/1e6).toFixed(1)}M`}function ul(t){if(t==null)return wt;const e=t<=1?t*100:t;return`${Math.round(e)}%`}function pl(t){if(t===void 0)return wt;const e=t<1?4:2;return`$${t.toFixed(e)}`}function fl(t,e){return e?t===e?"~":t.startsWith(`${e}/`)?`~${t.slice(e.length)}`:t:t}function hl(t,e){const n=[];return t>0&&n.push(`↑${t}`),e>0&&n.push(`↓${e}`),n.join(" ")}function ml(t,e=!0){const n=C(s=>s.client);return zt({queryKey:Me.providerModels(t),queryFn:async()=>{if(!n)throw new Error("not connected");return(await n.providers.listModels(t)).models},enabled:!!n&&!!t&&e})}function gl(t,e){if(e.trim()==="")return t;const n=e.toLowerCase();return t.filter(s=>s.label.toLowerCase().includes(n)||s.description!==void 0&&s.description.toLowerCase().includes(n))}function _l(t,e){if(!e)return t;const n=t.find(s=>s.id===e);return n?[n,...t.filter(s=>s.id!==e)]:t}function yl(t){const e=new Set;return t.filter(n=>e.has(n.id)?!1:(e.add(n.id),!0))}const bl="_content_17y31_4",wl="_search_17y31_17",Sl="_list_17y31_35",xl="_item_17y31_40",vl="_checkSlot_17y31_55",kl="_label_17y31_64",Il="_modelId_17y31_70",jl="_state_17y31_77",Cl="_stateError_17y31_86",Y={content:bl,search:wl,list:Sl,item:xl,checkSlot:vl,label:kl,modelId:Il,state:jl,stateError:Cl};function Tl({currentModel:t,provider:e,onSelect:n,renderTrigger:s}){const[o,r]=v.useState(!1),[a,c]=v.useState(""),d=v.useRef(null),{data:m=[],isLoading:f,isError:b,error:h}=ml(e,o),S=yl(_l(m,t));v.useEffect(()=>{var j;o&&(c(""),(j=d.current)==null||j.focus())},[o]);const g=new Map(S.map(j=>[j.id,j.provider])),_=S.map(j=>({value:j.id,label:j.label??j.id,description:j.id})),y=gl(_,a),M=h instanceof Error?h.message:"Failed to load models";function V(j){j.stopPropagation(),j.key==="Escape"&&r(!1)}return i.jsxs(Ge,{open:o,onOpenChange:r,modal:!1,children:[i.jsx(Ve,{asChild:!0,children:s(t)}),i.jsx(Je,{children:i.jsxs(Ye,{className:Y.content,align:"start",sideOffset:4,children:[i.jsx("input",{ref:d,className:Y.search,placeholder:"Search models…",value:a,onChange:j=>c(j.target.value),onKeyDown:V}),f&&i.jsx("div",{className:Y.state,children:i.jsx(xn,{size:"sm"})}),!f&&b&&i.jsx("div",{className:Y.stateError,children:M}),!f&&!b&&y.length===0&&i.jsx("div",{className:Y.state,children:"No models found"}),!f&&!b&&y.length>0&&i.jsx("div",{className:Y.list,children:y.map(j=>i.jsxs(G,{className:Y.item,onSelect:()=>n(j.value,g.get(j.value)),children:[i.jsx("span",{className:Y.checkSlot,"aria-hidden":!0,children:j.value===t&&i.jsx(Xt,{size:14})}),i.jsx("span",{className:Y.label,children:j.label}),i.jsxs("span",{className:Y.modelId,children:["(",j.value,")"]})]},j.value))})]})})]})}const Nl="_statusBar_tm1j6_1",El="_segmentGroup_tm1j6_16",Rl="_chevron_tm1j6_20",ql="_segment_tm1j6_16",Ml="_icon_tm1j6_33",Bl="_modelSegment_tm1j6_39",$l="_modelChevron_tm1j6_63",Al="_text_tm1j6_74",U={statusBar:Nl,segmentGroup:El,chevron:Rl,segment:ql,icon:Ml,modelSegment:Bl,modelChevron:$l,text:Al};function Dl(){const t=T(y=>y.activeSessionId),e=T(y=>t?y.sessions[t]:void 0),n=C(y=>y.client),s=T(y=>y.setModel),o=bt(),r=E(y=>y.activeWorkspaceCwd);dl(r||"");const a=X(y=>y.available),c=X(y=>y.branch),d=X(y=>y.ahead),m=X(y=>y.behind),f=X(y=>y.detached),b=X(y=>y.conflictCount),h=X(y=>y.changes.length),S=Cn(y=>t?y.bySession[t]:void 0);cl(t);const g=[];if(e){const y=fl(e.cwd,o);g.push({key:"cwd",icon:i.jsx(Ee,{size:13}),text:y,title:e.cwd})}if(a){const y=hl(d,m),M=[f?"(detached)":c??"?"];y&&M.push(y),h>0&&M.push(`●${h}`),b>0&&M.push(`⚠${b}`),g.push({key:"branch",icon:i.jsx(Vn,{size:13}),text:M.join(" ")})}if(e){const y=`${ul(S==null?void 0:S.contextPercent)} (${Ie(S==null?void 0:S.contextTokens)}/${Ie(S==null?void 0:S.contextWindow)})`;g.push({key:"context",icon:i.jsx(Jn,{size:13}),text:y}),g.push({key:"tokens",icon:i.jsx(Yn,{size:13}),text:Ie(S==null?void 0:S.totalTokens),title:`in ${Ie(S==null?void 0:S.inputTokens)} / out ${Ie(S==null?void 0:S.outputTokens)}`}),g.push({key:"cost",icon:i.jsx(Xn,{size:13}),text:pl(S==null?void 0:S.cost)})}function _(y,M){t&&(s(t,y,M),!(!n||!M)&&(async()=>{const V=await bn(n,t);await n.agent(V).setModel(M,y)})().catch(()=>{}))}return i.jsxs("div",{className:U.statusBar,children:[e&&i.jsx("span",{className:U.segmentGroup,children:i.jsx(Tl,{currentModel:e.model,provider:"pi",onSelect:_,renderTrigger:y=>i.jsxs("button",{type:"button",className:U.modelSegment,disabled:!n,title:y?`Model: ${y}`:"Select model",children:[i.jsx("span",{className:U.icon,children:i.jsx(Qn,{size:13})}),i.jsx("span",{className:U.text,children:y??"Model"}),i.jsx(Lt,{size:12,className:U.modelChevron,"aria-hidden":"true"})]})})}),g.map((y,M)=>i.jsxs("span",{className:U.segmentGroup,children:[(!!e||M>0)&&i.jsx(ht,{size:12,className:U.chevron,"aria-hidden":"true"}),i.jsxs("span",{className:U.segment,title:y.title,children:[i.jsx("span",{className:U.icon,children:y.icon}),i.jsx("span",{className:U.text,children:y.text})]})]},y.key))]})}const Fl="_wrapper_131x2_3",Ol="_box_131x2_18",Pl="_checkmark_131x2_36",zl="_nativeInput_131x2_41",He={wrapper:Fl,box:Ol,checkmark:Pl,nativeInput:zl};v.forwardRef(function({label:e,checked:n=!1,disabled:s,className:o,onChange:r,...a},c){return i.jsxs("label",{className:He.wrapper,"data-disabled":s||void 0,children:[i.jsx("input",{ref:c,type:"checkbox",className:He.nativeInput,checked:n,disabled:s,onChange:r,...a}),i.jsx("span",{className:He.box,"data-checked":n,"aria-hidden":!0,children:n&&i.jsx(Xt,{size:12,className:He.checkmark})}),e&&i.jsx("span",{children:e})]})});const Hl="_select_vj45v_3",Wl={select:Hl};v.forwardRef(function({options:e,placeholder:n,className:s,...o},r){return i.jsxs("select",{ref:r,className:A(Wl.select,s),...o,children:[n&&i.jsx("option",{value:"",disabled:!0,children:n}),e.map(a=>i.jsx("option",{value:a.value,children:a.label},a.value))]})});const Ll="_overlay_1yaef_1",Ul="_contentWrapper_1yaef_7",Kl="_dialog_1yaef_16",Gl="_header_1yaef_28",Vl="_title_1yaef_36",Jl="_closeBtn_1yaef_43",Yl="_body_1yaef_57",Xl="_footer_1yaef_63",Ql="_bare_1yaef_72",Zl="_bareBody_1yaef_78",ed="_bareCloseBtn_1yaef_82",td="_visuallyHidden_1yaef_101",z={overlay:Ll,contentWrapper:Ul,dialog:Kl,header:Gl,title:Vl,closeBtn:Jl,body:Yl,footer:Xl,bare:Ql,bareBody:Zl,bareCloseBtn:ed,visuallyHidden:td},nd=it;function sd({open:t,onOpenChange:e,title:n,children:s,footer:o,width:r,className:a,bare:c=!1}){return i.jsx(es,{open:t,onOpenChange:e,children:i.jsxs(ts,{children:[i.jsx(ns,{className:z.overlay}),i.jsx("div",{className:z.contentWrapper,children:i.jsxs(ss,{className:A(z.dialog,c&&z.bare,a),style:r!==void 0?{width:r}:void 0,children:[c?i.jsx(St,{className:z.visuallyHidden,children:n}):i.jsxs("div",{className:z.header,children:[i.jsx(St,{className:z.title,children:n}),i.jsx(it,{asChild:!0,children:i.jsx("button",{type:"button",className:z.closeBtn,"aria-label":"Close",children:i.jsx(rt,{size:16})})})]}),i.jsx("div",{className:A(z.body,c&&z.bareBody),children:s}),c&&i.jsx(it,{asChild:!0,children:i.jsx("button",{type:"button",className:z.bareCloseBtn,"aria-label":"Close",children:i.jsx(rt,{size:16})})}),o&&i.jsx("div",{className:z.footer,children:o})]})})]})})}const od="_handle_1ocv1_1",rd={handle:od};function Pt({side:t,onResize:e,className:n}){const s=v.useRef(0),o=v.useCallback(c=>{const d=c.clientX-s.current;s.current=c.clientX,e(t==="left"?d:-d)},[e,t]),r=v.useCallback(c=>{var d,m;window.removeEventListener("pointermove",o),window.removeEventListener("pointerup",r),document.body.style.cursor="",document.body.style.userSelect="",(m=(d=c.target)==null?void 0:d.releasePointerCapture)==null||m.call(d,c.pointerId)},[o]);function a(c){c.preventDefault(),s.current=c.clientX,document.body.style.cursor="col-resize",document.body.style.userSelect="none",window.addEventListener("pointermove",o),window.addEventListener("pointerup",r)}return i.jsx("div",{className:A(rd.handle,n),onPointerDown:a,role:"separator","aria-orientation":"vertical"})}function ad(t,e){const{order:n,sessions:s}=T.getState(),r=Sn(n,s,e).find(a=>a.cwd===t);if(r!=null&&r.sessions[0]){const a=r.sessions[0].id;T.getState().activate(a);const c=T.getState().sessions[a];E.getState().open({id:Q.chat(a),kind:"chat",label:(c==null?void 0:c.title)??"New chat",closable:!0,data:{sessionId:a},workspaceCwd:t})}else yt(t);k.getState().setCwd(t)}const id="_pathRow_trimn_1",cd="_pathInput_trimn_9",ld="_createRow_trimn_13",dd="_createInput_trimn_21",ud="_createError_trimn_25",pd="_list_trimn_30",fd="_item_trimn_37",hd="_name_trimn_49",md="_emptyState_trimn_54",K={pathRow:id,pathInput:cd,createRow:ld,createInput:dd,createError:ud,list:pd,item:fd,name:hd,emptyState:md};function gd(){const t=k(p=>p.cwdPickerOpen),e=k(p=>p.closeCwdPicker),n=E(p=>p.activeWorkspaceCwd),s=k(p=>p.cwd),o=C(p=>p.client),r=bt(),[a,c]=v.useState("/"),[d,m]=v.useState("/"),[f,b]=v.useState(!1),[h,S]=v.useState(""),[g,_]=v.useState(null),[y,M]=v.useState(!1),V=Re();v.useEffect(()=>{if(!t)return;const p=ye(n||s||"~",r);c(p),m(p),ie()},[t,o,n,s]);const{data:j,isLoading:Be,isError:be,error:fe}=oc(a,t&&!!o),ae=((j==null?void 0:j.entries)??[]).filter(p=>p.kind==="directory");function ie(){b(!1),S(""),_(null)}function ce(p){c(p),m(p),ie()}function Ze(){ce(a.split("/").slice(0,-1).join("/")||"/")}function we(){ce(d.trim())}async function $e(){const p=h.trim();if(!(!p||!o||y)){M(!0),_(null);try{const R=await jn(o,a,p,"directory");await V.invalidateQueries({queryKey:Me.explorer(a)}),ce(R)}catch(R){_(R instanceof Error?R.message:"Failed to create folder")}finally{M(!1)}}}function et(){ad(a,r),e()}return i.jsxs(sd,{open:t,onOpenChange:p=>!p&&e(),title:"Open Workspace",footer:i.jsxs(i.Fragment,{children:[i.jsx(nd,{asChild:!0,children:i.jsx(F,{size:"sm",variant:"secondary",children:"Cancel"})}),i.jsx(F,{size:"sm",onClick:et,children:"Open this folder"})]}),children:[i.jsxs("div",{className:K.pathRow,children:[i.jsx(F,{size:"xs",variant:"ghost",iconOnly:!0,title:"Up",onClick:Ze,children:i.jsx(Zn,{size:13})}),i.jsx(Ue,{className:K.pathInput,value:d,onChange:p=>m(p.target.value),onKeyDown:p=>{p.key==="Enter"&&(p.preventDefault(),we())}}),i.jsx(F,{size:"xs",onClick:we,children:"Go"}),i.jsx(F,{size:"xs",variant:"ghost",iconOnly:!0,title:"New folder",disabled:!o||be||f,onClick:()=>{b(!0),S(""),_(null)},children:i.jsx(Yt,{size:13})})]}),f&&i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:K.createRow,children:[i.jsx(Ee,{size:14}),i.jsx(Ue,{className:K.createInput,autoFocus:!0,placeholder:"New folder name",value:h,onChange:p=>S(p.target.value),onKeyDown:p=>{p.key==="Enter"?(p.preventDefault(),$e()):p.key==="Escape"&&(p.preventDefault(),p.stopPropagation(),ie())}}),i.jsx(F,{size:"xs",loading:y,disabled:!h.trim()||y,onClick:()=>void $e(),children:"Create"}),i.jsx(F,{size:"xs",variant:"secondary",onClick:ie,children:"Cancel"})]}),g&&i.jsx("div",{className:K.createError,children:g})]}),i.jsx("div",{className:K.list,children:Be?i.jsx("div",{className:K.emptyState,children:"Loading..."}):be?i.jsxs("div",{className:K.emptyState,children:["Error: ",fe instanceof Error?fe.message:"unknown error"]}):ae.length===0?i.jsx("div",{className:K.emptyState,children:"No subdirectories"}):ae.map(p=>i.jsxs("div",{className:K.item,onClick:()=>ce(a==="/"?`/${p.name}`:`${a}/${p.name}`),children:[i.jsx(Ee,{size:14}),i.jsx("span",{className:K.name,children:p.name})]},p.name))})]})}const _d="_shell_1m1nv_1",yd="_main_1m1nv_7",bd="_sidebarLeft_1m1nv_13",wd="_leftHandle_1m1nv_21",Sd="_center_1m1nv_24",xd="_sidebarRight_1m1nv_31",vd="_rightHandle_1m1nv_39",ue={shell:_d,main:yd,sidebarLeft:bd,leftHandle:wd,center:Sd,sidebarRight:xd,rightHandle:vd};function kd(){const t=k(a=>a.leftSidebarCollapsed),e=k(a=>a.rightSidebarCollapsed),n=k(a=>a.leftSidebarWidth),s=k(a=>a.rightSidebarWidth),o=k(a=>a.resizeLeftSidebar),r=k(a=>a.resizeRightSidebar);return i.jsxs("div",{className:ue.shell,children:[i.jsx(ja,{}),i.jsxs("div",{className:ue.main,children:[!t&&i.jsxs("aside",{className:ue.sidebarLeft,style:{width:n},children:[i.jsx(ji,{}),i.jsx(Pt,{side:"left",className:ue.leftHandle,onResize:o})]}),i.jsxs("div",{className:ue.center,children:[i.jsx(Pi,{}),i.jsx(tc,{})]}),!e&&i.jsxs("aside",{className:ue.sidebarRight,style:{width:s},children:[i.jsx(Pt,{side:"right",className:ue.rightHandle,onResize:r}),i.jsx(rl,{})]})]}),i.jsx(Dl,{}),i.jsx(gd,{})]})}function Id(){const t=v.useRef(!1);v.useEffect(()=>{if(t.current)return;if(t.current=!0,window.location.hash.includes("offer=")){const d=window.location.href;k.getState().setHost(d),C.getState().connect({url:d});return}const e=new URLSearchParams(window.location.search),n=e.get("host"),s=e.get("pair"),o=e.get("password"),r=e.get("cwd"),a=e.get("connect")==="1",c=k.getState();if(s?c.setHost(s):n&&c.setHost(n),o&&c.setPassword(o),r&&c.setCwd(r),s)C.getState().connect({url:s});else if(a){const{host:d,password:m}=k.getState();C.getState().connect({url:d,password:m||void 0})}},[])}function jd(t){return typeof t=="object"&&t!==null&&"kind"in t}function Cd(t){const e=[];for(const n of t)if(jd(n))if(n.kind==="other")n.event&&e.push(n.event);else for(const s of n.events??[])e.push(s);return e}function Td(t){return typeof t.model=="string"}function Nd(){const t=C(s=>s.client),e=C(s=>s.status),n=v.useRef(!1);v.useEffect(()=>{e!=="open"||!t||n.current||(n.current=!0,(async()=>{var f;let s=[];try{s=(await t.connection.request("list_agents_request",{all:!1})).agents??[]}catch{s=[]}s.sort((b,h)=>(h.lastActivity??0)-(b.lastActivity??0));const o=T.getState();for(const b of s){if(o.findByAgentId(b.agentId))continue;let h=ut;try{const g=await t.agent(b.agentId).timeline.fetch({direction:"after",limit:200});h=Cd(g.items).reduce(yn,ut)}catch{}const S=h.rows.length===0;o.hydrate({id:`s-${b.agentId.slice(0,12)}`,agentId:b.agentId,title:b.title||(S?"New chat":(f=b.cwd)==null?void 0:f.split("/").pop())||"Restored",status:b.status??"idle",cwd:b.cwd||"~",timeline:h,userMessageCount:h.rows.filter(g=>g.kind==="user").length,model:b.model,modelProvider:b.modelProvider})}const{order:r,sessions:a}=T.getState(),c=r.length>0?a[r[0]??""]:void 0;if(!c)return;const d=await Qe(t).catch(()=>null),m=ye(c.cwd||"~",d);T.getState().activate(c.id),k.getState().setCwd(c.cwd),E.getState().open({id:Q.chat(c.id),kind:"chat",label:c.title,closable:!0,data:{sessionId:c.id},workspaceCwd:m})})())},[e,t]),v.useEffect(()=>{if(!(e!=="open"||!t))return t.onAgentUpdate(s=>{if(Td(s)){const o=typeof s.modelProvider=="string"?s.modelProvider:void 0;T.getState().setModelByAgentId(s.agentId,s.model,o)}})},[e,t])}function Ed(){const t=C(s=>s.client),e=C(s=>s.status),n=v.useRef(!1);v.useEffect(()=>{e!=="open"||!t||n.current||(n.current=!0,(async()=>{let s=[];try{s=(await t.connection.request("list_terminals_request",{})).terminals??[]}catch{s=[]}if(s.length===0)return;const o=await Qe(t).catch(()=>null),r=E.getState().open;for(const a of s){if(a.closed)continue;const c=ye(a.cwd||"~",o);r({id:Q.terminal(a.slot),kind:"terminal",label:a.name,closable:!0,data:{slot:a.slot,cwd:c},workspaceCwd:c})}})())},[e,t])}function Rd(){v.useEffect(()=>{function t(e){const n=k.getState();if(e.key==="Escape"){n.closeCwdPicker(),n.closeSessionMenu();return}const s=e.ctrlKey||e.metaKey;if(s&&e.key.toLowerCase()==="t"){e.preventDefault(),wn(E.getState().activeWorkspaceCwd||"~");return}if(s&&e.key.toLowerCase()==="w"){const{activeTabId:o,tabs:r}=E.getState();if(!o)return;const a=r.find(c=>c.id===o);(a==null?void 0:a.closable)!==!1&&(e.preventDefault(),pt(o))}}return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[])}function qd(){return Id(),Nd(),Ed(),Rd(),null}function Md(){return i.jsxs(to,{children:[i.jsx(qd,{}),i.jsx(kd,{})]})}const Tn=document.getElementById("root");if(!Tn)throw new Error("Missing #root element");qn.createRoot(Tn).render(i.jsx(v.StrictMode,{children:i.jsx(Md,{})}));export{F as B,sd as D,xn as S,Wd as T,C as a,Ld as b,E as c,Dt as d,bn as e,Me as r,Ca as t,T as u};
|
|
3
|
+
//# sourceMappingURL=index-BTP_UxAo.js.map
|