@av-pi-studio/web-client 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/web/assets/{BinaryFallbackViewer-BVnOJSh_.js → BinaryFallbackViewer-B5XuuZJX.js} +2 -2
  3. package/dist/web/assets/{BinaryFallbackViewer-BVnOJSh_.js.map → BinaryFallbackViewer-B5XuuZJX.js.map} +1 -1
  4. package/dist/web/assets/{ChatPanel-BOR3MYdN.js → ChatPanel-6y4_CIof.js} +2 -2
  5. package/dist/web/assets/{ChatPanel-BOR3MYdN.js.map → ChatPanel-6y4_CIof.js.map} +1 -1
  6. package/dist/web/assets/{CodeView-BJb8T6q4.js → CodeView-Cs8mamsP.js} +2 -2
  7. package/dist/web/assets/{CodeView-BJb8T6q4.js.map → CodeView-Cs8mamsP.js.map} +1 -1
  8. package/dist/web/assets/{FilePanel-lERDJldp.js → FilePanel-DZQ3Ebt0.js} +3 -3
  9. package/dist/web/assets/{FilePanel-lERDJldp.js.map → FilePanel-DZQ3Ebt0.js.map} +1 -1
  10. package/dist/web/assets/{ImageViewer-Cnr0mhRu.js → ImageViewer-4r7WUMsE.js} +2 -2
  11. package/dist/web/assets/{ImageViewer-Cnr0mhRu.js.map → ImageViewer-4r7WUMsE.js.map} +1 -1
  12. package/dist/web/assets/{MarkdownFileViewer-CDHJBxdH.js → MarkdownFileViewer-nYG7CqrM.js} +2 -2
  13. package/dist/web/assets/{MarkdownFileViewer-CDHJBxdH.js.map → MarkdownFileViewer-nYG7CqrM.js.map} +1 -1
  14. package/dist/web/assets/{TerminalPanel-cnkK_YF5.js → TerminalPanel-zbfBqrQA.js} +2 -2
  15. package/dist/web/assets/{TerminalPanel-cnkK_YF5.js.map → TerminalPanel-zbfBqrQA.js.map} +1 -1
  16. package/dist/web/assets/{TextViewer-DWYO-J8z.js → TextViewer-Ck0ZpcxT.js} +2 -2
  17. package/dist/web/assets/{TextViewer-DWYO-J8z.js.map → TextViewer-Ck0ZpcxT.js.map} +1 -1
  18. package/dist/web/assets/{VideoViewer-D2ZnEQoA.js → VideoViewer-Bel4eeXC.js} +2 -2
  19. package/dist/web/assets/{VideoViewer-D2ZnEQoA.js.map → VideoViewer-Bel4eeXC.js.map} +1 -1
  20. package/dist/web/assets/index-DgUa1nu2.js +3 -0
  21. package/dist/web/assets/index-DgUa1nu2.js.map +1 -0
  22. package/dist/web/assets/{use-file-download-BpyWNVxA.js → use-file-download-BdS-AJjX.js} +2 -2
  23. package/dist/web/assets/{use-file-download-BpyWNVxA.js.map → use-file-download-BdS-AJjX.js.map} +1 -1
  24. package/dist/web/index.html +1 -1
  25. package/package.json +3 -3
  26. package/dist/web/assets/index-DnTTpAX5.js +0 -3
  27. package/dist/web/assets/index-DnTTpAX5.js.map +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-DnTTpAX5.js";import{u as m,C as p}from"./CodeView-BJb8T6q4.js";import{M as l}from"./markdown-Biwdm3dP.js";import{p as n}from"./FilePanel-lERDJldp.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-BFXtRv5b.js";import"./vendor-markdown-CpaoCv-a.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-B4H-yHuX.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-CDHJBxdH.js.map
1
+ import{r as d,j as r}from"./vendor-react-BoIQBqDW.js";import{S as c,B as a}from"./index-DgUa1nu2.js";import{u as m,C as p}from"./CodeView-Cs8mamsP.js";import{M as l}from"./markdown-Biwdm3dP.js";import{p as n}from"./FilePanel-DZQ3Ebt0.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-BFXtRv5b.js";import"./vendor-markdown-CpaoCv-a.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-B4H-yHuX.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-nYG7CqrM.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownFileViewer-CDHJBxdH.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
+ {"version":3,"file":"MarkdownFileViewer-nYG7CqrM.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{e as E,a as N,b as T,S as D}from"./index-DnTTpAX5.js";import"./vendor-BFXtRv5b.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-markdown-CpaoCv-a.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,f){this.daemon.sendBinary(E({opcode:"Resize",slot:e,rows:t,cols:f}))}dispatch(e){var f,p,u;const t=this.subscribers.get(e.slot);if(t)switch(e.opcode){case"Output":(f=t.onOutput)==null||f.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",d={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),m=a.useRef(!1),R=a.useRef(!1);return a.useEffect(()=>{if(m.current=!0,!t||b.current!==null||R.current)return()=>{m.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(!m.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=>{m.current&&v(s instanceof Error?s.message:String(s))}).finally(()=>{R.current=!1}),()=>{m.current=!1}},[t,n.id]),a.useEffect(()=>()=>{var s;const r=b.current;r!==null&&((s=S.current)==null||s.connection.request("kill_terminal_request",{slot:r}).catch(()=>{}))},[]),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:d.wrap,children:l.jsxs("div",{className:d.status,children:["Terminal error: ",_]})}):c===null?l.jsx("div",{className:d.wrap,children:l.jsxs("div",{className:d.status,children:[l.jsx(D,{size:"sm"})," Starting terminal…"]})}):l.jsx("div",{className:d.wrap,children:l.jsx("div",{ref:u,className:d.terminal})})}export{te as TerminalPanel};
2
- //# sourceMappingURL=TerminalPanel-cnkK_YF5.js.map
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{e as E,a as N,b as T,S as D}from"./index-DgUa1nu2.js";import"./vendor-BFXtRv5b.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-markdown-CpaoCv-a.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,f){this.daemon.sendBinary(E({opcode:"Resize",slot:e,rows:t,cols:f}))}dispatch(e){var f,p,u;const t=this.subscribers.get(e.slot);if(t)switch(e.opcode){case"Output":(f=t.onOutput)==null||f.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",d={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),m=a.useRef(!1),R=a.useRef(!1);return a.useEffect(()=>{if(m.current=!0,!t||b.current!==null||R.current)return()=>{m.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(!m.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=>{m.current&&v(s instanceof Error?s.message:String(s))}).finally(()=>{R.current=!1}),()=>{m.current=!1}},[t,n.id]),a.useEffect(()=>()=>{var s;const r=b.current;r!==null&&((s=S.current)==null||s.connection.request("kill_terminal_request",{slot:r}).catch(()=>{}))},[]),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:d.wrap,children:l.jsxs("div",{className:d.status,children:["Terminal error: ",_]})}):c===null?l.jsx("div",{className:d.wrap,children:l.jsxs("div",{className:d.status,children:[l.jsx(D,{size:"sm"})," Starting terminal…"]})}):l.jsx("div",{className:d.wrap,children:l.jsx("div",{ref:u,className:d.terminal})})}export{te as TerminalPanel};
2
+ //# sourceMappingURL=TerminalPanel-zbfBqrQA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TerminalPanel-cnkK_YF5.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 useEffect(() => {\n return () => {\n const currentSlot = slotRef.current;\n if (currentSlot === null) return;\n void clientRef.current?.connection\n .request(\"kill_terminal_request\", { slot: currentSlot })\n .catch(() => {});\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-zbfBqrQA.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 useEffect(() => {\n return () => {\n const currentSlot = slotRef.current;\n if (currentSlot === null) return;\n void clientRef.current?.connection\n .request(\"kill_terminal_request\", { slot: currentSlot })\n .catch(() => {});\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-DnTTpAX5.js";import{u as s,C as n}from"./CodeView-BJb8T6q4.js";import{p as o}from"./FilePanel-lERDJldp.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-BFXtRv5b.js";import"./vendor-markdown-CpaoCv-a.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-B4H-yHuX.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-DWYO-J8z.js.map
1
+ import{j as e}from"./vendor-react-BoIQBqDW.js";import{S as i}from"./index-DgUa1nu2.js";import{u as s,C as n}from"./CodeView-Cs8mamsP.js";import{p as o}from"./FilePanel-DZQ3Ebt0.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-BFXtRv5b.js";import"./vendor-markdown-CpaoCv-a.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-B4H-yHuX.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-Ck0ZpcxT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextViewer-DWYO-J8z.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
+ {"version":3,"file":"TextViewer-Ck0ZpcxT.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-DnTTpAX5.js";import{u as a}from"./use-file-download-BpyWNVxA.js";import{p as e}from"./FilePanel-lERDJldp.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-BFXtRv5b.js";import"./vendor-markdown-CpaoCv-a.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-B4H-yHuX.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-D2ZnEQoA.js.map
1
+ import{j as o}from"./vendor-react-BoIQBqDW.js";import{S as t}from"./index-DgUa1nu2.js";import{u as a}from"./use-file-download-BdS-AJjX.js";import{p as e}from"./FilePanel-DZQ3Ebt0.js";import"./vendor-query-CAh-Aqig.js";import"./vendor-BFXtRv5b.js";import"./vendor-markdown-CpaoCv-a.js";import"./vendor-highlight-DaTzDdJW.js";import"./vendor-icons-DUloQbkI.js";import"./vendor-overlays-Bo99M0pM.js";import"./vendor-dnd-D9kA7FgH.js";import"./DiffView-B4H-yHuX.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-Bel4eeXC.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VideoViewer-D2ZnEQoA.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"}
1
+ {"version":3,"file":"VideoViewer-Bel4eeXC.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-6y4_CIof.js","assets/vendor-react-BoIQBqDW.js","assets/vendor-query-CAh-Aqig.js","assets/vendor-icons-DUloQbkI.js","assets/markdown-Biwdm3dP.js","assets/vendor-highlight-DaTzDdJW.js","assets/vendor-markdown-CpaoCv-a.js","assets/vendor-BFXtRv5b.js","assets/markdown-BQwXm0MF.css","assets/DiffView-B4H-yHuX.js","assets/DiffView-CRbeRztO.css","assets/vendor-overlays-Bo99M0pM.js","assets/vendor-dnd-D9kA7FgH.js","assets/ChatPanel-DW5U4HRf.css","assets/FilePanel-DZQ3Ebt0.js","assets/FilePanel-DIInFr3h.css","assets/TerminalPanel-zbfBqrQA.js","assets/vendor-terminal-BhzX2_ts.js","assets/vendor-terminal-DYP7pi_n.css","assets/TerminalPanel-BQj62G6N.css"])))=>i.map(i=>d[i]);
2
+ var bt=Object.defineProperty;var _t=(t,e,n)=>e in t?bt(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var k=(t,e,n)=>_t(t,typeof e!="symbol"?e+"":e,n);import{r as v,j as a,d as wt}from"./vendor-react-BoIQBqDW.js";import{Q as yt,a as St,u as vt,b as xt}from"./vendor-query-CAh-Aqig.js";import{A as c,B as m,C as E,D as We,E as q,F as ce,G as H,H as N,I as y,J as B,K as L,L as ge,M as K}from"./vendor-BFXtRv5b.js";import{L as kt,P as It,a as Ct,b as Tt,c as jt,E as Nt,C as Rt,d as Et,F as At,e as He,f as Bt,S as $t,G as Mt,g as Dt,M as Pt,X as me,A as Le,h as Ue,i as qt,T as zt,R as Ot,j as Ft}from"./vendor-icons-DUloQbkI.js";import{R as Wt,T as Ht,P as Lt,C as Ut,I as le,S as Vt,D as Gt,a as Kt,b as Xt,c as Jt,d as Re,e as ye}from"./vendor-overlays-Bo99M0pM.js";import{u as Yt,a as Zt,D as Qt,c as en,S as tn,h as nn,P as sn,b as rn,C as on}from"./vendor-dnd-D9kA7FgH.js";import{_ as Ce}from"./vendor-highlight-DaTzDdJW.js";import"./vendor-markdown-CpaoCv-a.js";(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const i of o.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&s(i)}).observe(document,{childList:!0,subtree:!0});function n(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(r){if(r.ep)return;r.ep=!0;const o=n(r);fetch(r.href,o)}})();const an=new yt;function Ve(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 cn(t){return Math.max(0,Math.min(255,Math.round(t)))}function ln({r:t,g:e,b:n}){const s=r=>cn(r).toString(16).padStart(2,"0");return`#${s(t)}${s(e)}${s(n)}`}function dn(t){const{r:e,g:n,b:s}=Ve(t),r=o=>{const i=o/255;return i<=.03928?i/12.92:((i+.055)/1.055)**2.4};return .2126*r(e)+.7152*r(n)+.0722*r(s)}function Te(t,e="#18181b",n="#ffffff"){return dn(t)>.45?e:n}function un(t,e){const{r:n,g:s,b:r}=Ve(t),o=Math.max(0,Math.min(1,e));return ln({r:n+(255-n)*o,g:s+(255-s)*o,b:r+(255-r)*o})}function de(t){const e=t.trim().replace(/^#/,"");return(e.length===3||e.length===6)&&!/[^0-9a-fA-F]/.test(e)}const P=(t,e,n,s,r,o,i,l,d,u,g)=>({50:t,100:e,200:n,300:s,400:r,500:o,600:i,700:l,800:d,900:u,950:g}),f={zinc:P("#fafafa","#f4f4f5","#e4e4e7","#d4d4d8","#a1a1aa","#71717a","#52525b","#3f3f46","#27272a","#18181b","#09090b"),gray:P("#f9fafb","#f3f4f6","#e5e7eb","#d1d5db","#9ca3af","#6b7280","#4b5563","#374151","#1f2937","#111827","#030712"),slate:P("#f8fafc","#f1f5f9","#e2e8f0","#cbd5e1","#94a3b8","#64748b","#475569","#334155","#1e293b","#0f172a","#020617"),blue:P("#eff6ff","#dbeafe","#bfdbfe","#93c5fd","#60a5fa","#3b82f6","#2563eb","#1d4ed8","#1e40af","#1e3a8a","#172554"),green:P("#f0fdf4","#dcfce7","#bbf7d0","#86efac","#4ade80","#22c55e","#16a34a","#15803d","#166534","#14532d","#052e16"),red:P("#fef2f2","#fee2e2","#fecaca","#fca5a5","#f87171","#ef4444","#dc2626","#b91c1c","#991b1b","#7f1d1d","#450a0a"),teal:P("#f0fdfa","#ccfbf1","#99f6e4","#5eead4","#2dd4bf","#14b8a6","#0d9488","#0f766e","#115e59","#134e4a","#042f2e"),amber:P("#fffbeb","#fef3c7","#fde68a","#fcd34d","#fbbf24","#f59e0b","#d97706","#b45309","#92400e","#78350f","#451a03"),yellow:P("#fefce8","#fef9c3","#fef08a","#fde047","#facc15","#eab308","#ca8a04","#a16207","#854d0e","#713f12","#422006"),purple:P("#faf5ff","#f3e8ff","#e9d5ff","#d8b4fe","#c084fc","#a855f7","#9333ea","#7e22ce","#6b21a8","#581c87","#3b0764"),orange:P("#fff7ed","#ffedd5","#fed7aa","#fdba74","#fb923c","#f97316","#ea580c","#c2410c","#9a3412","#7c2d12","#431407"),white:"#ffffff",black:"#000000"},pn={statusSuccess:"#16a34a",statusDanger:"#dc2626",statusWarning:"#f59e0b",statusMerged:"#9333ea"},fn={statusSuccess:"#15803d",statusDanger:"#b91c1c",statusWarning:"#d97706",statusMerged:"#7c3aed"};function hn(){return{keyword:f.purple[300],string:f.green[300],number:f.orange[300],boolean:f.orange[300],comment:f.zinc[500],function:f.blue[300],variable:f.zinc[200],type:f.teal[300],class:f.amber[300],constant:f.orange[300],operator:f.zinc[400],punctuation:f.zinc[400],tag:f.red[300],attribute:f.amber[300],property:f.blue[200],regexp:f.teal[300],escape:f.orange[200],heading:f.blue[300],link:f.blue[400],deleted:f.red[400],inserted:f.green[400]}}function mn(){return{keyword:f.purple[700],string:f.green[700],number:f.orange[700],boolean:f.orange[700],comment:f.zinc[500],function:f.blue[700],variable:f.zinc[800],type:f.teal[700],class:f.amber[700],constant:f.orange[700],operator:f.zinc[600],punctuation:f.zinc[600],tag:f.red[700],attribute:f.amber[700],property:f.blue[700],regexp:f.teal[700],escape:f.orange[700],heading:f.blue[700],link:f.blue[600],deleted:f.red[700],inserted:f.green[700]}}function Ge(t,e,n){return{background:t,foreground:e,cursor:n,cursorAccent:t,selectionBackground:"rgba(255,255,255,0.18)",black:f.zinc[900],red:f.red[500],green:f.green[500],yellow:f.amber[500],blue:f.blue[500],magenta:f.purple[500],cyan:f.teal[500],white:f.zinc[300],brightBlack:f.zinc[600],brightRed:f.red[400],brightGreen:f.green[400],brightYellow:f.amber[400],brightBlue:f.blue[400],brightMagenta:f.purple[400],brightCyan:f.teal[400],brightWhite:f.zinc[50]}}function ne(t){const e=f.zinc[50],n=Te(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:f.white,success:t.accent,successForeground:f.white,border:t.border,borderAccent:t.borderAccent,...pn,diffAddition:f.green[400],diffDeletion:f.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:f,syntax:hn(),terminal:Ge(t.surface0,e,t.accent)}}function gn(){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:Te(e),destructive:"#b04138",destructiveForeground:"#ffffff",success:e,successForeground:"#ffffff",border:"#e4e4e7",borderAccent:"#ececf1",...fn,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:f,syntax:mn(),terminal:{...Ge("#ffffff",t,e),selectionBackground:"rgba(0,0,0,0.15)",white:"#ffffff",brightWhite:"#fafafa"}}}const bn={light:"#ffffff",dark:"#3b62b0",zinc:"#808080",midnight:"#4A6BA8",claude:"#D97757",ghostty:"#8caaee"},Ke=["light","dark","zinc","midnight","claude","ghostty"];function _n(t){if(t==="light")return gn();switch(t){case"dark":return ne({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 ne({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 ne({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 ne({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 ne({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 Xe={};for(const t of Ke){const e=t==="light"?"light":"dark";Xe[t]={name:t,colorScheme:e,colors:_n(t),swatch:bn[t]}}const wn=Xe,yn={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},Je={xs:12,code:12,sm:14,base:16,lg:18,xl:20,"2xl":22,"3xl":26,"4xl":34},Sn={normal:"400",medium:"500",semibold:"600",bold:"700"},vn={none:0,sm:2,base:4,md:6,lg:8,xl:12,"2xl":16,full:9999},xn={0:0,1:1,2:2},kn={0:0,50:.5,100:1},In={xs:12,sm:14,md:16,lg:20},Cn={diff:22},Ye='system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',Ze='ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace';function Tn(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 Qe(t){const e=wn[t];return{name:t,colorScheme:e.colorScheme,colors:e.colors,spacing:yn,fontSize:{...Je},fontFamily:{ui:Ye,mono:Ze},lineHeight:{...Cn},iconSize:In,fontWeight:Sn,borderRadius:vn,borderWidth:xn,opacity:kn,shadow:Tn(e.colorScheme),swatch:e.swatch}}const jn=16,Nn=10,Rn=24;function En(t,e){const n=e.themeName??t.name,s=Qe(n),r=e.uiFont&&e.uiFont.trim()!==""?e.uiFont:Ye,o=e.monoFont&&e.monoFont.trim()!==""?e.monoFont:Ze;let i={...s.fontSize};if(e.fontSize!=null){const d=Math.max(Nn,Math.min(Rn,e.fontSize))/jn,u=["xs","code","sm","base","lg","xl","2xl","3xl","4xl"];for(const g of u){const p=Je[g];i[g]=Math.round(p*d)}}return{...s,fontSize:i,fontFamily:{ui:r,mono:o}}}function An(t){return Qe(t)}const Bn="dark";function $n(t){const e={};Mn(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 r=s;e[`--pi-shadow-${n}`]=`${r.offsetX}px ${r.offsetY}px ${r.radius}px ${r.color}`}return e["--pi-color-scheme"]=t.colorScheme,e}function Mn(t,e){const{palette:n,syntax:s,terminal:r,...o}=t;for(const[i,l]of Object.entries(o))typeof l=="string"&&(e[`--pi-color-${i}`]=l);s&&Dn(s,e),r&&(e["--pi-terminal-bg"]=r.background,e["--pi-terminal-fg"]=r.foreground)}function Dn(t,e){for(const[n,s]of Object.entries(t))typeof s=="string"&&(e[`--syntax-${Pn(n)}`]=s)}function Pn(t){return t.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function qn(t){if(typeof document>"u")return;const e=document.documentElement.style;for(const[s,r]of Object.entries(t))e.setProperty(s,r);const n=t["--pi-color-scheme"];n&&document.documentElement.style.setProperty("color-scheme",n)}function zn(t){const e=$n(t);qn(e)}const se=c().min(1,"Asset path must not be empty"),On=m({accent:c().refine(de,{message:"accent must be a valid #rrggbb hex color"}),accentBright:c().refine(de,{message:"accentBright must be a valid #rrggbb hex color"}).optional(),accentForeground:c().refine(de,{message:"accentForeground must be a valid #rrggbb hex color"}).optional(),swatch:c().refine(de,{message:"swatch must be a valid #rrggbb hex color"}).optional()}),Fn=m({logoLight:se,logoDark:se,logoMark:se.optional(),icon:se,splash:se.optional()}),Wn=m({docs:c().url().optional(),support:c().url().optional(),issues:c().url().optional(),website:c().url().optional()}).optional(),Hn=m({copyright:c().optional(),companyName:c().optional()}).optional();m({productName:c().min(1,"productName is required"),shortName:c().optional(),tagline:c().optional(),colors:On,assets:Fn,links:Wn,legal:Hn});function Ln(t){const e=t.accent,n=t.accentBright??un(e,.35),s=t.accentForeground??Te(e),r=t.swatch??e;return{accent:e,accentBright:n,accentForeground:s,swatch:r}}function Un(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 Ee="pi-studio-appearance";function Vn(t,e){let n=l(t),s=null;function r(g){return g==="system"?typeof window<"u"&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":g}function o(g,p){const h=r(g),T=An(h);let w=En(T,{...p,themeName:h});if(e!=null&&e.colors){const b=Ln(e.colors);w=Un(w,b)}return w}function i(){const g=JSON.stringify({mode:n.mode,settings:n.settings});t.set(Ee,g)}function l(g){const p=g.get(Ee);let h=Bn,T={};if(p)try{const b=JSON.parse(p);b.mode&&(Ke.includes(b.mode)||b.mode==="system")&&(h=b.mode),b.settings&&typeof b.settings=="object"&&(T=b.settings)}catch{}const w=o(h,T);return{mode:h,settings:T,resolvedTheme:w}}function d(){n={...n,resolvedTheme:o(n.mode,n.settings)},i()}const u={getState(){return n},setMode(g){n={...n,mode:g},d(),u.apply()},updateSettings(g){n={...n,settings:{...n.settings,...g}},d(),u.apply()},apply(){zn(n.resolvedTheme)},listen(){if(typeof window>"u")return()=>{};const g=window.matchMedia("(prefers-color-scheme: dark)"),p=()=>{n.mode==="system"&&(d(),u.apply())};return g.addEventListener("change",p),s=()=>g.removeEventListener("change",p),s}};return u}function Gn({store:t,brandConfig:e,children:n}){const s=v.useRef(null);return s.current||(s.current=Vn(t,e),s.current.apply()),v.useEffect(()=>s.current.listen(),[]),a.jsx(a.Fragment,{children:n})}const Kn={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 Xn({children:t}){return a.jsx(Gn,{store:Kn,children:a.jsx(St,{client:an,children:t})})}const Jn="_btn_1chbg_4",Yn="_secondary_1chbg_44",Zn="_outline_1chbg_53",Qn="_ghost_1chbg_62",es="_destructive_1chbg_72",ts="_iconOnly_1chbg_82",ns="_loadingSpinner_1chbg_89",ss="_piSpin_1chbg_1",ue={btn:Jn,default:"_default_1chbg_35",secondary:Yn,outline:Zn,ghost:Qn,destructive:es,iconOnly:ts,loadingSpinner:ns,piSpin:ss},Ae={xs:28,sm:32,md:36,lg:40},rs={xs:12,sm:14,md:16,lg:20},Be={xs:8,sm:10,md:12,lg:16},os={xs:12,sm:13,md:14,lg:15};function as(t){const{disabled:e,loading:n}=t;return e||n?{opacity:.5,isGhostHover:!1}:{opacity:1,isGhostHover:!1}}function D({variant:t="default",size:e="md",loading:n=!1,disabled:s=!1,leftIcon:r,trailing:o,iconOnly:i=!1,children:l,style:d,className:u,...g}){const{opacity:p}=as({disabled:s??!1,loading:n}),h=s||n,T=rs[e];return a.jsxs("button",{className:E(ue.btn,ue[t],i&&ue.iconOnly,u),disabled:h,"aria-busy":n||void 0,style:{minHeight:Ae[e],paddingLeft:i?void 0:Be[e],paddingRight:i?void 0:Be[e],fontSize:os[e],opacity:p,...i?{width:Ae[e]}:{},...d},...g,children:[n?a.jsx(kt,{className:ue.loadingSpinner,size:T,"aria-hidden":!0}):r?a.jsx("span",{"aria-hidden":!0,style:{display:"flex",alignItems:"center",flexShrink:0},children:r}):null,l,o&&!n&&a.jsx("span",{"aria-hidden":!0,style:{display:"flex",alignItems:"center",flexShrink:0},children:o})]})}const is="_input_a7qyq_3",cs="_textarea_a7qyq_32",Se={input:is,textarea:cs},ve=v.forwardRef(function({className:e,...n},s){return a.jsx("input",{ref:s,className:E(Se.input,e),...n})}),Oi=v.forwardRef(function({className:e,...n},s){return a.jsx("textarea",{ref:s,className:E(Se.input,Se.textarea,e),...n})}),et=c().datetime({offset:!0});c().uuid();c().regex(/^[A-Za-z0-9_-]+$/,"expected base64url");const ie=We([q(),et]),ls=ce(["mobile","browser","cli","mcp"]),ds=m({type:y("hello"),clientId:c(),clientType:ls,protocolVersion:q(),appVersion:c().optional(),capabilities:H(c(),N()).optional()}),us=m({status:y("server_info"),serverId:c(),hostname:c().optional(),version:c().optional(),capabilities:H(c(),B()),features:H(c(),B())}),ps=m({type:y("status"),payload:us}),fs=m({type:y("ping"),requestId:c(),clientSentAt:ie.optional()}),hs=m({type:y("pong"),requestId:c(),clientSentAt:ie.optional(),serverReceivedAt:ie,serverSentAt:ie}),tt=ce(["initializing","idle","running","error","closed"]),nt=m({mimeType:c().optional(),data:c().optional()}).passthrough(),ms=m({prs:L(B()).optional(),issues:L(B()).optional()}).passthrough(),gs=m({provider:c(),cwd:c(),modeId:c().optional(),model:c().optional(),thinkingOptionId:c().optional(),featureValues:H(c(),B()).optional(),title:c().nullable().optional(),approvalPolicy:c().optional(),sandboxMode:c().optional(),networkAccess:N().optional(),webSearch:N().optional(),extra:m({pi:B().optional()}).passthrough().optional(),systemPrompt:c().optional(),mcpServers:H(c(),B()).optional()}),bs=m({type:y("create_agent_request"),requestId:c(),config:gs,env:H(c(),c()).optional(),workspaceId:c().optional(),worktreeName:c().optional(),initialPrompt:c().optional(),clientMessageId:c().optional(),outputSchema:H(c(),B()).optional(),images:L(nt).optional(),attachments:ms.optional(),git:B().optional(),worktree:B().optional(),autoArchive:N().optional(),labels:H(c(),c()).default({})}),_s=m({type:y("create_agent_response"),requestId:c(),payload:m({agentId:c()}).passthrough()}),ws=m({type:y("agent_update"),agentId:c(),status:tt.optional(),title:c().nullable().optional(),labels:H(c(),c()).optional()}),ys=m({type:y("agent_status"),agentId:c(),status:tt}),Ss=m({type:y("agent_list"),agents:L(m({id:c()}).passthrough())}),vs=m({type:y("agent_deleted"),agentId:c()}),xs=m({type:y("agent_archived"),agentId:c(),archivedAt:et.optional()}),st=ge("kind",[m({kind:y("shell"),command:c().optional(),output:c().optional()}),m({kind:y("read"),path:c().optional(),output:c().optional()}),m({kind:y("edit"),path:c().optional(),diff:c().optional(),output:c().optional()}),m({kind:y("write"),path:c().optional(),output:c().optional()}),m({kind:y("search"),query:c().optional(),output:c().optional()}),m({kind:y("fetch"),url:c().optional(),output:c().optional()}),m({kind:y("task"),description:c().optional(),output:c().optional()})]),ks=ge("kind",[m({kind:y("user_message"),messageId:c().optional(),text:c().optional(),images:L(nt).optional()}),m({kind:y("assistant_message"),messageId:c().optional(),text:c().optional()}),m({kind:y("reasoning"),text:c().optional()}),m({kind:y("tool_call"),callId:c().optional(),tool:st,status:c().optional()}),m({kind:y("turn_started"),turnId:c().optional()}),m({kind:y("turn_completed"),turnId:c().optional()}),m({kind:y("turn_failed"),turnId:c().optional(),error:c().optional()}),m({kind:y("turn_canceled"),turnId:c().optional()}),m({kind:y("error"),message:c().optional()})]),Is=m({type:y("agent_stream"),agentId:c(),seq:q().optional(),timestamp:ie.optional(),event:ks}),Cs=ce(["before","after"]),Ts=m({start:q(),end:q()}),js=m({type:y("fetch_agent_timeline_request"),requestId:c(),agentId:c(),cursor:c().nullable().optional(),direction:Cs,limit:q().optional()}),Ns=m({type:y("fetch_agent_timeline_response"),requestId:c(),agentId:c().optional(),items:L(B()),seqStart:q(),seqEnd:q(),sourceSeqRanges:L(Ts),collapsed:N(),hasNewer:N(),startCursor:c().nullable().optional(),endCursor:c().nullable().optional()}),Rs=m({type:y("agent_permission_request"),requestId:c(),agentId:c(),toolName:c().optional(),tool:st.optional(),action:B().optional(),responses:L(c()).optional()}),Es=m({type:y("agent_permission_resolved"),requestId:c(),agentId:c(),decision:c().optional()}),As=m({type:y("agent.permission.respond.request"),requestId:c(),permissionRequestId:c(),response:B()}),Bs=m({type:y("agent.permission.respond.response"),requestId:c(),payload:m({resolved:N()}).passthrough()}),$s=m({type:y("respond_to_permission"),requestId:c(),permissionRequestId:c(),response:B()}),rt=ce(["conversation","files","both"]),Ms=m({type:y("agent.rewind.request"),requestId:c(),agentId:c(),messageId:c(),mode:rt}).passthrough(),Ds=m({type:y("agent.rewind.response"),requestId:c(),payload:m({agentId:c(),messageId:c(),mode:rt,truncatedAt:c().optional()}).passthrough()}).passthrough(),Ps=m({type:y("rpc_error"),requestId:c(),code:c().optional(),message:c().optional(),error:c().optional()}),qs=ge("type",[bs,_s,ws,ys,Ss,vs,xs,Is,js,Ns,Rs,Es,As,Bs,$s,Ms,Ds,Ps]),zs=m({type:c()}).passthrough(),Os=m({type:y("session"),message:We([qs,zs])});ge("type",[ds,ps,fs,hs,Os]);const Y={Output:1,Input:2,Resize:3,Snapshot:4,Restore:5},Fs=Object.fromEntries(Object.entries(Y).map(([t,e])=>[e,t])),ot=m({rows:q().int().nonnegative(),cols:q().int().nonnegative()});class ae extends Error{constructor(e){super(e),this.name="TerminalFrameError"}}const Ws=new TextEncoder,Hs=new TextDecoder;function Ls(t){if(!Number.isInteger(t)||t<0||t>255)throw new ae(`slot must be an integer 0–255, got ${t}`)}function re(t,e,n){const s=new Uint8Array(2+n.length);return s[0]=t,s[1]=e,s.set(n,2),s}function Fi(t){switch(Ls(t.slot),t.opcode){case"Output":return re(Y.Output,t.slot,t.data);case"Input":return re(Y.Input,t.slot,t.data);case"Snapshot":return re(Y.Snapshot,t.slot,t.data);case"Restore":return re(Y.Restore,t.slot,t.data);case"Resize":{const e=JSON.stringify(ot.parse({rows:t.rows,cols:t.cols}));return re(Y.Resize,t.slot,Ws.encode(e))}}}function Us(t){if(t.length<2)throw new ae(`frame too short: ${t.length} bytes (need ≥ 2)`);const e=t[0],n=t[1],s=Fs[e];if(!s)throw new ae(`unknown terminal opcode 0x${e.toString(16)}`);const r=t.subarray(2);if(s==="Resize"){let o;try{o=JSON.parse(Hs.decode(r))}catch{throw new ae("resize payload is not valid JSON")}const i=ot.safeParse(o);if(!i.success)throw new ae("resize payload is not { rows, cols }");return{opcode:"Resize",slot:n,rows:i.data.rows,cols:i.data.cols}}return{opcode:s,slot:n,data:r.slice()}}const at={Begin:16,Chunk:17,End:18,Error:19},Vs=Object.fromEntries(Object.entries(at).map(([t,e])=>[e,t])),Gs=m({transferId:c(),fileName:c().optional(),mimeType:c().optional(),totalBytes:q().int().nonnegative().optional()});class pe extends Error{constructor(e){super(e),this.name="FileTransferFrameError"}}new TextEncoder;const $e=new TextDecoder;function Ks(t){if(t.length<2)throw new pe(`frame too short: ${t.length} bytes (need ≥ 2)`);const e=t[0],n=t[1],s=Vs[e];if(!s)throw new pe(`unknown file-transfer opcode 0x${e.toString(16)}`);const r=t.subarray(2);switch(s){case"Begin":{let o;try{o=JSON.parse($e.decode(r))}catch{throw new pe("begin payload is not valid JSON")}const i=Gs.safeParse(o);if(!i.success)throw new pe("begin payload is not a valid transfer header");return{opcode:"Begin",stream:n,meta:i.data}}case"Chunk":return{opcode:"Chunk",stream:n,data:r.slice()};case"End":return{opcode:"End",stream:n,ok:(r[0]??1)!==0};case"Error":return{opcode:"Error",stream:n,message:$e.decode(r)}}}function Xs(t){try{return Ks(t)}catch{return null}}const Js=c().regex(/^[a-z][a-z0-9-]*$/,"invalid provider id"),Ys=ce(["safe","moderate","dangerous","planning"]),Zs=m({supportsStreaming:N(),supportsSessionPersistence:N(),supportsDynamicModes:N(),supportsMcpServers:N(),supportsReasoningStream:N(),supportsToolInvocations:N(),supportsRewindConversation:N().optional(),supportsRewindFiles:N().optional(),supportsRewindBoth:N().optional()}).passthrough(),Qs=m({id:c(),label:c().optional(),description:c().optional(),icon:c().optional(),colorTier:Ys});m({id:Js,label:c(),description:c().optional(),extends:c().optional(),modes:L(Qs),capabilities:Zs});function er(t){return typeof t=="string"?t:t instanceof Uint8Array||Buffer.isBuffer(t)?t.toString("utf8"):String(t??"")}function it(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((r,o)=>{const i=t??(()=>new WebSocket(s));try{e=t?i(s):new WebSocket(s)}catch(l){o(l);return}e.onopen=()=>r(),e.onerror=l=>{var d;(e==null?void 0:e.readyState)!==1&&o(l),(d=n.onError)==null||d.call(n,l)},e.onclose=l=>{var d;(d=n.onClose)==null||d.call(n,l.code,er(l.reason))},e.onmessage=l=>{var u,g,p,h;const{data:d}=l;d instanceof ArrayBuffer||d instanceof Uint8Array?(u=n.onMessage)==null||u.call(n,d):typeof d=="string"?(g=n.onMessage)==null||g.call(n,d):typeof Blob<"u"&&d instanceof Blob?(p=n.onMessage)==null||p.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,r=""){e==null||e.close(s,r),e=null}};return n}const tr=1;function Me(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`req-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}class nr extends Error{constructor(e,n,s){super(e),this.requestId=n,this.code=s,this.name="RpcError"}}class De extends Error{constructor(e){super(`RPC ${e} timed out`),this.requestId=e,this.name="RpcTimeoutError"}}class sr{constructor(e){k(this,"transport");k(this,"rpcTimeoutMs");k(this,"now");k(this,"_state","idle");k(this,"_serverId",null);k(this,"_features",{});k(this,"_serverCapabilities",{});k(this,"pending",new Map);k(this,"sessionHandlers",new Set);k(this,"terminalHandlers",new Set);k(this,"fileTransferHandlers",new Set);k(this,"stateHandlers",new Set);k(this,"helloResolve",null);k(this,"helloReject",null);this.options=e,this.transport=e.transport??it(),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,r)=>{this.helloResolve=s,this.helloReject=r});this.transport.sendText(JSON.stringify({type:"hello",clientId:this.options.clientId,clientType:this.options.clientType,protocolVersion:this.options.protocolVersion??tr,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 r=n.requestId??Me();return new Promise((o,i)=>{const l=s??this.rpcTimeoutMs,d=l>0?setTimeout(()=>{this.pending.delete(r),i(new De(r))},l):null;this.pending.set(r,{resolve:u=>o(u),reject:i,timer:d}),this.sendSession({type:e,...n,requestId:r})})}sendSession(e){this.transport.sendText(JSON.stringify({type:"session",message:e}))}sendBinary(e){this.transport.sendBinary(e)}ping(e=1e4){const n=Me();return new Promise((s,r)=>{const o=e>0?setTimeout(()=>{this.pending.delete(n),r(new De(n))},e):null;this.pending.set(n,{resolve:()=>s(),reject:r,timer:o}),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(at).includes(n)){const o=Xs(e);if(!o)return;for(const i of this.fileTransferHandlers)i(o);return}const r=Us(e);for(const o of this.terminalHandlers)o(r)}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 nr(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 rr{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 ar(this.daemon,e)}workspace(e){return new ir(this.daemon,e)}get providers(){return new cr(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 or{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 ar{constructor(e,n){k(this,"timeline");this.daemon=e,this.agentId=n,this.timeline=new or(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})}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)})}}class ir{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 cr{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})}refreshSnapshot(){return this.daemon.request("providers.snapshot.refresh.request",{})}}class lr{constructor(e,n={}){k(this,"initialDelayMs");k(this,"maxDelayMs");k(this,"factor");k(this,"jitter");k(this,"maxAttempts");k(this,"setTimer");k(this,"clearTimer");k(this,"random");k(this,"attempt",0);k(this,"timer",null);k(this,"active",!1);k(this,"detachState",null);k(this,"reconnectedHandlers",new Set);k(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,r)=>setTimeout(s,r)),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 dr(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(),r=e.slice(n[0].length).replace(/\/+$/,"");switch(s){case"http":return`ws://${r}`;case"https":return`wss://${r}`;case"ws":case"wss":return`${s}://${r}`;default:return e}}function ur(){return"web-"+Math.random().toString(36).slice(2,10)}const C=K()((t,e)=>({status:"idle",serverInfo:null,error:null,daemon:null,client:null,reconnection:null,async connect(n){e().disconnect();const s=n.password?it(l=>new WebSocket(l,[`pi-studio.bearer.${n.password}`])):void 0,r=new sr({url:dr(n.url),clientId:n.clientId??ur(),clientType:"browser",capabilities:{},transport:s,rpcTimeoutMs:1800*1e3}),o=new rr(r),i=new lr(r);r.onStateChange(l=>t({status:l})),i.onReconnected(()=>t({error:null})),i.onReconnectFailed(l=>{t({error:l instanceof Error?l.message:String(l)})}),t({daemon:r,client:o,reconnection:i,error:null,status:"connecting"});try{const l=await r.connect();t({serverInfo:l}),i.start()}catch(l){throw t({error:l instanceof Error?l.message:String(l)}),l}},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})}})),pr=100,fr=480,hr=220,mr=280;function fe(t){return Math.min(fr,Math.max(pr,t))}const x=K()(t=>({host:"ws://127.0.0.1:6767",password:"",cwd:"~",cwdPickerOpen:!1,sessionMenu:null,rightSidebarTab:"files",collapsedWorkspaces:new Set,leftSidebarCollapsed:!1,rightSidebarCollapsed:!1,leftSidebarWidth:hr,rightSidebarWidth:mr,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}),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:fe(e)}),setRightSidebarWidth:e=>t({rightSidebarWidth:fe(e)}),resizeLeftSidebar:e=>t(n=>({leftSidebarWidth:fe(n.leftSidebarWidth+e)})),resizeRightSidebar:e=>t(n=>({rightSidebarWidth:fe(n.rightSidebarWidth+e)}))})),gr="_wrap_emmus_1",br="_dot_emmus_8",_r="_open_emmus_15",wr="_connecting_emmus_18",yr="_closed_emmus_21",Sr="_idle_emmus_22",vr="_closing_emmus_23",be={wrap:gr,dot:br,open:_r,connecting:wr,closed:yr,idle:Sr,closing:vr},xr={idle:"disconnected",connecting:"connecting…",open:"connected",closing:"disconnecting…",closed:"disconnected"};function kr(){const t=C(n=>n.status),e=C(n=>n.error);return a.jsxs("span",{className:be.wrap,title:e??void 0,children:[a.jsx("span",{className:E(be.dot,be[t])}),xr[t]??t]})}const Ir="_toolbar_12zzc_1",Cr="_brand_12zzc_10",Tr="_sep_12zzc_16",jr="_host_12zzc_22",Nr="_password_12zzc_25",Rr="_sidebarToggles_12zzc_28",J={toolbar:Ir,brand:Cr,sep:Tr,host:jr,password:Nr,sidebarToggles:Rr};function Er(){const t=C(h=>h.status),e=C(h=>h.connect),n=C(h=>h.disconnect),s=x(h=>h.host),r=x(h=>h.setHost),o=x(h=>h.password),i=x(h=>h.setPassword),l=x(h=>h.leftSidebarCollapsed),d=x(h=>h.toggleLeftSidebar),u=x(h=>h.rightSidebarCollapsed),g=x(h=>h.toggleRightSidebar),p=t==="open"||t==="connecting";return a.jsxs("div",{className:J.toolbar,children:[a.jsx("span",{className:J.brand,children:"Pi-Studio"}),a.jsx(kr,{}),a.jsx("div",{className:J.sep}),a.jsx(ve,{className:J.host,value:s,onChange:h=>r(h.target.value),placeholder:"host:port or ws://… / http://…",disabled:p}),a.jsx(ve,{className:J.password,type:"password",value:o,onChange:h=>i(h.target.value),placeholder:"password",disabled:p}),t==="open"||t==="connecting"||t==="closing"?a.jsx(D,{size:"sm",onClick:()=>n(),children:"Disconnect"}):a.jsx(D,{size:"sm",variant:"default",onClick:()=>void e({url:s,password:o||void 0}),children:"Connect"}),a.jsxs("div",{className:J.sidebarToggles,children:[a.jsx(D,{size:"sm",variant:"ghost",iconOnly:!0,title:l?"Show sessions sidebar":"Hide sessions sidebar",onClick:()=>d(),children:l?a.jsx(It,{size:16}):a.jsx(Ct,{size:16})}),a.jsx(D,{size:"sm",variant:"ghost",iconOnly:!0,title:u?"Show files/changes sidebar":"Hide files/changes sidebar",onClick:()=>g(),children:u?a.jsx(Tt,{size:16}):a.jsx(jt,{size:16})})]})]})}const xe={rows:[],streamingAssistantIndex:null,streamingReasoningIndex:null,toolIndexByCallId:{}};let Pe=0;function X(){return Pe+=1,`row-${Pe}`}function Ar(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 Br(t,e){return t??`${e.kind}:${Ar(e)}`}function $r(t){return{...t,streamingAssistantIndex:null,streamingReasoningIndex:null}}function Mr(t,e){var o;const n=t.rows.slice();let s=t.streamingAssistantIndex;if(s===null||((o=n[s])==null?void 0:o.kind)!=="assistant"){const i={kind:"assistant",id:X(),text:"",streaming:!0};n.push(i),s=n.length-1}const r=n[s];return!r||r.kind!=="assistant"?t:(n[s]={...r,text:r.text+e},{...t,rows:n,streamingAssistantIndex:s,streamingReasoningIndex:null})}function Dr(t,e){var o;const n=t.rows.slice();let s=t.streamingReasoningIndex;if(s===null||((o=n[s])==null?void 0:o.kind)!=="reasoning"){const i={kind:"reasoning",id:X(),text:"",streaming:!0};n.push(i),s=n.length-1}const r=n[s];return!r||r.kind!=="reasoning"?t:(n[s]={...r,text:r.text+e},{...t,rows:n,streamingReasoningIndex:s,streamingAssistantIndex:null})}function Pr(t,e){if(t.kind!==e.kind)return e;const n={...t};for(const[s,r]of Object.entries(e))r!==void 0&&r!==""&&(n[s]=r);return n}function qr(t,e){var l;const n=Br(e.callId,e.tool),s=e.status==="completed"||e.status==="error"?e.status:"running",r=t.toolIndexByCallId[n],o=t.rows.slice();if(r!==void 0&&((l=o[r])==null?void 0:l.kind)==="tool"){const d=o[r];return d.kind!=="tool"?t:(o[r]={...d,tool:Pr(d.tool,e.tool),status:s},{...t,rows:o,streamingAssistantIndex:null,streamingReasoningIndex:null})}const i={kind:"tool",id:X(),callId:n,tool:e.tool,status:s};return o.push(i),{...t,rows:o,toolIndexByCallId:{...t.toolIndexByCallId,[n]:o.length-1},streamingAssistantIndex:null,streamingReasoningIndex:null}}function je(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 zr(t,e){const n=je(t),s={kind:"error",id:X(),text:e||"turn failed"};return{...n,rows:[...n.rows,s]}}function Or(t){const e=je(t),n={kind:"system",id:X(),text:"(canceled)"};return{...e,rows:[...e.rows,n]}}function Fr(t,e){const n={kind:"error",id:X(),text:e||"error"};return{...t,rows:[...t.rows,n]}}function Wr(t,e,n){const s={kind:"user",id:X(),text:e,images:n};return{...t,rows:[...t.rows,s]}}function ct(t,e){switch(e.kind){case"turn_started":return $r(t);case"user_message":return Wr(t,e.text??"",e.images);case"assistant_message":return Mr(t,e.text??"");case"reasoning":return Dr(t,e.text??"");case"tool_call":return qr(t,e);case"turn_completed":return je(t);case"turn_failed":return zr(t,e.error);case"turn_canceled":return Or(t);case"error":return Fr(t,e.message);default:return t}}let qe=0;function Hr(){return qe+=1,`s-${Date.now().toString(36)}-${qe}`}const A=K()((t,e)=>({sessions:{},order:[],activeSessionId:null,createSession(n){const s=Hr(),r={id:s,agentId:null,title:"New chat",status:"idle",cwd:n,timeline:xe,userMessageCount:0};return t(o=>({sessions:{...o.sessions,[s]:r},order:[s,...o.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(r=>{const o=r.sessions[n];return o?{sessions:{...r.sessions,[n]:{...o,agentId:s}}}:r})},setStatus(n,s){t(r=>{const o=r.sessions[n];return o?{sessions:{...r.sessions,[n]:{...o,status:s}}}:r})},setStatusByAgentId(n,s){const r=e().findByAgentId(n);r&&e().setStatus(r.id,s)},setTitle(n,s){t(r=>{const o=r.sessions[n];return o?{sessions:{...r.sessions,[n]:{...o,title:s}}}:r})},setCwd(n,s){t(r=>{const o=r.sessions[n];return o?{sessions:{...r.sessions,[n]:{...o,cwd:s}}}:r})},applyStreamEvent(n,s){t(r=>{const o=r.sessions[n];if(!o)return r;const i=ct(o.timeline,s);let l=o.title;if(s.kind==="turn_completed"&&l==="New chat"){const d=i.rows.slice().reverse().find(u=>u.kind==="assistant");d&&d.kind==="assistant"&&d.text&&(l=d.text.slice(0,40)+(d.text.length>40?"…":""))}return{sessions:{...r.sessions,[n]:{...o,timeline:i,title:l}}}})},addUserMessage(n){t(s=>{const r=s.sessions[n];return r?{sessions:{...s.sessions,[n]:{...r,userMessageCount:r.userMessageCount+1}}}:s})},activate(n){t({activeSessionId:n})},remove(n){t(s=>{const{[n]:r,...o}=s.sessions,i=s.order.filter(d=>d!==n),l=s.activeSessionId===n?i[0]??null:s.activeSessionId;return{sessions:o,order:i,activeSessionId:l}})},findByAgentId(n){return Object.values(e().sessions).find(s=>s.agentId===n)}}));function _e(t,e){return t.filter(n=>n.workspaceCwd===e)}const I=K()((t,e)=>({tabs:[],activeTabId:null,activeWorkspaceCwd:null,lastActiveTabByWorkspace:{},open(n){const s=e().tabs.find(r=>r.id===n.id);if(s){e().activate(s.id);return}t(r=>({tabs:[...r.tabs,n],activeTabId:n.id,activeWorkspaceCwd:n.workspaceCwd,lastActiveTabByWorkspace:{...r.lastActiveTabByWorkspace,[n.workspaceCwd]:n.id}}))},close(n){t(s=>{const r=s.tabs.find(u=>u.id===n);if(!r)return s;const o=s.tabs.findIndex(u=>u.id===n),i=s.tabs.filter(u=>u.id!==n);let l=s.activeTabId;const d={...s.lastActiveTabByWorkspace};if(l===n){const u=_e(i,r.workspaceCwd),g=Math.min(o,u.length-1),p=u[g];l=(p==null?void 0:p.id)??null}if(d[r.workspaceCwd]===n){const u=_e(i,r.workspaceCwd)[0];u?d[r.workspaceCwd]=u.id:delete d[r.workspaceCwd]}return{tabs:i,activeTabId:l,lastActiveTabByWorkspace:d}})},activate(n){t(s=>{const r=s.tabs.find(o=>o.id===n);return r?{activeTabId:n,activeWorkspaceCwd:r.workspaceCwd,lastActiveTabByWorkspace:{...s.lastActiveTabByWorkspace,[r.workspaceCwd]:n}}:s})},switchWorkspace(n){t(s=>{var d;const r=_e(s.tabs,n),o=s.lastActiveTabByWorkspace[n],l=o&&r.some(u=>u.id===o)?o:((d=r[0])==null?void 0:d.id)??null;return{activeWorkspaceCwd:n,activeTabId:l,lastActiveTabByWorkspace:l?{...s.lastActiveTabByWorkspace,[n]:l}:s.lastActiveTabByWorkspace}})},reorder(n,s){t(r=>{const o=r.tabs.findIndex(u=>u.id===n),i=r.tabs.findIndex(u=>u.id===s);if(o===-1||i===-1||o===i)return r;const l=r.tabs.slice(),[d]=l.splice(o,1);return d?(l.splice(i,0,d),{tabs:l}):r})},updateLabel(n,s){t(r=>({tabs:r.tabs.map(o=>o.id===n?{...o,label:s}:o)}))},updateData(n,s){t(r=>({tabs:r.tabs.map(o=>o.id===n?{...o,data:{...o.data,...s}}:o)}))}})),z={chat:t=>`chat-${t}`,file:t=>`file-${t}`,diff:(t,e)=>`diff-${t}${e?"-staged":""}`,terminal:t=>`term-${t}`};let we=0;function lt(t){we+=1,I.getState().open({id:z.terminal(`new-${we}`),kind:"terminal",label:`Terminal ${we}`,closable:!0,data:{slot:null,cwd:t},workspaceCwd:t})}const Z=K()((t,e)=>({currentPath:"",rootPath:"",setRoot:n=>t({rootPath:n,currentPath:n}),setPath:n=>t({currentPath:n}),goUp:()=>{const{currentPath:n,rootPath:s}=e();if(!s||n===s)return;const r=n.split("/").slice(0,-1).join("/")||"/",o=r.length<s.length||!r.startsWith(s)?s:r;t({currentPath:o})}}));let Q=null;const ke=new Set;function Lr(t){return ke.add(t),()=>ke.delete(t)}async function Ne(t){var e;if(Q)return Q;try{const n=await t.connection.request("file_explorer_request",{path:"/home"}),r=(((e=n.result)==null?void 0:e.entries)??n.entries??[]).find(o=>o.kind==="directory"||o.type==="directory");Q="/home/"+((r==null?void 0:r.name)||"user")}catch{return"/tmp"}for(const n of ke)n(Q);return Q}function Ur(){return Q}async function Vr(t,e){return e==="~"||e.startsWith("~/")?await Ne(t)+e.slice(1):e}function dt(){const t=C(r=>r.client),e=C(r=>r.status),[n,s]=v.useState(Ur());return v.useEffect(()=>Lr(s),[]),v.useEffect(()=>{!t||e!=="open"||n||Ne(t)},[t,e,n]),n}const Gr="_dot_202py_3",Kr={dot:Gr};function Xr(t){const{status:e,requiresAttention:n,attentionReason:s,showInactive:r}=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 r?"foregroundMuted":null}}const ze=8,Jr={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 Yr({className:t,...e}){const n=Xr(e);return n?a.jsx("span",{className:`${Kr.dot}${t?` ${t}`:""}`,style:{width:ze,height:ze,backgroundColor:Jr[n]??"currentColor"},role:"presentation"}):null}const Zr={initializing:"queued",idle:"idle",running:"running",error:"error",closed:"finished"};function Qr(t){return Zr[t]??"idle"}const eo="_wrap_sqws5_1",to="_header_sqws5_7",no="_list_sqws5_23",so="_item_sqws5_28",ro="_active_sqws5_37",oo="_title_sqws5_40",ao="_meta_sqws5_49",io="_menuBtn_sqws5_57",co="_workspaceGroup_sqws5_75",lo="_workspaceHeader_sqws5_78",uo="_workspaceChevron_sqws5_91",po="_workspaceIcon_sqws5_102",fo="_workspaceLabel_sqws5_106",ho="_workspaceCount_sqws5_112",mo="_newSessionBtn_sqws5_117",go="_workspaceSessions_sqws5_129",R={wrap:eo,header:to,list:no,item:so,active:ro,title:oo,meta:ao,menuBtn:io,workspaceGroup:co,workspaceHeader:lo,workspaceChevron:uo,workspaceIcon:po,workspaceLabel:fo,workspaceCount:ho,newSessionBtn:mo,workspaceSessions:go};function bo({session:t,active:e,onSelect:n,onOpenMenu:s}){return a.jsxs("div",{className:E(R.item,e&&R.active),onClick:n,onContextMenu:r=>{r.preventDefault(),s(r.clientX,r.clientY)},children:[a.jsxs("div",{className:R.title,children:[a.jsx(Yr,{status:Qr(t.status),showInactive:!0}),a.jsx("span",{children:t.title})]}),a.jsxs("div",{className:R.meta,children:[t.cwd||"~"," · ",t.agentId?t.agentId.slice(0,8):"new"," ·"," ",t.userMessageCount," msgs"]}),a.jsx("button",{type:"button",className:R.menuBtn,title:"Actions",onClick:r=>{r.stopPropagation();const o=r.currentTarget.getBoundingClientRect();s(o.left,o.bottom)},children:a.jsx(Nt,{size:14})})]})}const _o="_trigger_16o4s_1",wo="_content_16o4s_7",yo="_item_16o4s_16",So="_danger_16o4s_33",vo="_sep_16o4s_36",W={trigger:_o,content:wo,item:yo,danger:So,sep:vo};function xo(){const t=x(w=>w.sessionMenu),e=x(w=>w.closeSessionMenu),n=C(w=>w.client),s=v.useRef(null),[r,o]=v.useState(!1);v.useEffect(()=>{o(t!==null)},[t]);const i=A(w=>t?w.sessions[t.sessionId]:void 0);if(!t)return null;const l=!!(i!=null&&i.agentId)&&(i==null?void 0:i.status)==="running";function d(w){o(w),w||e()}function u(){if(!i)return;const w=window.prompt("Rename:",i.title);if(w!=null&&w.trim()){const b=w.trim();A.getState().setTitle(i.id,b),I.getState().updateLabel(z.chat(i.id),b),i.agentId&&(n==null||n.agent(i.agentId).update({title:b}).catch(()=>{}))}e()}function g(){i!=null&&i.agentId&&(n==null||n.agent(i.agentId).interrupt().catch(()=>{})),e()}function p(w){A.getState().remove(w),I.getState().close(z.chat(w))}async function h(){if(i){if(!window.confirm("Archive this agent? It can be resumed later."))return e();if(e(),!i.agentId){p(i.id);return}if(!n){window.alert("Not connected — cannot archive remotely.");return}try{await n.agent(i.agentId).archive(),p(i.id)}catch(w){window.alert(`Failed to archive: ${w instanceof Error?w.message:String(w)}`)}}}async function T(){if(i){if(!window.confirm("Permanently delete this agent? This cannot be undone."))return e();if(e(),!i.agentId){p(i.id);return}if(!n){window.alert("Not connected — cannot delete remotely.");return}try{await n.agent(i.agentId).delete(),p(i.id)}catch(w){window.alert(`Failed to delete: ${w instanceof Error?w.message:String(w)}`)}}}return a.jsxs(Wt,{open:r,onOpenChange:d,modal:!1,children:[a.jsx(Ht,{asChild:!0,children:a.jsx("button",{ref:s,type:"button",className:W.trigger,style:{left:t.x,top:t.y},"aria-hidden":!0,tabIndex:-1})}),a.jsx(Lt,{children:a.jsxs(Ut,{className:W.content,align:"start",sideOffset:2,children:[a.jsx(le,{className:W.item,onSelect:u,children:"Rename"}),a.jsx(le,{className:W.item,disabled:!l,onSelect:g,children:"Stop agent"}),a.jsx(Vt,{className:W.sep}),a.jsx(le,{className:`${W.item} ${W.danger}`,onSelect:h,children:"Archive"}),a.jsx(le,{className:`${W.item} ${W.danger}`,onSelect:T,children:"Delete permanently"})]})})]})}function ko({label:t,cwd:e,sessionCount:n,collapsed:s,onToggleCollapsed:r,onNewSession:o}){return a.jsxs("div",{className:R.workspaceHeader,onClick:r,title:e,children:[a.jsx("button",{type:"button",className:R.workspaceChevron,"aria-label":s?"Expand workspace":"Collapse workspace",onClick:i=>{i.stopPropagation(),r()},children:s?a.jsx(Rt,{size:13}):a.jsx(Et,{size:13})}),a.jsx(At,{size:13,className:E(R.workspaceIcon)}),a.jsx("span",{className:R.workspaceLabel,children:t}),a.jsx("span",{className:R.workspaceCount,children:n}),a.jsx(D,{size:"xs",variant:"ghost",iconOnly:!0,title:"New conversation",className:R.newSessionBtn,onClick:i=>{i.stopPropagation(),o()},children:a.jsx(He,{size:13})})]})}function te(t,e){return e&&(t==="~"||t.startsWith("~/"))?e+t.slice(1):t}function ut(t,e,n){const s=new Map;for(const r of t){const o=e[r];if(!o)continue;const i=te(o.cwd||"~",n),l=s.get(i);l?l.push(o):s.set(i,[o])}return Array.from(s,([r,o])=>({cwd:r,sessions:o}))}function Io(t){return!t||t==="~"?"~":t.split("/").filter(Boolean).pop()||t}function Co(){const t=A(_=>_.order),e=A(_=>_.sessions),n=A(_=>_.activeSessionId),s=A(_=>_.activate),r=A(_=>_.createSession),o=I(_=>_.open),i=C(_=>_.status),l=x(_=>_.openSessionMenu),d=x(_=>_.setCwd),u=x(_=>_.openCwdPicker),g=x(_=>_.collapsedWorkspaces),p=x(_=>_.toggleWorkspaceCollapsed),h=dt();function T(_){const j=te(_||"~",h),S=r(j);o({id:z.chat(S),kind:"chat",label:"New chat",closable:!0,data:{sessionId:S},workspaceCwd:j})}function w(_){s(_);const j=e[_],S=te((j==null?void 0:j.cwd)||"~",h);j!=null&&j.cwd&&d(j.cwd),o({id:z.chat(_),kind:"chat",label:(j==null?void 0:j.title)??"Chat",closable:!0,data:{sessionId:_},workspaceCwd:S})}const b=ut(t,e,h);return a.jsxs("div",{className:R.wrap,children:[a.jsxs("div",{className:R.header,children:[a.jsx("h3",{children:"Workspaces"}),a.jsx(D,{size:"xs",variant:"ghost",iconOnly:!0,title:i!=="open"?"Connect to open a workspace":"Open a workspace folder",disabled:i!=="open",onClick:()=>u(),children:a.jsx(Bt,{size:14})})]}),a.jsx("div",{className:R.list,children:b.map(_=>{const j=g.has(_.cwd);return a.jsxs("div",{className:R.workspaceGroup,children:[a.jsx(ko,{label:Io(_.cwd),cwd:_.cwd,sessionCount:_.sessions.length,collapsed:j,onToggleCollapsed:()=>p(_.cwd),onNewSession:()=>T(_.cwd)}),!j&&a.jsx("div",{className:R.workspaceSessions,children:_.sessions.map(S=>a.jsx(bo,{session:S,active:S.id===n,onSelect:()=>w(S.id),onOpenMenu:(mt,gt)=>l(S.id,mt,gt)},S.id))})]},_.cwd)})}),a.jsx(xo,{})]})}const To="_strip_cnwks_1",jo="_tab_cnwks_10",No="_active_cnwks_26",Ro="_icon_cnwks_30",Eo="_label_cnwks_35",Ao="_close_cnwks_40",ee={strip:To,tab:jo,active:No,icon:Ro,label:Eo,close:Ao},Bo={chat:Pt,file:Dt,diff:Mt,terminal:$t};function $o({tab:t}){const e=I(p=>p.activeTabId),n=I(p=>p.activate),s=I(p=>p.close),r=Bo[t.kind],{attributes:o,listeners:i,setNodeRef:l,transform:d,transition:u,isDragging:g}=rn({id:t.id});return a.jsxs("div",{ref:l,className:E(ee.tab,t.id===e&&ee.active),style:{transform:on.Transform.toString(d),transition:u,opacity:g?.5:1},onClick:()=>n(t.id),onAuxClick:p=>{p.button===1&&t.closable&&s(t.id)},title:t.label,...o,...i,children:[a.jsx("span",{className:ee.icon,children:a.jsx(r,{size:13})}),a.jsx("span",{className:ee.label,children:t.label}),t.closable&&a.jsx("span",{className:ee.close,onClick:p=>{p.stopPropagation(),s(t.id)},children:a.jsx(me,{size:12})})]})}function Mo(){const t=I(i=>i.tabs),e=I(i=>i.activeWorkspaceCwd),n=I(i=>i.reorder),s=t.filter(i=>i.workspaceCwd===e),r=Yt(Zt(sn,{activationConstraint:{distance:4}}));function o(i){const{active:l,over:d}=i;!d||l.id===d.id||n(String(l.id),String(d.id))}return a.jsx(Qt,{sensors:r,collisionDetection:en,onDragEnd:o,children:a.jsx(tn,{items:s.map(i=>i.id),strategy:nn,children:a.jsx("div",{className:ee.strip,children:s.map(i=>a.jsx($o,{tab:i},i.id))})})})}const Do="_spinner_1tgzp_3",Po={spinner:Do},qo={xs:12,sm:16,md:20,lg:24},zo={xs:1,sm:2,md:2,lg:3};function Oo({size:t="md",color:e="currentColor",className:n,"aria-label":s="Loading"}){const r=typeof t=="number"?t:qo[t],o=typeof t=="number"?2:zo[t];return a.jsx("span",{className:`${Po.spinner}${n?` ${n}`:""}`,role:"status","aria-label":s,style:{width:r,height:r,borderWidth:o,color:e}})}const Fo=v.lazy(()=>Ce(()=>import("./ChatPanel-6y4_CIof.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13])).then(t=>({default:t.ChatPanel}))),Oe=v.lazy(()=>Ce(()=>import("./FilePanel-DZQ3Ebt0.js").then(t=>t.F),__vite__mapDeps([14,1,7,6,5,2,9,10,15])).then(t=>({default:t.FilePanel}))),Wo=v.lazy(()=>Ce(()=>import("./TerminalPanel-zbfBqrQA.js"),__vite__mapDeps([16,1,17,18,7,6,5,2,3,11,12,19])).then(t=>({default:t.TerminalPanel}))),Ho={chat:Fo,file:Oe,diff:Oe,terminal:Wo},Lo="_area_1vzxd_1",Uo="_panel_1vzxd_7",Vo="_active_1vzxd_14",Go="_empty_1vzxd_17",oe={area:Lo,panel:Uo,active:Vo,empty:Go};function Ko(){const t=I(r=>r.tabs),e=I(r=>r.activeTabId),n=I(r=>r.activeWorkspaceCwd);return t.some(r=>r.workspaceCwd===n)?a.jsx("div",{className:oe.area,children:t.map(r=>{const o=Ho[r.kind];return a.jsx("div",{className:E(oe.panel,r.id===e&&oe.active),children:a.jsx(v.Suspense,{fallback:a.jsx(Oo,{size:"md"}),children:a.jsx(o,{tab:r})})},r.id)})}):a.jsx("div",{className:oe.area,children:a.jsx("div",{className:oe.empty,children:"No open tabs in this workspace"})})}const Xo={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"],agentTimeline:t=>["agents","timeline",t]};function Jo(t){const e=t.kind==="directory"||t.type==="directory"?"directory":"file";return{name:t.name??"",kind:e,size:t.size,mtimeMs:t.mtimeMs}}function Yo(t){return t.slice().sort((e,n)=>e.kind!==n.kind?e.kind==="directory"?-1:1:e.name.localeCompare(n.name))}function pt(t,e=!0){const n=C(s=>s.client);return vt({queryKey:Xo.explorer(t),queryFn:async()=>{if(!n)throw new Error("not connected");const r=(await n.connection.request("file_explorer_request",{path:t})).result;if(!r||r.ok===!1)throw new Error(r&&"error"in r?r.error:"explorer request failed");const o="entries"in r?r.entries??[]:[];return{path:r.resolvedPath??t,entries:Yo(o.map(Jo))}},enabled:!!n&&!!t&&e})}const Zo="_list_1o67b_1",Qo="_upRow_1o67b_4",ea="_item_1o67b_24",ta="_icon_1o67b_36",na="_name_1o67b_43",sa="_dirName_1o67b_48",ra="_emptyState_1o67b_54",O={list:Zo,upRow:Qo,item:ea,icon:ta,name:na,dirName:sa,emptyState:ra};function oa(){const t=C(b=>b.client),e=Z(b=>b.currentPath),n=Z(b=>b.rootPath),s=Z(b=>b.setPath),r=Z(b=>b.setRoot),o=Z(b=>b.goUp),i=I(b=>b.activeWorkspaceCwd),l=I(b=>b.open),d=v.useRef(null);v.useEffect(()=>{if(!t)return;const b=i||"~";d.current!==b&&(d.current=b,Vr(t,b).then(_=>r(_)))},[t,i,r]);const{data:u,isLoading:g,isError:p,error:h}=pt(e,!!t);function T(b){s(e?`${e}/${b}`:b)}function w(b){const _=e?`${e}/${b}`:b;l({id:z.file(_),kind:"file",label:_.split("/").pop()||_,closable:!0,data:{path:_},workspaceCwd:i||"~"})}return t?g?a.jsx("div",{className:O.emptyState,children:"Loading..."}):p?a.jsxs("div",{className:O.emptyState,children:["Error: ",h instanceof Error?h.message:"unknown error"]}):!u||u.entries.length===0?a.jsx("div",{className:O.emptyState,children:"No files loaded"}):a.jsxs("div",{className:O.list,children:[e&&e!==n&&a.jsxs("div",{className:O.upRow,onClick:()=>o(),children:[a.jsx(Le,{size:12}),a.jsx("span",{children:e})]}),u.entries.map(b=>a.jsxs("div",{className:O.item,onClick:()=>b.kind==="directory"?T(b.name):w(b.name),children:[a.jsx("span",{className:O.icon,children:b.kind==="directory"?a.jsx(Ue,{size:14}):a.jsx(qt,{size:14})}),a.jsx("span",{className:b.kind==="directory"?O.dirName:O.name,children:b.name})]},b.name))]}):a.jsx("div",{className:O.emptyState,children:"Connect to browse files"})}const Ie=K()(t=>({subscribedCwd:null,changes:[],setSubscribedCwd:e=>t({subscribedCwd:e}),applyProjection:e=>{if(!e||!e.available){t({changes:[]});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})}}));function aa(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 ia(t){const e=C(o=>o.client),n=Ie(o=>o.applyProjection),s=Ie(o=>o.setSubscribedCwd),r=v.useRef(e);return r.current=e,v.useEffect(()=>{if(!e||!t)return;let o=!1;e.connection.request("checkout_status_subscribe",{cwd:t}).catch(()=>{}),s(t);const i=e.connection.onSessionMessage(l=>{if(o)return;const d=l;aa(d)&&d.cwd===t&&n(d.projection)});return e.connection.request("checkout_refresh_request",{cwd:t}).catch(()=>{}),()=>{o=!0,i(),e.connection.request("checkout_status_unsubscribe",{cwd:t}).catch(()=>{}),s(null)}},[e,t,n,s]),{refresh(){const o=r.current;!o||!t||o.connection.request("checkout_refresh_request",{cwd:t}).catch(()=>{})}}}const ca="_list_1pgby_1",la="_summary_1pgby_4",da="_item_1pgby_11",ua="_badge_1pgby_23",pa="_added_1pgby_30",fa="_modified_1pgby_34",ha="_deleted_1pgby_38",ma="_name_1pgby_42",ga="_emptyState_1pgby_47",V={list:ca,summary:la,item:da,badge:ua,added:pa,modified:fa,deleted:ha,name:ma,emptyState:ga},ba={added:"A",modified:"M",deleted:"D"};function _a(){const e=I(o=>o.activeWorkspaceCwd)||"~";ia(e);const n=Ie(o=>o.changes),s=I(o=>o.open);function r(o,i){s({id:z.diff(o,i),kind:"diff",label:o.split("/").pop()||o,closable:!0,data:{path:o,staged:i},workspaceCwd:e})}return n.length===0?a.jsx("div",{className:V.emptyState,children:"No changes detected"}):a.jsxs("div",{className:V.list,children:[a.jsxs("div",{className:V.summary,children:[n.length," changed file",n.length===1?"":"s"]}),n.map((o,i)=>a.jsxs("div",{className:V.item,onClick:()=>r(o.path,o.staged),children:[a.jsx("span",{className:E(V.badge,V[o.status]),children:ba[o.status]}),a.jsx("span",{className:V.name,children:o.path})]},`${o.path}-${o.staged}-${i}`))]})}const ft=K()(t=>({terminals:[],setTerminals:e=>t({terminals:e})}));function wa(t){return typeof t=="object"&&t!==null&&"type"in t&&t.type==="terminals_update"&&"terminals"in t&&Array.isArray(t.terminals)}function ya(){const t=C(n=>n.client),e=ft(n=>n.setTerminals);v.useEffect(()=>{if(!t){e([]);return}let n=!1;t.connection.request("subscribe_terminals_request",{}).then(r=>{n||e(r.terminals??[])}).catch(()=>{});const s=t.connection.onSessionMessage(r=>{if(n)return;const o=r;wa(o)&&e(o.terminals)});return()=>{n=!0,s(),t.connection.request("unsubscribe_terminals_request",{}).catch(()=>{})}},[t,e])}const Sa="_wrap_sx7p7_1",va="_newTerminal_sx7p7_5",xa="_list_sx7p7_10",ka="_summary_sx7p7_13",Ia="_item_sx7p7_20",Ca="_reattach_sx7p7_30",Ta="_icon_sx7p7_45",ja="_name_sx7p7_49",Na="_openBadge_sx7p7_54",Ra="_kill_sx7p7_62",Ea="_emptyState_sx7p7_80",$={wrap:Sa,newTerminal:va,list:xa,summary:ka,item:Ia,reattach:Ca,icon:Ta,name:ja,openBadge:Na,kill:Ra,emptyState:Ea};function Aa(){ya();const t=C(p=>p.client),e=ft(p=>p.terminals),n=I(p=>p.tabs),s=I(p=>p.activeWorkspaceCwd),r=I(p=>p.open),o=I(p=>p.activate),i=I(p=>p.close);function l(p){return n.find(h=>h.kind==="terminal"&&h.data.slot===p)}function d(p,h,T){const w=l(p);if(w){o(w.id);return}const b=T||"~";r({id:z.terminal(p),kind:"terminal",label:h,closable:!0,data:{slot:p,cwd:b},workspaceCwd:b})}function u(p){const h=l(p);if(h){i(h.id);return}t&&t.connection.request("kill_terminal_request",{slot:p}).catch(()=>{})}const g=a.jsx(D,{variant:"secondary",size:"sm",leftIcon:a.jsx(He,{size:14}),className:$.newTerminal,onClick:()=>lt(s||"~"),children:"New terminal"});return e.length===0?a.jsxs("div",{className:$.wrap,children:[g,a.jsx("div",{className:$.emptyState,children:"No terminals running"})]}):a.jsxs("div",{className:$.wrap,children:[g,a.jsxs("div",{className:$.list,children:[a.jsxs("div",{className:$.summary,children:[e.length," terminal",e.length===1?"":"s"," running"]}),e.map(p=>{const h=l(p.slot)!==void 0;return a.jsxs("div",{className:$.item,children:[a.jsxs("button",{type:"button",className:$.reattach,onClick:()=>d(p.slot,p.name,p.cwd),title:p.cwd,children:[a.jsx(zt,{size:13,className:$.icon}),a.jsx("span",{className:$.name,children:p.name}),h&&a.jsx("span",{className:$.openBadge,children:"open"})]}),a.jsx("button",{type:"button",className:$.kill,onClick:()=>u(p.slot),title:"Kill terminal",children:a.jsx(me,{size:13})})]},p.slot)})]})]})}const Ba="_wrap_r37ok_1",$a="_tabBar_r37ok_7",Ma="_tabBtn_r37ok_13",Da="_active_r37ok_26",Pa="_refreshBtn_r37ok_30",qa="_content_r37ok_34",F={wrap:Ba,tabBar:$a,tabBtn:Ma,active:Da,refreshBtn:Pa,content:qa};function za(){const t=x(d=>d.rightSidebarTab),e=x(d=>d.setRightSidebarTab),n=Z(d=>d.currentPath),r=I(d=>d.activeWorkspaceCwd)||"~",o=C(d=>d.client),i=xt();function l(){i.invalidateQueries({queryKey:["explorer",n]}),o&&r&&o.connection.request("checkout_refresh_request",{cwd:r}).catch(()=>{})}return a.jsxs("div",{className:F.wrap,children:[a.jsxs("div",{className:F.tabBar,children:[a.jsx("button",{type:"button",className:E(F.tabBtn,t==="files"&&F.active),onClick:()=>e("files"),children:"Files"}),a.jsx("button",{type:"button",className:E(F.tabBtn,t==="changes"&&F.active),onClick:()=>e("changes"),children:"Changes"}),a.jsx("button",{type:"button",className:E(F.tabBtn,t==="terminals"&&F.active),onClick:()=>e("terminals"),children:"Terminals"}),t!=="terminals"&&a.jsx(D,{size:"xs",variant:"ghost",iconOnly:!0,title:"Refresh",className:F.refreshBtn,onClick:l,children:a.jsx(Ot,{size:13})})]}),a.jsx("div",{className:F.content,children:t==="files"?a.jsx(oa,{}):t==="changes"?a.jsx(_a,{}):a.jsx(Aa,{})})]})}const Oa="_wrapper_131x2_3",Fa="_box_131x2_18",Wa="_checkmark_131x2_36",Ha="_nativeInput_131x2_41",he={wrapper:Oa,box:Fa,checkmark:Wa,nativeInput:Ha};v.forwardRef(function({label:e,checked:n=!1,disabled:s,className:r,onChange:o,...i},l){return a.jsxs("label",{className:he.wrapper,"data-disabled":s||void 0,children:[a.jsx("input",{ref:l,type:"checkbox",className:he.nativeInput,checked:n,disabled:s,onChange:o,...i}),a.jsx("span",{className:he.box,"data-checked":n,"aria-hidden":!0,children:n&&a.jsx(Ft,{size:12,className:he.checkmark})}),e&&a.jsx("span",{children:e})]})});const La="_select_vj45v_3",Ua={select:La};v.forwardRef(function({options:e,placeholder:n,className:s,...r},o){return a.jsxs("select",{ref:o,className:E(Ua.select,s),...r,children:[n&&a.jsx("option",{value:"",disabled:!0,children:n}),e.map(i=>a.jsx("option",{value:i.value,children:i.label},i.value))]})});const Va="_overlay_1yaef_1",Ga="_contentWrapper_1yaef_7",Ka="_dialog_1yaef_16",Xa="_header_1yaef_28",Ja="_title_1yaef_36",Ya="_closeBtn_1yaef_43",Za="_body_1yaef_57",Qa="_footer_1yaef_63",ei="_bare_1yaef_72",ti="_bareBody_1yaef_78",ni="_bareCloseBtn_1yaef_82",si="_visuallyHidden_1yaef_101",M={overlay:Va,contentWrapper:Ga,dialog:Ka,header:Xa,title:Ja,closeBtn:Ya,body:Za,footer:Qa,bare:ei,bareBody:ti,bareCloseBtn:ni,visuallyHidden:si},ri=ye;function oi({open:t,onOpenChange:e,title:n,children:s,footer:r,width:o,className:i,bare:l=!1}){return a.jsx(Gt,{open:t,onOpenChange:e,children:a.jsxs(Kt,{children:[a.jsx(Xt,{className:M.overlay}),a.jsx("div",{className:M.contentWrapper,children:a.jsxs(Jt,{className:E(M.dialog,l&&M.bare,i),style:o!==void 0?{width:o}:void 0,children:[l?a.jsx(Re,{className:M.visuallyHidden,children:n}):a.jsxs("div",{className:M.header,children:[a.jsx(Re,{className:M.title,children:n}),a.jsx(ye,{asChild:!0,children:a.jsx("button",{type:"button",className:M.closeBtn,"aria-label":"Close",children:a.jsx(me,{size:16})})})]}),a.jsx("div",{className:E(M.body,l&&M.bareBody),children:s}),l&&a.jsx(ye,{asChild:!0,children:a.jsx("button",{type:"button",className:M.bareCloseBtn,"aria-label":"Close",children:a.jsx(me,{size:16})})}),r&&a.jsx("div",{className:M.footer,children:r})]})})]})})}const ai="_handle_1ocv1_1",ii={handle:ai};function Fe({side:t,onResize:e,className:n}){const s=v.useRef(0),r=v.useCallback(l=>{const d=l.clientX-s.current;s.current=l.clientX,e(t==="left"?d:-d)},[e,t]),o=v.useCallback(l=>{var d,u;window.removeEventListener("pointermove",r),window.removeEventListener("pointerup",o),document.body.style.cursor="",document.body.style.userSelect="",(u=(d=l.target)==null?void 0:d.releasePointerCapture)==null||u.call(d,l.pointerId)},[r]);function i(l){l.preventDefault(),s.current=l.clientX,document.body.style.cursor="col-resize",document.body.style.userSelect="none",window.addEventListener("pointermove",r),window.addEventListener("pointerup",o)}return a.jsx("div",{className:E(ii.handle,n),onPointerDown:i,role:"separator","aria-orientation":"vertical"})}function ci(t,e){var g;const{order:n,sessions:s,createSession:r,activate:o}=A.getState(),l=ut(n,s,e).find(p=>p.cwd===t),d=((g=l==null?void 0:l.sessions[0])==null?void 0:g.id)??r(t);o(d);const u=A.getState().sessions[d];I.getState().open({id:z.chat(d),kind:"chat",label:(u==null?void 0:u.title)??"New chat",closable:!0,data:{sessionId:d},workspaceCwd:t}),x.getState().setCwd(t)}const li="_pathRow_9xphl_1",di="_pathInput_9xphl_9",ui="_list_9xphl_13",pi="_item_9xphl_20",fi="_name_9xphl_32",hi="_emptyState_9xphl_37",U={pathRow:li,pathInput:di,list:ui,item:pi,name:fi,emptyState:hi};function mi(){const t=x(S=>S.cwdPickerOpen),e=x(S=>S.closeCwdPicker),n=I(S=>S.activeWorkspaceCwd),s=C(S=>S.client),r=dt(),[o,i]=v.useState("/"),[l,d]=v.useState("/");v.useEffect(()=>{if(!t)return;const S=te(n||"~",r);i(S),d(S)},[t,s,n]);const{data:u,isLoading:g,isError:p,error:h}=pt(o,t&&!!s),T=((u==null?void 0:u.entries)??[]).filter(S=>S.kind==="directory");function w(S){i(S),d(S)}function b(){w(o.split("/").slice(0,-1).join("/")||"/")}function _(){w(l.trim())}function j(){ci(o,r),e()}return a.jsxs(oi,{open:t,onOpenChange:S=>!S&&e(),title:"Open Workspace",footer:a.jsxs(a.Fragment,{children:[a.jsx(ri,{asChild:!0,children:a.jsx(D,{size:"sm",variant:"secondary",children:"Cancel"})}),a.jsx(D,{size:"sm",onClick:j,children:"Open this folder"})]}),children:[a.jsxs("div",{className:U.pathRow,children:[a.jsx(D,{size:"xs",variant:"ghost",iconOnly:!0,title:"Up",onClick:b,children:a.jsx(Le,{size:13})}),a.jsx(ve,{className:U.pathInput,value:l,onChange:S=>d(S.target.value),onKeyDown:S=>{S.key==="Enter"&&(S.preventDefault(),_())}}),a.jsx(D,{size:"xs",onClick:_,children:"Go"})]}),a.jsx("div",{className:U.list,children:g?a.jsx("div",{className:U.emptyState,children:"Loading..."}):p?a.jsxs("div",{className:U.emptyState,children:["Error: ",h instanceof Error?h.message:"unknown error"]}):T.length===0?a.jsx("div",{className:U.emptyState,children:"No subdirectories"}):T.map(S=>a.jsxs("div",{className:U.item,onClick:()=>w(o==="/"?`/${S.name}`:`${o}/${S.name}`),children:[a.jsx(Ue,{size:14}),a.jsx("span",{className:U.name,children:S.name})]},S.name))})]})}const gi="_shell_1m1nv_1",bi="_main_1m1nv_7",_i="_sidebarLeft_1m1nv_13",wi="_leftHandle_1m1nv_21",yi="_center_1m1nv_24",Si="_sidebarRight_1m1nv_31",vi="_rightHandle_1m1nv_39",G={shell:gi,main:bi,sidebarLeft:_i,leftHandle:wi,center:yi,sidebarRight:Si,rightHandle:vi};function xi(){const t=x(i=>i.leftSidebarCollapsed),e=x(i=>i.rightSidebarCollapsed),n=x(i=>i.leftSidebarWidth),s=x(i=>i.rightSidebarWidth),r=x(i=>i.resizeLeftSidebar),o=x(i=>i.resizeRightSidebar);return a.jsxs("div",{className:G.shell,children:[a.jsx(Er,{}),a.jsxs("div",{className:G.main,children:[!t&&a.jsxs("aside",{className:G.sidebarLeft,style:{width:n},children:[a.jsx(Co,{}),a.jsx(Fe,{side:"left",className:G.leftHandle,onResize:r})]}),a.jsxs("div",{className:G.center,children:[a.jsx(Mo,{}),a.jsx(Ko,{})]}),!e&&a.jsxs("aside",{className:G.sidebarRight,style:{width:s},children:[a.jsx(Fe,{side:"right",className:G.rightHandle,onResize:o}),a.jsx(za,{})]})]}),a.jsx(mi,{})]})}function ki(){const t=v.useRef(!1);v.useEffect(()=>{if(t.current)return;t.current=!0;const e=new URLSearchParams(window.location.search),n=e.get("host"),s=e.get("password"),r=e.get("cwd"),o=e.get("connect")==="1",i=x.getState();if(n&&i.setHost(n),s&&i.setPassword(s),r&&i.setCwd(r),o){const{host:l,password:d}=x.getState();C.getState().connect({url:l,password:d||void 0})}},[])}function Ii(t){return typeof t=="object"&&t!==null&&"kind"in t}function Ci(t){const e=[];for(const n of t)if(Ii(n))if(n.kind==="other")n.event&&e.push(n.event);else for(const s of n.events??[])e.push(s);return e}function Ti(){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 d;let s=[];try{s=(await t.connection.request("list_agents_request",{all:!1})).agents??[]}catch{s=[]}s.sort((u,g)=>(g.lastActivity??0)-(u.lastActivity??0));const r=A.getState();for(const u of s){if(r.findByAgentId(u.agentId))continue;let g=xe;try{const p=await t.agent(u.agentId).timeline.fetch({direction:"after",limit:200});g=Ci(p.items).reduce(ct,xe)}catch{}r.hydrate({id:`s-${u.agentId.slice(0,12)}`,agentId:u.agentId,title:u.title||((d=u.cwd)==null?void 0:d.split("/").pop())||"Restored",status:u.status??"idle",cwd:u.cwd||"~",timeline:g,userMessageCount:g.rows.filter(p=>p.kind==="user").length})}const o=await Ne(t).catch(()=>null),{order:i,sessions:l}=A.getState();if(i.length>0){const u=l[i[0]??""];if(u){const g=te(u.cwd||"~",o);A.getState().activate(u.id),x.getState().setCwd(u.cwd),I.getState().open({id:z.chat(u.id),kind:"chat",label:u.title,closable:!0,data:{sessionId:u.id},workspaceCwd:g})}}else{const u=x.getState().cwd||"~",g=te(u,o),p=A.getState().createSession(u);I.getState().open({id:z.chat(p),kind:"chat",label:"New chat",closable:!0,data:{sessionId:p},workspaceCwd:g})}})())},[e,t])}function ji(){v.useEffect(()=>{function t(e){const n=x.getState();if(e.key==="Escape"){n.closeCwdPicker(),n.closeSessionMenu();return}const s=e.ctrlKey||e.metaKey;if(s&&e.key.toLowerCase()==="t"){e.preventDefault(),lt(I.getState().activeWorkspaceCwd||"~");return}if(s&&e.key.toLowerCase()==="w"){const{activeTabId:r,tabs:o,close:i}=I.getState();if(!r)return;const l=o.find(d=>d.id===r);(l==null?void 0:l.closable)!==!1&&(e.preventDefault(),i(r))}}return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[])}function Ni(){return ki(),Ti(),ji(),null}function Ri(){return a.jsxs(Xn,{children:[a.jsx(Ni,{}),a.jsx(xi,{})]})}const ht=document.getElementById("root");if(!ht)throw new Error("Missing #root element");wt.createRoot(ht).render(a.jsx(v.StrictMode,{children:a.jsx(Ri,{})}));export{D as B,oi as D,Oo as S,Oi as T,C as a,I as b,Fi as e,Xo as r,Ar as t,A as u};
3
+ //# sourceMappingURL=index-DgUa1nu2.js.map