@evandu/super-pi 0.1.106 → 0.1.107

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.
@@ -70,7 +70,7 @@ WARNING: This link could potentially be dangerous`)){let e=window.open();if(e){t
70
70
  `,t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){this._addonManager.loadAddon(this,e)}static get strings(){return{get promptLabel(){return Yi.get()},set promptLabel(e){Yi.set(e)},get tooMuchOutput(){return Zi.get()},set tooMuchOutput(e){Zi.set(e)}}}_verifyIntegers(...e){for(kf of e)if(kf===1/0||isNaN(kf)||kf%1!=0)throw Error(`This API only accepts integers`)}_verifyPositiveIntegers(...e){for(kf of e)if(kf&&(kf===1/0||isNaN(kf)||kf%1!=0||kf<0))throw Error(`This API only accepts positive integers`)}},jf=2,Mf=1,Nf=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let t=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(e.css.cell.width===0||e.css.cell.height===0)return;let t=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,n=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(n.getPropertyValue(`height`)),i=Math.max(0,parseInt(n.getPropertyValue(`width`))),a=window.getComputedStyle(this._terminal.element),o={top:parseInt(a.getPropertyValue(`padding-top`)),bottom:parseInt(a.getPropertyValue(`padding-bottom`)),right:parseInt(a.getPropertyValue(`padding-right`)),left:parseInt(a.getPropertyValue(`padding-left`))},s=o.top+o.bottom,c=o.right+o.left,l=r-s,u=i-c-t;return{cols:Math.max(jf,Math.floor(u/e.css.cell.width)),rows:Math.max(Mf,Math.floor(l/e.css.cell.height))}}},Pf=`terminal-right-rail`,Ff=5,If=20,Lf=5,Rf=240,zf=120,Bf={checking:`检查中`,unavailable:`不可用`,starting:`启动中`,running:`运行中`,exited:`已结束`},$=e=>`${Pf}-${e}`,Vf=e=>({id:$(e),title:String(e),phase:`checking`});function Hf({workspaceId:e,workspaceLabel:t,connected:n,sendCommand:r,registerSink:i}){let[a,o]=(0,p.useState)(()=>[Vf(1)]),[s,c]=(0,p.useState)(()=>$(1)),l=(0,p.useRef)(s);l.current=s;let u=(0,p.useRef)(a);u.current=a;let d=(0,p.useRef)(e);d.current=e;let f=(0,p.useRef)(r);f.current=r;let h=(0,p.useRef)(new Set),g=(0,p.useRef)(!1),_=(0,p.useRef)(new Map),v=(0,p.useRef)(new Map),y=(0,p.useRef)(new Map),[b,x]=(0,p.useState)(0),S=(0,p.useRef)(n),C=(0,p.useCallback)(e=>{_.current.get(e)?.dispose(),_.current.delete(e),v.current.delete(e),y.current.delete(e)},[]),w=(0,p.useCallback)(e=>{let t=_.current.get(e),n=v.current.get(e);if(!t||!n)return;let r=y.current.get(e);if(!(!r||r.clientWidth<2||r.clientHeight<2)){try{n.fit()}catch{return}t.cols<If||t.rows<Lf||t.cols>Rf||t.rows>zf||h.current.has(e)&&f.current({type:`terminal.resize`,sessionId:e,cols:t.cols,rows:t.rows})}},[]),T=(0,p.useCallback)((e,t)=>{if(!t){y.current.delete(e);return}if(y.current.set(e,t),_.current.has(e))return;let n=getComputedStyle(t),r=(e,t)=>n.getPropertyValue(e).trim()||t,i=new Af({cursorBlink:!0,convertEol:!1,scrollback:5e3,fontFamily:`Consolas, 'Cascadia Mono', 'DejaVu Sans Mono', monospace`,fontSize:12,lineHeight:1.35,theme:{background:`#00000000`,foreground:r(`--term-fg`,`#dbe4f0`),cursor:r(`--term-fg`,`#dbe4f0`),selectionBackground:r(`--term-selection`,`#3a4f6b`)},allowProposedApi:!0}),a=new Nf;i.loadAddon(a),i.open(t),i.onData(t=>{h.current.has(e)&&f.current({type:`terminal.input`,sessionId:e,data:t})}),i.onResize(({cols:t,rows:n})=>{h.current.has(e)&&f.current({type:`terminal.resize`,sessionId:e,cols:t,rows:n})}),_.current.set(e,i),v.current.set(e,a),requestAnimationFrame(()=>w(e)),x(e=>e+1)},[w]),E=(0,p.useCallback)(e=>{_.current.get(e)?.reset()},[]),D=(0,p.useCallback)(e=>{let t=d.current,n=_.current.get(e);if(!t||!n||h.current.has(e))return;n.reset(),w(e),o(t=>t.map(t=>t.id===e?{...t,phase:`starting`,exitCode:void 0,reason:``}:t));let r=Math.max(If,Math.min(Rf,n.cols||80)),i=Math.max(Lf,Math.min(zf,n.rows||24));f.current({type:`terminal.open`,sessionId:e,workspaceId:t,cols:r,rows:i})?(h.current.add(e),o(t=>t.map(t=>t.id===e?{...t,phase:`running`}:t))):o(t=>t.map(t=>t.id===e?{...t,phase:`exited`,reason:`Super Pi 服务的连接尚未就绪`}:t))},[w]);(0,p.useEffect)(()=>{let e=!1;return fetch(`/api/terminal`).then(e=>e.json()).then(t=>{e||(t.enabled?(g.current=!0,o(e=>e.map(e=>e.phase===`checking`?{...e,phase:`starting`}:e))):o(e=>e.map(e=>({...e,phase:`unavailable`,reason:t.reason??`终端未启用`}))))}).catch(()=>{e||o(e=>e.map(e=>({...e,phase:`unavailable`,reason:`无法读取终端状态`})))}),()=>{e=!0}},[]),(0,p.useEffect)(()=>{if(g.current)for(let e of a)(e.phase===`checking`||e.phase===`starting`)&&!h.current.has(e.id)&&D(e.id)},[a,D,b]);let ee=(0,p.useCallback)(e=>{e.type===`terminal.output`?_.current.get(e.sessionId)?.write(e.data):e.type===`terminal.exit`?(h.current.delete(e.sessionId),E(e.sessionId),o(t=>t.map(t=>t.id===e.sessionId?{...t,phase:`exited`,exitCode:e.exitCode}:t))):e.type===`terminal.error`?(h.current.delete(e.sessionId),E(e.sessionId),o(t=>t.map(t=>t.id===e.sessionId?{...t,phase:`exited`,reason:e.message}:t))):e.type===`terminal.status`&&!e.enabled&&o(t=>t.map(t=>({...t,phase:`unavailable`,reason:e.reason??`终端未启用`})))},[E]);(0,p.useEffect)(()=>(i(ee),()=>i(void 0)),[ee,i]),(0,p.useEffect)(()=>()=>{for(let e of h.current)f.current({type:`terminal.close`,sessionId:e});h.current.clear();for(let e of _.current.keys())C(e)},[C]),(0,p.useEffect)(()=>{let e=n&&!S.current;S.current=n,e&&o(e=>e.map(e=>e.phase===`exited`&&!e.deliberate?{...e,phase:`starting`,reason:``}:e))},[n]),(0,p.useLayoutEffect)(()=>{let e=new ResizeObserver(()=>w(l.current));for(let t of y.current.values())e.observe(t);return w(l.current),()=>e.disconnect()},[w,a,b]);let O=(0,p.useCallback)(e=>{c(e),requestAnimationFrame(()=>w(e))},[w]),te=(0,p.useCallback)(()=>{let e=new Set(u.current.map(e=>e.title)),t=1;for(;e.has(String(t));)t+=1;let n=Vf(t);o(e=>e.length>=Ff?e:[...e,n]),c(n.id)},[]),ne=(0,p.useCallback)(e=>{f.current({type:`terminal.close`,sessionId:e}),h.current.delete(e),C(e),o(t=>{if(t.length<=1)return t;let n=t.findIndex(t=>t.id===e),r=t.filter(t=>t.id!==e);return l.current===e&&c(r[Math.min(n,r.length-1)].id),r})},[C]),re=(0,p.useCallback)(()=>{let e=l.current;f.current({type:`terminal.close`,sessionId:e}),h.current.delete(e),o(t=>t.map(t=>t.id===e?{...t,phase:`exited`,deliberate:!0}:t))},[]),k=a.find(e=>e.id===s)??a[0];return k?k.phase===`checking`?(0,m.jsx)(`p`,{className:`rail-empty`,"data-terminal-phase":`checking`,children:`正在检查终端状态…`}):k.phase===`unavailable`?(0,m.jsxs)(`div`,{className:`terminal-unavailable`,"data-terminal-phase":`unavailable`,children:[(0,m.jsx)(`p`,{className:`terminal-unavailable-reason`,children:k.reason}),(0,m.jsx)(`p`,{className:`rail-empty`,children:`终端仅接受本机与局域网连接。`})]}):(0,m.jsxs)(`div`,{className:`terminal-panel`,"data-terminal-panel":`1`,"data-terminal-phase":k.phase,children:[(0,m.jsxs)(`div`,{className:`terminal-strip`,role:`tablist`,"aria-label":`终端会话`,"data-terminal-strip":`1`,children:[a.map(e=>(0,m.jsxs)(`div`,{className:`terminal-tab${e.id===s?` is-active`:``}`,children:[(0,m.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":e.id===s,className:`terminal-tab-btn`,"data-terminal-slot":e.id,onClick:()=>O(e.id),title:Bf[e.phase],children:[(0,m.jsx)(`span`,{className:`terminal-tab-dot terminal-tab-dot-${e.phase}`,"aria-hidden":`true`}),e.title]}),(0,m.jsx)(`button`,{type:`button`,className:`terminal-tab-close`,"aria-label":`关闭终端 ${e.title}`,"data-terminal-slot-close":e.id,onClick:()=>ne(e.id),children:`×`})]},e.id)),a.length<Ff&&(0,m.jsx)(`button`,{type:`button`,className:`terminal-strip-add`,"data-terminal-add":`1`,onClick:te,title:`新建终端`,"aria-label":`新建终端`,children:`+`})]}),(0,m.jsxs)(`div`,{className:`terminal-toolbar`,children:[(0,m.jsxs)(`span`,{className:`terminal-status terminal-status-${k.phase}`,"data-terminal-status":k.phase,children:[(0,m.jsx)(`span`,{className:`terminal-status-dot`,"aria-hidden":`true`}),Bf[k.phase]]}),(0,m.jsxs)(`span`,{className:`terminal-toolbar-right`,children:[t&&(0,m.jsx)(`span`,{className:`terminal-cwd`,"data-terminal-hint":`1`,title:t,children:t}),k.phase===`running`?(0,m.jsx)(`button`,{type:`button`,className:`terminal-close-btn`,"data-terminal-close":`1`,onClick:re,children:`结束会话`}):(0,m.jsx)(`button`,{type:`button`,className:`terminal-restart-btn`,"data-terminal-restart":`1`,onClick:()=>D(k.id),children:`重新打开`})]})]}),k.reason&&(0,m.jsx)(`p`,{className:`tool-error`,"data-terminal-error":`1`,role:`alert`,children:k.reason}),k.phase===`exited`&&k.exitCode!==void 0&&k.exitCode!==0&&(0,m.jsxs)(`p`,{className:`tool-error`,"data-terminal-exit":`1`,children:[`会话已结束,退出码 `,k.exitCode,`。`]}),(0,m.jsx)(`div`,{className:`terminal-surface`,"data-terminal-surface":`1`,children:a.map(e=>(0,m.jsx)(`div`,{ref:t=>T(e.id,t),className:`terminal-xterm-host`,"data-terminal-xterm":e.id,style:{display:e.id===s?`block`:`none`}},e.id))})]}):null}var Uf=`.super-pi-tool.json`,Wf=512e3,Gf=/^[a-z0-9][a-z0-9-]{0,63}$/,Kf=/^[A-Za-z0-9][A-Za-z0-9_.-]*==[^=\s,;<>|'"`\\]{1,80}$/;function qf(e,t){let n;try{n=JSON.parse(e)}catch{return{ok:!1,reason:`「${t}」不是 JSON。确认一下选的是别人分享的工具文件(${Uf})。`}}if(!n||typeof n!=`object`||Array.isArray(n))return{ok:!1,reason:`这个 JSON 不是一个工具包。`};let r=n,i=typeof r.format==`string`?r.format:void 0;if(i!==void 0&&i!==`super-pi.tool`)return{ok:!1,reason:`这不是 Super Pi 的工具文件(format: ${i})。`};if(typeof r.version==`number`&&r.version>1)return{ok:!1,reason:`这个工具文件是更新版本的 Super Pi 导出的(version: ${r.version}),当前版本读不了。`};let a=typeof r.slug==`string`?r.slug.trim():``,o=typeof r.name==`string`?r.name.trim():``;if(!a)return{ok:!1,reason:`这个工具包里没有 slug(那是它的短名字,也是它在磁盘上的目录名)。`};if(!o)return{ok:!1,reason:`这个工具包里没有名字。`};if(!Array.isArray(r.files)||!r.files.length)return{ok:!1,reason:`这个工具包里没有文件。`};if(r.files.length>32)return{ok:!1,reason:`文件太多了:${r.files.length} 个,上限 32 个。`};let s=[],c=0;for(let e of r.files){let t=e;if(!t||typeof t.path!=`string`||typeof t.content!=`string`)return{ok:!1,reason:`工具包里的文件项格式不对(每一项都要有 path 和 content)。`};let n=t.path.trim();if(!n||n.startsWith(`/`)||n.includes(`\\`)||n.includes(`\0`)||n.split(`/`).includes(`..`))return{ok:!1,reason:`文件路径「${n}」不合法:不能是绝对路径,也不能跳出工具自己的目录。`};if(s.some(e=>e.path===n))return{ok:!1,reason:`工具包里有重复的文件:${n}`};if(c+=new TextEncoder().encode(t.content).length,c>512e3)return{ok:!1,reason:`工具文件合计超过 ${tp(Wf)} 的上限。`};s.push({path:n,content:t.content})}let l=typeof r.entrypoint==`string`&&r.entrypoint.trim()?r.entrypoint.trim():`index.html`;if(!l.endsWith(`.html`))return{ok:!1,reason:`入口文件必须是一个 HTML 文件。`};if(!s.some(e=>e.path===l))return{ok:!1,reason:`工具包里没有包含入口文件 ${l}。`};let u;if(r.script!==void 0&&r.script!==null){let e=r.script,t=typeof e.path==`string`?e.path.trim():``;if(!t.endsWith(`.py`))return{ok:!1,reason:`工具包声明的脚本必须是一个 .py 文件。`};if(!s.some(e=>e.path===t))return{ok:!1,reason:`工具包里没有包含它声明的脚本 ${t}。`};u={path:t,timeoutMs:typeof e.timeoutMs==`number`?e.timeoutMs:void 0,parameters:typeof e.parameters==`object`&&e.parameters!==null?e.parameters:void 0}}let d;if(r.environment!==void 0&&r.environment!==null){let e=r.environment,t=e.requires;if(t!==void 0&&!Array.isArray(t))return{ok:!1,reason:`工具包声明的依赖列表格式不对(requires 必须是数组)。`};if(Array.isArray(t)){for(let e of t)if(typeof e!=`string`||!Kf.test(e.trim()))return{ok:!1,reason:`依赖必须钉死到精确版本(写成 pkg==version):${String(e).slice(0,60)}。`}}let n=e.fingerprint&&typeof e.fingerprint==`object`?e.fingerprint:void 0;d={requiresPython:typeof e.requiresPython==`string`?e.requiresPython:void 0,requires:Array.isArray(t)?t.map(e=>String(e).trim()):void 0,fingerprint:n}}let f=r.permissions&&typeof r.permissions==`object`&&r.permissions.llm===!0?{llm:!0}:void 0;return{ok:!0,unnamedFormat:i===void 0,bundle:{...i===void 0?{}:{format:i},...typeof r.version==`number`?{version:r.version}:{},...typeof r.exportedAt==`string`?{exportedAt:r.exportedAt}:{},slug:a,name:o,...typeof r.description==`string`&&r.description.trim()?{description:r.description.trim().slice(0,500)}:{},entrypoint:l,files:s,script:u,environment:d,...f?{permissions:f}:{}}}}function Jf(e){let t=e.trim().toLowerCase();return t?Gf.test(t)?{ok:!0,slug:t}:{ok:!1,reason:`slug 只能用小写字母、数字和连字符,且要以字母或数字开头。`}:{ok:!1,reason:`请填写 slug(工具的短名字,只能用小写字母、数字和连字符)。`}}function Yf(e,t){let n=e.trim().toLowerCase().slice(0,60).replace(/[^a-z0-9-]+/g,`-`).replace(/^-+|-+$/g,``)||`tool`;if(!t.includes(n))return n;for(let e=2;e<100;e+=1){let r=`${n}-${e}`;if(!t.includes(r))return r}return n}function Xf(e){return`${e.slug}${Uf}`}function Zf(e){let t=e.trim().replace(/[\\/:*?"<>|]/g,``).replace(/\.+$/,``).trim();return t?t.length>80?{ok:!1,reason:`文件名太长了,请控制在 80 个字符以内。`}:{ok:!0,name:t.endsWith(`.super-pi-tool.json`)?t:`${t}${Uf}`}:{ok:!1,reason:`请填写文件名。`}}function Qf(e){if(e.permissions?.llm)return{tone:`warn`,text:`这个工具可以调用模型:它能把内容发给你的模型回答,每次调用都会用你的模型额度`}}function $f(e){let t=e.environment?.requires??[];return!e.script&&t.length===0?{tone:`ok`,text:`纯页面工具 · 导入即用,不需要 Python`}:t.length===0?{tone:`ok`,text:`只用 Python 标准库 · 导入即用,不需要安装任何包${e.environment?.requiresPython?`(需要 Python ${e.environment.requiresPython})`:``}`}:{tone:`warn`,text:`首次运行时会安装 ${t.length} 个依赖:${t.join(`、`)}(装进这个工具自己的虚拟环境)${e.environment?.requiresPython?` · 需要 Python ${e.environment.requiresPython}`:``}`}}function ep(e){if(e)return e.state===`zero-deps`?{text:`零依赖`,warn:!1}:e.state===`ready`?{text:`环境就绪`,warn:!1}:e.state===`needs-env`?{text:`首次运行时安装依赖`,warn:!1}:e.state===`needs-python`?{text:`缺少可用的 Python`,warn:!0}:{text:`与导出方环境不一致`,warn:!0}}function tp(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1048576).toFixed(1)} MB`}function np(e,t){let{format:n,version:r,exportedAt:i,...a}=e;return{...a,slug:t}}var rp={workspaces:[],conversations:[],subagentRuns:[]},ip=e=>e.nativeEvent.isComposing||e.keyCode===229,ap=(e,t,n)=>{let r=e.filter(e=>(e.role===`user`||e.role===`tool`)&&e.delivery),i=r.findIndex(e=>e.id===t);if(i<0||r[i].delivery===`sending`)return e;let a=r.reduce((e,t,n)=>t.delivery===`sending`?n:e,-1),o=Math.max(a+1,Math.min(n,r.length-1));if(o===i)return e;let s=[...r],[c]=s.splice(i,1);s.splice(o,0,c);let l=[...e],u=0;for(let e=0;e<l.length;e+=1)(l[e].role===`user`||l[e].role===`tool`)&&l[e].delivery&&(l[e]=s[u++]);return l},op=e=>{if(typeof e!=`string`||e.length===0)return``;let t=new Date(e);return Number.isNaN(t.getTime())?``:new Intl.DateTimeFormat(`zh-CN`,{hour:`2-digit`,minute:`2-digit`}).format(t)},sp=6e4,cp=60*sp,lp=24*cp,up=7*lp,dp=30*lp,fp=365*lp,pp=(e,t)=>{let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=t-n.getTime();return r<3e4?`now`:r<cp?`${Math.max(1,Math.floor(r/sp))}m ago`:r<lp?`${Math.floor(r/cp)}h ago`:r<up?`${Math.floor(r/lp)}d ago`:r<dp?`${Math.floor(r/up)}w ago`:r<fp?`${Math.floor(r/dp)}mo ago`:`${Math.floor(r/fp)}y ago`},mp=(e,t)=>e.updatedAt<t.updatedAt?1:e.updatedAt>t.updatedAt?-1:0,hp=(e,t)=>{let n=e.archivedAt??``,r=t.archivedAt??``;return n<r?1:n>r?-1:0},gp=e=>{if(!e)return``;let t=new Date(e);return Number.isNaN(t.getTime())?``:`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)}`},_p=1e3,vp=3e4,yp=async e=>{try{if(navigator.clipboard?.writeText)return await navigator.clipboard.writeText(e),!0}catch{}let t=document.createElement(`textarea`);t.value=e,t.setAttribute(`readonly`,``),t.style.cssText=`position:fixed;top:0;left:0;width:1px;height:1px;padding:0;border:0;opacity:0;pointer-events:none`,document.body.appendChild(t);try{return t.select(),t.setSelectionRange(0,t.value.length),document.execCommand(`copy`)}catch{return!1}finally{t.remove()}};function bp({workspace:e,x:t,y:n,notify:r,onClose:i}){let a=(0,p.useRef)(null),[o,s]=(0,p.useState)({left:t,top:n});(0,p.useLayoutEffect)(()=>{let e=a.current;if(!e)return;let r=e.getBoundingClientRect();s({left:Math.max(8,Math.min(t,window.innerWidth-r.width-8)),top:Math.max(8,Math.min(n,window.innerHeight-r.height-8))})},[t,n]),(0,p.useEffect)(()=>{let e=e=>{e.key===`Escape`&&(e.stopPropagation(),i())},t=e=>{a.current?.contains(e.target)||i()},n={x:window.scrollX,y:window.scrollY,width:window.innerWidth,height:window.innerHeight},r=()=>{(window.scrollX!==n.x||window.scrollY!==n.y)&&i()},o=()=>{(window.innerWidth!==n.width||window.innerHeight!==n.height)&&i()};return window.addEventListener(`keydown`,e,!0),window.addEventListener(`pointerdown`,t,!0),window.addEventListener(`scroll`,r,!0),window.addEventListener(`resize`,o),()=>{window.removeEventListener(`keydown`,e,!0),window.removeEventListener(`pointerdown`,t,!0),window.removeEventListener(`scroll`,i,!0),window.removeEventListener(`resize`,o)}},[i]);let c=async()=>{let t=await yp(e.path);i(),t?r(`已复制工作区路径:${e.path}`,`info`):r(`复制失败:浏览器拒绝了剪贴板写入,可以手动选中路径复制`,`error`)};return(0,m.jsxs)(`div`,{ref:a,className:`ctx-menu`,role:`menu`,"data-ctx-menu":`1`,"data-workspace-id":e.id,style:{left:o.left,top:o.top},onContextMenu:e=>e.preventDefault(),onPointerDown:e=>e.stopPropagation(),children:[(0,m.jsx)(`button`,{type:`button`,role:`menuitem`,className:`ctx-menu-item`,"data-copy-workspace-path":e.id,onClick:()=>void c(),children:`复制工作区路径`}),(0,m.jsx)(`div`,{className:`ctx-menu-hint`,"aria-hidden":`true`,children:e.path})]})}function xp({conversation:e,x:t,y:n,notify:r,onRename:i,onClose:a}){let o=(0,p.useRef)(null),[s,c]=(0,p.useState)({left:t,top:n});(0,p.useLayoutEffect)(()=>{let e=o.current;if(!e)return;let r=e.getBoundingClientRect();c({left:Math.max(8,Math.min(t,window.innerWidth-r.width-8)),top:Math.max(8,Math.min(n,window.innerHeight-r.height-8))})},[t,n]),(0,p.useEffect)(()=>{let e=e=>{e.key===`Escape`&&(e.stopPropagation(),a())},t=e=>{o.current?.contains(e.target)||a()},n={x:window.scrollX,y:window.scrollY,width:window.innerWidth,height:window.innerHeight},r=()=>{(window.scrollX!==n.x||window.scrollY!==n.y)&&a()},i=()=>{(window.innerWidth!==n.width||window.innerHeight!==n.height)&&a()};return window.addEventListener(`keydown`,e,!0),window.addEventListener(`pointerdown`,t,!0),window.addEventListener(`scroll`,r,!0),window.addEventListener(`resize`,i),()=>{window.removeEventListener(`keydown`,e,!0),window.removeEventListener(`pointerdown`,t,!0),window.removeEventListener(`scroll`,a,!0),window.removeEventListener(`resize`,i)}},[a]);let l=async()=>{let t=await yp(e.id);a(),t?r(`已复制会话 ID:${e.id}`,`info`):r(`复制失败:浏览器拒绝了剪贴板写入`,`error`)};return(0,m.jsxs)(`div`,{ref:o,className:`ctx-menu`,role:`menu`,"data-ctx-menu":`1`,"data-session-id":e.id,style:{left:s.left,top:s.top},onContextMenu:e=>e.preventDefault(),onPointerDown:e=>e.stopPropagation(),children:[(0,m.jsx)(`button`,{type:`button`,role:`menuitem`,className:`ctx-menu-item`,"data-copy-session-id":e.id,onClick:()=>void l(),children:`复制会话 ID`}),(0,m.jsx)(`button`,{type:`button`,role:`menuitem`,className:`ctx-menu-item`,"data-ai-rename-session":e.id,onClick:()=>{a(),i()},children:`AI 智能重命名`}),(0,m.jsx)(`div`,{className:`ctx-menu-hint`,"aria-hidden":`true`,children:e.id})]})}var Sp={model:`模型`,thinking:`思考`,agent:`智能体`,subagent:`子智能体`},Cp={model:`模型`,thinking:`思考等级`,agent:`智能体`,subagent:`子智能体`},wp={model:`选择模型`,thinking:`选择思考等级`,agent:`选择智能体`,subagent:`选择子智能体`},Tp=`图文`,Ep=e=>e.imageInput?Tp:void 0,Dp=e=>e.normalize(`NFKD`).replace(/\p{M}/gu,``).toLowerCase(),Op=(e,t)=>{let n=Dp(t.trim());return n?e.filter(e=>Dp(`${e.label} ${e.detail??``} ${e.badge??``}`).includes(n)):e};function kp({onClose:e,onCreate:t}){let[n,r]=(0,p.useState)(),[i,a]=(0,p.useState)(!0),[o,s]=(0,p.useState)(),[c,l]=(0,p.useState)(``),[u,d]=(0,p.useState)(``),f=async e=>{a(!0),s(void 0);try{let t=await fetch(`/api/fs/dirs${e?`?path=${encodeURIComponent(e)}`:``}`),n=await t.json();if(!t.ok)throw Error(n.error??`HTTP ${t.status}`);let i=n;r(i),d(i.path),l(i.suggestedName)}catch(e){s(e instanceof Error?e.message:`目录加载失败`)}finally{a(!1)}};(0,p.useEffect)(()=>{f()},[]),(0,p.useEffect)(()=>{let t=t=>{t.key===`Escape`&&e()};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[e]);let h=e=>{e?.preventDefault();let t=u.trim();t&&f(t)};return(0,m.jsx)(`div`,{className:`overlay`,onClick:e,children:(0,m.jsxs)(`div`,{className:`picker workspace-picker`,onClick:e=>e.stopPropagation(),children:[(0,m.jsx)(`h2`,{children:`选择工作区目录`}),(0,m.jsxs)(`form`,{className:`picker-path-bar`,onSubmit:h,children:[(0,m.jsx)(`input`,{className:`picker-path-input`,value:u,onChange:e=>d(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(ip(e)?e.preventDefault():(e.preventDefault(),h()))},placeholder:`输入或粘贴目录绝对路径(如 D:\\projects 或 ~/code)`}),(0,m.jsx)(`button`,{type:`submit`,className:`picker-go-btn`,disabled:!u.trim()||i,children:`跳转`}),(0,m.jsx)(`button`,{type:`button`,className:`picker-up-btn`,disabled:!n?.parent||i,onClick:()=>n?.parent&&void f(n.parent),title:`返回上一级目录`,children:`上一级`})]}),n?.drives?.length||n?.homeDir?(0,m.jsxs)(`div`,{className:`picker-shortcuts`,children:[(0,m.jsx)(`span`,{className:`picker-shortcuts-label`,children:`快捷位置:`}),n?.homeDir&&(0,m.jsx)(`button`,{type:`button`,className:`picker-shortcut`,onClick:()=>void f(`~`),title:n.homeDir,children:`🏠 主目录`}),n?.drives?.map(e=>(0,m.jsx)(`button`,{type:`button`,className:`picker-shortcut`,onClick:()=>void f(e),children:e},e))]}):null,(0,m.jsxs)(`div`,{className:`picker-list`,children:[i&&(0,m.jsx)(`div`,{className:`picker-status`,children:`加载中…`}),!i&&o&&(0,m.jsxs)(`div`,{className:`picker-error`,children:[o,(0,m.jsx)(`button`,{onClick:()=>void f(n?.path||u),children:`重试`})]}),!i&&!o&&n?.entries.map(e=>(0,m.jsxs)(`button`,{className:`picker-dir`,onClick:()=>void f(e.path),children:[`📁 `,e.name]},e.path)),!i&&!o&&n&&n.entries.length===0&&(0,m.jsx)(`div`,{className:`picker-status`,children:`此目录下没有子目录`}),!i&&!o&&n?.truncated&&(0,m.jsx)(`div`,{className:`picker-status`,children:`目录过多,仅显示前 2000 项`})]}),(0,m.jsxs)(`label`,{className:`picker-name`,children:[`工作区名称`,(0,m.jsx)(`input`,{value:c,onChange:e=>l(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(ip(e)?e.preventDefault():(e.preventDefault(),c.trim()&&n&&t(c.trim(),n.path)))},placeholder:`工作区名称`})]}),(0,m.jsxs)(`div`,{className:`picker-actions`,children:[(0,m.jsx)(`button`,{className:`picker-cancel`,onClick:e,children:`取消`}),(0,m.jsx)(`button`,{className:`picker-ok`,disabled:!c.trim()||i||!!o||!n,onClick:()=>n&&t(c.trim(),n.path),children:`使用这个目录`})]})]})})}var Ap={timeout:`扩展提问超时,已取消`,aborted:`运行已停止,扩展提问已取消`,expired:`运行已结束,扩展提问已取消`},jp=10;function Mp(e,t){if(!t)return`正在从 Pi 读取${e}列表…`;if(t.source!==`pi`)return`读取 Pi ${e}列表失败:${t.error??`未知原因`}`}function Np(e){if(!e)return`正在读取 agent 列表…`;if(e.source!==`directory`)return`读取 agent 列表失败:${e.error??`未知原因`}`;if(e.problems.length)return`${e.problems.length} 个 agent 文件无法使用:${e.problems.map(e=>e.file).join(`、`)}`;if(!e.agents.length)return`${e.directory} 下没有 primary agent`}var Pp=e=>Math.abs(e)<1e3?String(e):`${(e/1e3).toFixed(1).replace(/\.0$/,``)}k`;function Fp(e){if(e===void 0||!Number.isFinite(e))return``;let t=Math.max(0,e);return t<1e3?`${Math.round(t)}ms`:t<6e4?`${(t/1e3).toFixed(1)}s`:`${Math.floor(t/6e4)}分${Math.round(t%6e4/1e3)}秒`}var Ip={dispatch:`派发时(子进程还没起来)`,prompt:`派活时(Pi 拒收了任务)`,turn:`生成回答时`,tool:`调用工具时`,settle:`收尾时`};function Lp({task:e,initialOutput:t,expanded:n}){let[r,i]=(0,p.useState)(t);(0,p.useEffect)(()=>{let n=t,r,a=t=>{let a=t.detail;a.sessionId===e.id&&(n=(n+a.data).slice(-512e3),r===void 0&&(r=requestAnimationFrame(()=>{r=void 0,i(n)})))};return window.addEventListener(`super-pi-exec-output`,a),()=>{window.removeEventListener(`super-pi-exec-output`,a),r!==void 0&&cancelAnimationFrame(r)}},[e.id]);let a=e.output??r;return(0,m.jsxs)(m.Fragment,{children:[!n&&a&&(0,m.jsx)(`div`,{className:`call-live-preview`,"data-background-preview":e.id,title:`展开调用查看完整输出`,children:a.split(`
71
71
  `).slice(-1)[0]}),n&&(0,m.jsx)(`pre`,{className:`call-result-body`,"data-background-output":e.id,children:a||`等待输出…`})]})}function Rp({call:e,index:t,expanded:n,onToggle:r,backgroundOutput:i,runCard:a}){let o=e.args??[];return(0,m.jsxs)(`div`,{className:`call-block call-block-${e.status??`running`}`,"data-call-block":t,"data-call-tool":e.label,"data-call-detail":e.detail??void 0,"data-call-status":e.status??`running`,"data-call-expanded":n?`true`:`false`,"data-call-arg-count":o.length,"data-thinking-at":e.thinkingAt,"data-background-exec":e.backgroundTask?.id,"data-background-status":e.backgroundTask?.status,children:[(0,m.jsx)(`button`,{type:`button`,className:`call-fold-edge`,"data-call-fold-edge":t,"aria-expanded":n,"aria-label":`${n?`折叠`:`展开`} ${e.label} 调用`,title:n?`折叠这次调用`:`展开这次调用`,onClick:r}),(0,m.jsxs)(`div`,{className:`call-head-row`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`call-head`,"data-call-head":t,"aria-expanded":n,onClick:r,children:[(0,m.jsx)(`span`,{className:`call-chevron`,"aria-hidden":`true`,children:n?`▾`:`▸`}),(0,m.jsx)(`span`,{className:`call-glyph`,"aria-hidden":`true`,children:e.status===`error`?`✕`:e.status===`ok`?`✓`:`·`}),(0,m.jsx)(`span`,{className:`call-label`,title:e.label,children:e.label}),e.detail&&(0,m.jsx)(`span`,{className:`call-detail`,title:e.detail,children:e.detail}),e.durationMs!==void 0&&(0,m.jsx)(`span`,{className:`call-duration`,children:Fp(e.durationMs)}),e.backgroundTask&&(0,m.jsxs)(`span`,{className:`call-background-status`,"data-background-status-text":e.backgroundTask.status,children:[`后台任务 · `,e.backgroundTask.status===`running`?`进行中`:e.backgroundTask.status===`completed`?`已完成`:`失败`,e.backgroundTask.exitCode===void 0?``:` · 退出码:${e.backgroundTask.exitCode}`]}),e.preparing&&(0,m.jsx)(`span`,{className:`call-preparing`,"data-call-preparing":t,children:`生成参数中…`})]}),n&&(0,m.jsx)(`button`,{type:`button`,className:`call-fold-top`,"data-call-fold-top":t,onClick:r,children:`收起`})]}),!n&&e.live&&(0,m.jsx)(`div`,{className:`call-live-preview`,"data-call-live-preview":t,title:`展开查看完整输出`,children:e.live.split(`
72
72
  `).slice(-1)[0]}),n&&(0,m.jsx)(`div`,{className:`call-args`,"data-call-args":o.length,children:o.length===0?(0,m.jsx)(`div`,{className:`call-arg call-arg-empty`,"data-call-arg-empty":t,children:`(这次调用没有可显示的参数)`}):o.map(e=>(0,m.jsxs)(`div`,{className:`call-arg`,"data-call-arg":e.key,"data-call-arg-value":e.value,children:[(0,m.jsx)(`span`,{className:`call-arg-key`,children:e.key}),(0,m.jsx)(`span`,{className:`call-arg-value`,title:e.value,children:e.value})]},e.key))}),n&&(e.result||e.live||i)&&(0,m.jsxs)(`div`,{className:`call-result`,"data-call-result":t,"data-call-result-state":e.result?`done`:`running`,children:[(e.result||e.live)&&(0,m.jsxs)(`div`,{className:`call-result-head`,children:[(0,m.jsx)(`span`,{className:`call-result-title`,children:e.result&&!e.live?`执行结果`:e.result?`执行结果 · 完整输出`:`执行中 · 输出预览`}),e.result?(0,m.jsx)(zp,{index:t,text:e.live??e.result.text}):null]}),(e.result||e.live)&&(0,m.jsx)(`pre`,{className:`call-result-body`,"data-call-result-body":t,children:e.live??e.result?.text}),e.result?.truncated&&e.live&&(0,m.jsx)(`div`,{className:`call-result-truncated`,children:`(服务端已截断到末尾 8 KB;上方显示的是执行中累积的完整输出)`}),e.result?.truncated&&!e.live&&(0,m.jsxs)(`div`,{className:`call-result-truncated`,children:[`(输出过长,已保留末尾关键内容`,e.result.droppedLines?`,省略前 ${e.result.droppedLines} 行`:``,`)`]}),i]}),!n&&i,a]})}function zp({index:e,text:t}){let[n,r]=(0,p.useState)(!1);return(0,m.jsx)(`button`,{type:`button`,className:`call-result-copy`,"data-call-result-copy":e,onClick:async()=>{await yp(t)&&(r(!0),window.setTimeout(()=>r(!1),1600))},children:n?`已复制`:`复制`})}function Bp({messageId:e,nestedCount:t,liveCall:n,liveExtra:r,preview:i,expanded:a,onToggle:o,children:s}){return(0,m.jsxs)(`section`,{className:`thinking-block`,"data-thinking-block":e,"data-thinking-expanded":a?`true`:`false`,"data-thinking-calls":t,children:[(0,m.jsx)(`button`,{type:`button`,className:`call-fold-edge`,"data-thinking-fold-edge":e,"aria-expanded":a,"aria-label":`${a?`折叠`:`展开`}这段思考`,title:a?`折叠这段思考`:`展开这段思考`,onClick:o}),(0,m.jsxs)(`button`,{type:`button`,className:`thinking-head`,"data-thinking-head":e,"aria-expanded":a,title:a?`折叠这段思考`:`展开这段思考`,onClick:o,children:[(0,m.jsx)(`span`,{className:`thinking-chevron`,"aria-hidden":`true`,children:a?`▾`:`▸`}),(0,m.jsx)(`span`,{className:`thinking-label`,children:`思考`}),t>0&&(0,m.jsxs)(`span`,{className:`thinking-count`,"data-thinking-count":t,children:[t,` 次工具调用`]}),!a&&n&&(0,m.jsxs)(`span`,{className:`thinking-live`,"data-thinking-live":n,"data-thinking-live-extra":r??0,children:[(0,m.jsx)(`span`,{className:`thinking-live-glyph`,"aria-hidden":`true`,children:`⚙`}),`正在执行 `,n,r?` 等 ${r+1} 个`:``]}),!a&&i&&(0,m.jsx)(`span`,{className:`thinking-preview`,title:i,children:i})]}),a&&(0,m.jsx)(`div`,{className:`thinking-body`,"data-thinking-body":e,children:s})]})}function Vp({run:e,name:t,expanded:n,onToggle:r,onStop:i,stopping:a}){let o=e.toolCalls??[],s=n?o:o.slice(-10),c=o.length-s.length,l=e.status===`running`,u=e.output??``,d=e.dispatchedBy===`model`,[f,h]=(0,p.useState)(0);(0,p.useEffect)(()=>{if(!l)return;h(Date.now());let e=window.setInterval(()=>h(Date.now()),200);return()=>window.clearInterval(e)},[l,e.startedAt]);let g=Date.parse(e.startedAt),_=l&&f>0&&Number.isFinite(g)?f-g:void 0,v=[...o].reverse().find(e=>e.status===void 0)?.label;return(0,m.jsxs)(`article`,{className:`subagent-card subagent-${e.status}${d?` subagent-by-model`:``}`,"data-subagent-card":e.id,"data-subagent-status":e.status,"data-subagent-agent":e.agentId,"data-subagent-tools":o.length,"data-subagent-dispatched-by":d?`model`:`human`,children:[(0,m.jsxs)(`div`,{className:`subagent-head`,children:[(0,m.jsx)(`span`,{className:`subagent-badge`,children:`子智能体`}),d&&(0,m.jsxs)(`span`,{className:`subagent-source`,"data-subagent-source":`model`,title:`primary 模型自己决定派这个子智能体去干活`,children:[(0,m.jsx)(`span`,{className:`subagent-source-glyph`,"aria-hidden":`true`,children:`⚡`}),`模型自主派发`]}),(0,m.jsx)(`strong`,{className:`subagent-name`,"data-subagent-name":`1`,children:t||e.agentId}),(0,m.jsx)(`span`,{className:`subagent-status`,"data-subagent-status-text":`1`,children:l?`运行中`:e.status===`completed`?`已完成`:e.status===`stopped`?`已停止`:`失败`}),l?_!==void 0&&(0,m.jsxs)(`span`,{className:`subagent-clock`,"data-subagent-elapsed":`1`,"data-subagent-elapsed-ms":_,children:[`已运行 `,Fp(_)]}):e.durationMs!==void 0&&(0,m.jsxs)(`span`,{className:`subagent-duration`,"data-subagent-duration":`1`,"data-subagent-duration-ms":e.durationMs,children:[`用时 `,Fp(e.durationMs)]}),l&&(0,m.jsx)(`button`,{type:`button`,className:`subagent-stop`,"data-subagent-stop":e.id,disabled:a,onClick:i,children:`停止`})]}),l&&e.activity&&(0,m.jsxs)(`div`,{className:`subagent-activity`,"data-subagent-activity":e.activity.kind,"data-subagent-activity-at":e.activity.at,children:[(0,m.jsx)(`span`,{className:`subagent-activity-dot`,"aria-hidden":`true`}),e.activity.kind===`tool`?`正在调用 ${e.activity.label??`工具`}`:`正在思考…`]}),(0,m.jsxs)(`div`,{className:`subagent-task`,"data-subagent-task":`1`,children:[d&&(0,m.jsx)(`span`,{className:`subagent-task-source`,"data-subagent-model-task":`1`,children:`模型给的任务`}),e.task]}),(0,m.jsx)(`div`,{className:`subagent-output`,"data-subagent-output":`1`,"data-live-length":u.length,children:u||(l?`…`:e.outputTruncated?`(已按 50 KB 上限截断,浏览器仍收到完整内容)`:`(没有输出)`)}),e.failure&&(0,m.jsxs)(`div`,{className:`subagent-failure`,"data-subagent-failure":`1`,"data-subagent-failure-stage":e.failure.stage,children:[(0,m.jsx)(`span`,{className:`subagent-failure-label`,children:`卡在`}),(0,m.jsx)(`span`,{className:`subagent-failure-stage`,"data-subagent-failure-text":`1`,children:Ip[e.failure.stage]}),e.failure.stage===`tool`&&v&&(0,m.jsxs)(`span`,{className:`subagent-failure-tool`,"data-subagent-failure-tool":`1`,children:[`· 正在跑 `,v]}),o.length>0&&(0,m.jsxs)(`span`,{className:`subagent-failure-progress`,children:[`· 死前已尝试 `,o.length,` 次工具调用`]})]}),e.error&&(0,m.jsx)(`div`,{className:`subagent-error`,"data-subagent-error":`1`,children:e.error}),o.length>0&&(0,m.jsxs)(`div`,{className:`subagent-tools`,"data-subagent-tool-count":o.length,children:[c>0&&!n&&(0,m.jsxs)(`button`,{type:`button`,className:`subagent-more`,"data-subagent-hidden":c,onClick:r,children:[`… 另有 `,c,` 条工具调用`]}),s.map((e,t)=>(0,m.jsxs)(`div`,{className:`subagent-tool${e.status?` subagent-tool-${e.status}`:``}`,"data-subagent-tool":e.label,"data-subagent-tool-detail":e.detail??void 0,"data-subagent-tool-status":e.status??`running`,children:[(0,m.jsx)(`span`,{className:`subagent-tool-glyph`,"aria-hidden":`true`,children:e.status===`error`?`✕`:e.status===`ok`?`✓`:`·`}),(0,m.jsx)(`span`,{className:`subagent-tool-label`,title:e.label,children:e.label}),e.detail&&(0,m.jsx)(`span`,{className:`subagent-tool-detail`,title:e.detail,children:e.detail}),e.durationMs!==void 0&&(0,m.jsx)(`span`,{className:`subagent-tool-duration`,children:Fp(e.durationMs)})]},`${t}:${e.label}`))]}),e.usage&&(0,m.jsxs)(`div`,{className:`subagent-usage`,"data-subagent-usage":`1`,"data-subagent-turns":e.usage.turns,children:[(0,m.jsxs)(`span`,{children:[e.usage.turns,` turns`]}),(0,m.jsxs)(`span`,{children:[`↑`,Pp(e.usage.input)]}),(0,m.jsxs)(`span`,{children:[`↓`,Pp(e.usage.output)]}),e.usage.cacheRead>0&&(0,m.jsxs)(`span`,{children:[`cache↓`,Pp(e.usage.cacheRead)]}),e.usage.cacheWrite>0&&(0,m.jsxs)(`span`,{children:[`cache↑`,Pp(e.usage.cacheWrite)]}),e.usage.cost>0&&(0,m.jsxs)(`span`,{children:[`$`,e.usage.cost.toFixed(4)]})]}),o.length>10&&(0,m.jsx)(`button`,{type:`button`,className:`subagent-collapse`,"data-subagent-collapse":e.id,"aria-expanded":n,onClick:r,children:n?`收起`:`展开全部 ${o.length} 条`})]})}function Hp({messages:e,running:t,onSteer:n,onInterrupt:r,onSend:i,onCancel:a,onEdit:o}){let[s,c]=(0,p.useState)(!1);if(!e.length)return null;let l=e.filter(e=>e.delivery===`sending`).length;return(0,m.jsxs)(`section`,{className:`queue-dock`,"data-queue-dock":`1`,"data-queue-count":e.length,"data-queue-sending":l,"aria-label":`排队等待回答的消息`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`queue-dock-head`,"data-queue-collapse":`1`,"aria-expanded":!s,onClick:()=>c(e=>!e),children:[(0,m.jsx)(`span`,{className:`chevron`,children:s?`▸`:`▾`}),(0,m.jsxs)(`strong`,{children:[e.length,` 条等待回答`]}),l>0&&(0,m.jsxs)(`span`,{className:`queue-dock-badge`,"data-queue-badge":`sending`,children:[`已交给 Agent `,l,` 条`]}),s&&(0,m.jsx)(`span`,{className:`queue-dock-preview`,children:Up(e[0])})]}),!s&&(0,m.jsx)(`ul`,{className:`queue-dock-list`,children:e.map((s,c)=>(0,m.jsx)(Gp,{message:s,order:c+1,total:e.length,running:t,onSteer:n,onInterrupt:r,onSend:i,onCancel:a,onEdit:o},s.id))})]})}function Up(e){return e.content||(e.images?.length?`【图片】(${e.images.length})`:``)}function Wp(e){if(e.role!==`tool`)return{label:`后台回传`,state:`completed`};let t=(()=>{let t=/<summary>([\s\S]*?)<\/summary>/.exec(e.content);return t?t[1].trim():`后台回传`})(),n=/<task id="[^"]+" state="([^"]+)"/.exec(e.content);return{label:t,state:n?n[1]:`completed`}}function Gp({message:e,order:t,total:n,running:r,onSteer:i,onInterrupt:a,onSend:o,onCancel:s,onEdit:c}){let[l,u]=(0,p.useState)(!1),[d,f]=(0,p.useState)(e.content),h=e.delivery===`sending`,g=e.role===`tool`,{label:_,state:v}=g?Wp(e):{label:Up(e),state:`user`},y=()=>{let t=d.trim();t&&t!==e.content&&c(e.id,t),u(!1)};return(0,m.jsxs)(`li`,{className:`queue-row ${h?`queue-row-sending`:`queue-row-queued`} ${g?`queue-row-bg-result`:``}`,"data-queue-id":e.id,"data-message-delivery":e.delivery,"data-message-role":e.role,"data-bg-result-state":g?v:void 0,"data-waiting-order":t,"data-waiting-total":n,children:[(0,m.jsx)(`span`,{className:`queue-index`,"aria-hidden":`true`,children:t}),g?(0,m.jsxs)(`span`,{className:`queue-bg-result`,title:_,children:[(0,m.jsx)(`span`,{className:`bg-result-glyph`,"aria-hidden":`true`,children:v===`error`?`✕`:`↩`}),(0,m.jsx)(`span`,{className:`bg-result-label`,children:`后台回传`}),(0,m.jsx)(`span`,{className:`bg-result-summary`,children:_})]}):l?(0,m.jsxs)(`div`,{className:`queue-row-edit`,children:[(0,m.jsx)(`textarea`,{value:d,autoFocus:!0,rows:2,"aria-label":`修改这条等待中的消息`,onChange:e=>f(e.target.value),onKeyDown:t=>{t.key===`Escape`&&(t.preventDefault(),f(e.content),u(!1)),t.key===`Enter`&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),y())}}),(0,m.jsx)(`button`,{type:`button`,className:`queue-edit-save`,"data-waiting-save":e.id,onClick:y,children:`保存`}),(0,m.jsx)(`button`,{type:`button`,className:`queue-edit-cancel`,"data-waiting-cancel-edit":e.id,onClick:()=>{f(e.content),u(!1)},children:`取消`})]}):(0,m.jsx)(`span`,{className:`queue-text`,title:_,children:_}),(0,m.jsx)(`span`,{className:`queue-state`,"data-waiting-state":h?`sending`:`queued`,children:h?`已交给 Agent`:t===1?`下一条回答这条`:`等待回答 · 第 ${t} 条`}),h?(0,m.jsx)(`span`,{className:`queue-locked`,"data-waiting-locked":e.id,children:`暂时改不了`}):(0,m.jsxs)(m.Fragment,{children:[r?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`button`,{type:`button`,className:`queue-interrupt`,"data-waiting-interrupt":e.id,title:`停止当前任务,立即回答这条消息`,"aria-label":`停止当前任务并回答「${_}」`,onClick:()=>a(e.id),children:`打断并回答`}),(0,m.jsx)(`button`,{type:`button`,className:`queue-steer`,"data-waiting-steer":e.id,title:t===1?`当前工具完成后回答这条消息`:`插到最前:让它成为下一条被回答的消息`,"aria-label":t===1?`当前工具完成后回答「${_}」`:`让「${_}」插到最前`,onClick:()=>i(e.id),children:t===1?`当前工具完成后回答`:`插到最前`})]}):(0,m.jsx)(`button`,{type:`button`,className:`queue-steer`,"data-waiting-send":e.id,title:`现在就回答这条消息`,"aria-label":`现在就回答「${_}」`,onClick:()=>o(e.id),children:`现在就回答`}),!g&&(0,m.jsx)(`button`,{type:`button`,className:`queue-edit`,"data-waiting-edit":e.id,title:`回答这条之前改字`,"aria-label":`修改「${_}」`,onClick:()=>{f(e.content),u(!0)},children:`改字`}),(0,m.jsx)(`button`,{type:`button`,className:`queue-cancel`,"data-waiting-cancel":e.id,title:`撤回这条消息,它不会被回答`,"aria-label":`撤回「${_}」`,onClick:()=>s(e.id),children:`撤回`})]})]})}function Kp({question:e,index:t,expanded:n,onToggle:r,onAnswer:i}){return(0,m.jsxs)(`div`,{className:`call-block question-block-${e.status}`,"data-call-block":t,"data-call-tool":`question`,"data-call-detail":`提问`,"data-call-status":e.status===`answered`?`ok`:e.status===`cancelled`?`error`:`running`,"data-call-expanded":n?`true`:`false`,"data-question-block":t,children:[(0,m.jsx)(`button`,{type:`button`,className:`call-fold-edge`,"data-question-fold-edge":t,"aria-expanded":n,"aria-label":`${n?`折叠`:`展开`}提问`,title:n?`折叠这段提问`:`展开这段提问`,onClick:r}),(0,m.jsxs)(`div`,{className:`call-head-row`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`call-head`,"data-call-head":t,"aria-expanded":n,onClick:r,children:[(0,m.jsx)(`span`,{className:`call-chevron`,"aria-hidden":`true`,children:n?`▾`:`▸`}),(0,m.jsx)(`span`,{className:`call-glyph`,"aria-hidden":`true`,children:e.status===`answered`?`✓`:e.status===`cancelled`?`✕`:`?`}),(0,m.jsx)(`span`,{className:`call-label`,children:`提问`}),(0,m.jsxs)(`span`,{className:`call-detail`,children:[e.items.length,` 个问题`]})]}),n&&(0,m.jsx)(`button`,{type:`button`,className:`call-fold-top`,"data-call-fold-top":t,onClick:r,children:`收起`})]}),n&&(0,m.jsx)(`div`,{className:`question-body`,"data-question-body":t,children:(0,m.jsx)(qp,{question:e,onAnswer:i})})]})}function qp({question:e,onAnswer:t}){let[n,r]=(0,p.useState)(()=>Object.fromEntries((e.answers??[]).map(e=>[e.id,e.selected]))),[i,a]=(0,p.useState)(()=>e.answers?.map(e=>e.note??``).join(`
73
- `)??``),o=(e,t,n)=>{r(r=>{let i=r[e]??[];return n?{...r,[e]:i.includes(t)?i.filter(e=>e!==t):[...i,t]}:{...r,[e]:[t]}})},s=()=>{t(e.items.map(e=>({id:e.id,selected:n[e.id]??[],...e.extraNote&&i.trim()?{note:i.trim()}:{}})),!1)},c=e.items.some(e=>(n[e.id]??[]).length>0);return(0,m.jsxs)(`div`,{className:`question-block question-${e.status}`,"data-question-status":e.status,children:[e.items.map(t=>(0,m.jsxs)(`div`,{className:`question-item`,children:[(0,m.jsx)(`div`,{className:`question-text`,children:t.header?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`question-header`,children:t.header}),(0,m.jsx)(`span`,{className:`question-sep`,children:` · `}),(0,m.jsx)(Ze,{source:t.question})]}):(0,m.jsx)(Ze,{source:t.question})}),(0,m.jsx)(`div`,{className:`question-options`,"data-question-options":t.id,children:t.options.map(r=>{let i=(n[t.id]??[]).includes(r),a=e.status!==`pending`;return(0,m.jsxs)(`label`,{className:i?`is-chosen`:``,"data-chosen":a&&i?`1`:void 0,children:[(0,m.jsx)(`input`,{type:t.multiple?`checkbox`:`radio`,name:`q-${t.id}`,checked:i,disabled:a,onChange:()=>o(t.id,r,t.multiple)}),(0,m.jsx)(Qe,{source:r}),a&&i?(0,m.jsx)(`span`,{className:`question-mark`,"aria-label":`已选择`,children:`✓`}):null]},r)})}),e.status===`pending`&&t.extraNote?(0,m.jsx)(`textarea`,{value:i,placeholder:`补充说明(可选)`,onChange:e=>a(e.target.value)}):e.status===`answered`&&(e.answers??[]).some(e=>e.note)?(0,m.jsxs)(`div`,{className:`question-summary`,"data-question-summary":`1`,children:[`补充:`,(e.answers??[]).map(e=>e.note).filter(Boolean).join(`;`)]}):null,e.status===`cancelled`&&(0,m.jsx)(`div`,{className:`question-summary`,"data-question-summary":`1`,children:`已取消,没有作答。`})]},t.id)),e.status===`pending`&&(0,m.jsxs)(`div`,{className:`question-actions`,children:[(0,m.jsx)(`button`,{type:`button`,onClick:s,disabled:!c,children:`提交`}),(0,m.jsx)(`button`,{type:`button`,className:`question-skip`,onClick:()=>t([],!0),children:`跳过`})]})]})}function Jp({request:e,onAnswer:t,pending:n}){let[r,i]=(0,p.useState)(e.prefill??``),a=e.method===`input`||e.method===`editor`,o=(0,m.jsx)(`button`,{type:`button`,className:`extui-cancel`,onClick:()=>t({cancelled:!0}),children:`取消提问`});return(0,m.jsxs)(`article`,{className:`extui-card extui-${e.method}`,"data-request-id":e.requestId,"data-method":e.method,children:[(0,m.jsxs)(`div`,{className:`extui-head`,children:[(0,m.jsx)(`span`,{className:`extui-badge`,children:`扩展提问`}),e.timeoutMs!==void 0&&(0,m.jsxs)(`span`,{className:`extui-deadline`,children:[Math.round(e.timeoutMs/1e3),`s 超时`]})]}),n&&(0,m.jsx)(`p`,{role:`status`,children:`提交中…`}),(0,m.jsxs)(`fieldset`,{disabled:n,style:{border:0,padding:0,margin:0},children:[(0,m.jsx)(`h3`,{className:`extui-title`,children:e.title||e.method}),e.method===`confirm`&&(0,m.jsx)(`p`,{className:`extui-body`,children:e.message}),e.method===`select`&&(0,m.jsxs)(`div`,{className:`extui-options`,children:[(e.options??[]).map(e=>(0,m.jsx)(`button`,{type:`button`,className:`extui-option`,onClick:()=>t({value:e}),children:e},e)),(e.options??[]).length===0&&(0,m.jsx)(`p`,{className:`extui-body`,children:`扩展没有提供任何选项`})]}),a&&(0,m.jsxs)(`form`,{className:`extui-form`,onSubmit:e=>{e.preventDefault(),!n&&r.trim()&&t({value:r})},children:[e.method===`input`?(0,m.jsx)(`input`,{className:`extui-field`,value:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&ip(e)&&e.preventDefault()},placeholder:e.placeholder??``}):(0,m.jsx)(`textarea`,{className:`extui-field`,value:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&ip(e)&&e.preventDefault()}}),(0,m.jsxs)(`div`,{className:`extui-actions`,children:[(0,m.jsx)(`button`,{type:`submit`,className:`extui-primary`,disabled:!r.trim(),children:`提交`}),o]})]}),!a&&(0,m.jsxs)(`div`,{className:`extui-actions`,children:[e.method===`confirm`&&(0,m.jsx)(`button`,{type:`button`,className:`extui-primary`,onClick:()=>t({confirmed:!0}),children:`确认`}),e.method===`confirm`&&(0,m.jsx)(`button`,{type:`button`,className:`extui-no`,onClick:()=>t({confirmed:!1}),children:`拒绝`}),o]})]})]})}function Yp({initial:e,label:t,onCommit:n,onClose:r}){let[i,a]=(0,p.useState)(e),o=(0,p.useRef)(null),s=(0,p.useRef)(!1);(0,p.useEffect)(()=>{o.current?.focus(),o.current?.select()},[]);let c=!i.trim(),l=()=>{s.current=!0,r()},u=()=>{if(c)return;let t=i.trim();(t===e||n(t))&&l()};return(0,m.jsxs)(`div`,{className:`inline-edit`,"data-editing":`1`,children:[(0,m.jsx)(`input`,{ref:o,className:`inline-edit-input`,value:i,"aria-label":t,onChange:e=>a(e.target.value),onKeyDown:e=>{if(e.key===`Enter`){if(ip(e))return;e.preventDefault(),u()}else e.key===`Escape`&&(e.preventDefault(),l())},onBlur:()=>{s.current||r()}}),(0,m.jsx)(`button`,{type:`button`,className:`inline-edit-ok`,title:`确认重命名`,"aria-label":`确认重命名`,disabled:c,onMouseDown:e=>e.preventDefault(),onClick:u,children:`✓`}),(0,m.jsx)(`button`,{type:`button`,className:`inline-edit-cancel`,title:`取消重命名`,"aria-label":`取消重命名`,onMouseDown:e=>e.preventDefault(),onClick:l,children:`✗`})]})}function Xp({kind:e,label:t,value:n,detail:r,options:i,disabled:a,note:o,onChoose:s,scope:c}){let[l,u]=(0,p.useState)(!1),[d,f]=(0,p.useState)(``),[h,g]=(0,p.useState)(0),_=(0,p.useRef)(null),v=(0,p.useRef)(null),y=(0,p.useRef)(null),b=(0,p.useRef)(null),x=(0,p.useRef)([]),S=i.find(e=>e.selected),C=Op(i,d),w=C.length===0?-1:Math.min(Math.max(h,0),C.length-1),T=w<0?void 0:C[w],E=(e=!1)=>{u(!1),e&&v.current?.focus()},D=()=>{f(``),g(Math.max(i.findIndex(e=>e.selected),0)),u(!0)},ee=e=>g(t=>C.length?Math.min(Math.max(t+e,0),C.length-1):0);(0,p.useEffect)(()=>{if(!l)return;let e=e=>{_.current?.contains(e.target)||E()};return window.addEventListener(`mousedown`,e),()=>window.removeEventListener(`mousedown`,e)},[l]),(0,p.useEffect)(()=>{if(!l)return;let e=_.current,t=t=>{e?.contains(t.relatedTarget)||E()};return e?.addEventListener(`focusout`,t),()=>e?.removeEventListener(`focusout`,t)},[l]),(0,p.useEffect)(()=>{l&&b.current?.focus()},[l]),(0,p.useEffect)(()=>{l&&w>=0&&x.current[w]?.scrollIntoView({block:`nearest`})},[l,w]),(0,p.useLayoutEffect)(()=>{if(!l)return;let e=y.current;if(!e)return;e.style.setProperty(`--picker-nudge`,`0px`),e.style.setProperty(`--picker-drop`,`0px`);let t=e.getBoundingClientRect(),n=Math.min(window.innerWidth-8-t.right,Math.max(8-t.left,0)),r=Math.min(window.innerHeight-8-t.bottom,Math.max(8-t.top,0));e.style.setProperty(`--picker-nudge`,`${n}px`),e.style.setProperty(`--picker-drop`,`${r}px`)},[l,C.length,i.length]);let O=e=>{if(l){if(e.key===`Escape`)e.preventDefault(),E(!0);else if(e.key===`ArrowDown`)e.preventDefault(),ee(1);else if(e.key===`ArrowUp`)e.preventDefault(),ee(-1);else if(e.key===`Home`)e.preventDefault(),g(0);else if(e.key===`End`)e.preventDefault(),g(Math.max(C.length-1,0));else if(e.key===`Enter`){if(ip(e))return;e.preventDefault(),T&&(s(T.key),E(!0))}}},te=`picker-list-${c??e}`,ne=t=>`picker-option-${c??e}-${t}`;return(0,m.jsxs)(`div`,{className:`session-picker-item session-picker-${e}`,ref:_,onKeyDown:l?O:void 0,children:[(0,m.jsxs)(`button`,{ref:v,type:`button`,className:`session-picker-trigger`,disabled:a,"aria-haspopup":`listbox`,"aria-expanded":l,title:o??`${Sp[e]}:${r?`${t} · ${r}`:t}`,"data-picker-trigger":e,"data-picker-value":n??t,"data-picker-selected":i.some(e=>e.selected),onClick:()=>l?E():D(),children:[(0,m.jsx)(`span`,{className:`session-picker-kind`,children:Sp[e]}),(0,m.jsx)(`span`,{className:`session-picker-name`,children:t}),r&&(0,m.jsx)(`span`,{className:`session-picker-detail`,children:r}),(0,m.jsx)(`span`,{className:`session-picker-caret`,"aria-hidden":`true`,children:`▾`})]}),l&&(0,m.jsxs)(`div`,{className:`picker-menu`,ref:y,"data-picker-menu":e,"data-picker-highlight":w,children:[(0,m.jsxs)(`div`,{className:`picker-filter`,children:[(0,m.jsx)(`span`,{className:`picker-filter-icon`,"aria-hidden":`true`,children:`🔍`}),(0,m.jsx)(`input`,{ref:b,className:`picker-filter-input`,"data-picker-filter":e,role:`combobox`,"aria-label":`筛选${Cp[e]}选项`,"aria-expanded":`true`,"aria-controls":te,"aria-autocomplete":`list`,"aria-activedescendant":T?ne(w):void 0,value:d,placeholder:`输入以筛选…`,autoComplete:`off`,spellCheck:!1,onChange:e=>{f(e.target.value),g(0)}}),d&&(0,m.jsx)(`button`,{type:`button`,className:`picker-filter-clear`,"data-picker-filter-clear":e,title:`清空筛选`,"aria-label":`清空筛选`,onMouseDown:e=>e.preventDefault(),onClick:()=>{f(``),g(0),b.current?.focus()},children:`✕`})]}),S&&!C.some(e=>e.key===S.key)&&(0,m.jsxs)(`div`,{className:`picker-current`,"data-picker-current":e,"data-picker-current-value":S.key,children:[(0,m.jsx)(`span`,{className:`picker-current-label`,children:`当前`}),(0,m.jsx)(`span`,{className:`picker-current-value`,children:S.label})]}),(0,m.jsxs)(`div`,{className:`picker-list`,role:`listbox`,id:te,"aria-label":wp[e],children:[C.map((e,t)=>(0,m.jsxs)(`button`,{id:ne(t),type:`button`,role:`option`,"aria-selected":e.selected,ref:e=>{x.current[t]=e},className:`picker-option${e.selected?` selected`:``}${t===w&&!e.selected?` preview`:``}`,"data-picker-option":e.key,"data-picker-option-selected":e.selected,"data-picker-highlight":t===w,onClick:()=>{s(e.key),E(!0)},children:[e.color&&(0,m.jsx)(`span`,{className:`picker-option-swatch`,style:{background:e.color},"aria-hidden":`true`}),(0,m.jsx)(`span`,{className:`picker-option-name`,children:e.label}),e.badge&&(0,m.jsx)(`span`,{className:`picker-option-badge`,"data-picker-option-badge":e.badge,children:e.badge}),e.detail&&(0,m.jsx)(`span`,{className:`picker-option-detail`,children:e.detail}),e.selected&&(0,m.jsx)(`span`,{className:`picker-option-mark`,"aria-hidden":`true`,children:`✓`})]},e.key)),C.length===0&&(0,m.jsx)(`div`,{className:`picker-empty`,"data-picker-empty":e,children:`没有匹配「${d.trim()}」的${Cp[e]}`})]})]})]})}var Zp=`__pi_default__`;function Qp({workspace:e,catalog:t,agents:n,onSave:r,onRename:i,onClose:a}){let[o,s]=(0,p.useState)(e.defaultAgentId),[c,l]=(0,p.useState)(e.defaultModel),[u,d]=(0,p.useState)(e.defaultThinkingLevel);(0,p.useEffect)(()=>{let e=e=>{e.key===`Escape`&&!e.defaultPrevented&&a()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[a]);let f=t?.source===`pi`,h=[{key:Zp,label:`跟随 Pi 默认`,detail:`不为新会话指定模型`,selected:c===void 0},...(t?.models??[]).map(e=>({key:`${e.provider}/${e.modelId}`,label:e.label,detail:e.detail,badge:Ep(e),selected:c?.provider===e.provider&&c.modelId===e.modelId}))],g=[{key:Zp,label:`跟随 Pi 默认`,detail:`不为新会话指定思考等级`,selected:u===void 0},...(t?.levels??[]).map(e=>({key:e,label:e,selected:e===u}))],_=e=>{if(e===Zp){l(void 0);return}let n=(t?.models??[]).find(t=>t.provider===e.split(`/`)[0]&&t.modelId===e.split(`/`)[1]);n&&l({provider:n.provider,modelId:n.modelId,label:n.label})},v=e=>d(e===Zp?void 0:e),y=[{key:Zp,label:`跟随 Pi 默认`,detail:`新会话不使用任何 agent 角色`,selected:o===void 0},...(n?.agents??[]).map(e=>({key:e.id,label:e.name,detail:e.toolSummary,color:e.color,selected:o===e.id}))];return(0,m.jsx)(`div`,{className:`overlay`,onClick:a,children:(0,m.jsxs)(`div`,{className:`picker settings-dialog`,"data-settings-dialog":`1`,onClick:e=>e.stopPropagation(),children:[(0,m.jsx)(`h2`,{children:`工作区设置`}),(0,m.jsxs)(`div`,{className:`settings-scope`,children:[e.name,` · 默认值只影响之后新建的会话,已有会话不变`]}),(0,m.jsxs)(`div`,{className:`settings-row`,children:[(0,m.jsx)(`span`,{className:`settings-label`,children:`默认智能体`}),(0,m.jsx)(Xp,{kind:`agent`,scope:`settings-agent`,label:n?.agents.find(e=>e.id===o)?.name??`跟随 Pi 默认`,value:o??Zp,detail:o?`${n?.agents.find(e=>e.id===o)?.toolSummary??``}`:void 0,options:y,disabled:!n||n.source===`unavailable`,note:Np(n),onChoose:e=>s(e===Zp?void 0:e)})]}),(0,m.jsxs)(`div`,{className:`settings-row`,children:[(0,m.jsx)(`span`,{className:`settings-label`,children:`默认模型`}),(0,m.jsx)(Xp,{kind:`model`,scope:`settings-model`,label:c?.label??`跟随 Pi 默认`,value:c?`${c.provider}/${c.modelId}`:Zp,detail:c?`${c.provider}/${c.modelId}`:void 0,options:h,disabled:!f,note:Mp(`模型`,t),onChoose:_})]}),(0,m.jsxs)(`div`,{className:`settings-row`,children:[(0,m.jsx)(`span`,{className:`settings-label`,children:`思考强度`}),(0,m.jsx)(Xp,{kind:`thinking`,scope:`settings-thinking`,label:u??`跟随 Pi 默认`,value:u??Zp,options:g,disabled:!f,note:Mp(`思考等级`,t),onChoose:v})]}),(0,m.jsxs)(`div`,{className:`picker-actions`,children:[(0,m.jsx)(`button`,{type:`button`,className:`settings-rename`,"data-settings-rename":`1`,onClick:i,children:`重命名工作区`}),(0,m.jsx)(`button`,{type:`button`,className:`picker-cancel`,"data-settings-cancel":`1`,onClick:a,children:`取消`}),(0,m.jsx)(`button`,{type:`button`,className:`picker-ok`,"data-settings-save":`1`,onClick:()=>r(o,c,u),children:`保存`})]})]})})}var $p=[{id:`main`,label:`主`,name:`主 tab`},{id:`tools`,label:`工具`,name:`工具 tab`},{id:`files`,label:`文件`,name:`文件 tab`},{id:`git`,label:`Git`,name:`Git tab`},{id:`terminal`,label:`终端`,name:`终端 tab`}],em={waiting:`⋯`,running:``,failed:`!`,question:`?`,unread:`•`,idle:``},tm={waiting:`等待 LLM`,running:`进行中`,failed:`出错`,question:`等你回答`,unread:`有未读`,idle:`空闲`};function nm(e,t,n){return t?`question`:e.status===`failed`?`failed`:e.status===`waiting`?`waiting`:e.status===`running`?`running`:e.updatedAt>(n??``)?`unread`:`idle`}function rm({state:e}){let t=em[e];return e===`idle`?null:(0,m.jsx)(`i`,{className:`session-state session-state-${e}`,"data-session-state":e,title:tm[e],"aria-label":tm[e],children:(0,m.jsx)(`i`,{className:`session-state-mark`,"aria-hidden":`true`,children:t})})}var im={pending:`未开始`,in_progress:`进行中`,completed:`已完成`},am={pending:`○`,in_progress:`◐`,completed:`✓`},om={high:`高`,medium:`中`,low:`低`};function sm(e){let t=e.filter(e=>e.status!==`completed`).length;return e.length?t?`${t} 个未完成 / 共 ${e.length} 个`:`全部完成:${e.length} 个`:`0 个待办任务`}function cm({todo:e,index:t}){let n=e.id??`todo_${t}`;return(0,m.jsxs)(`li`,{className:`todo-item todo-${e.status}`,"data-todo-item":n,"data-todo-status":e.status,children:[(0,m.jsx)(`span`,{className:`todo-mark`,"aria-hidden":`true`,children:am[e.status]}),(0,m.jsx)(`span`,{className:`todo-text`,children:e.content}),(0,m.jsx)(`span`,{className:`todo-status`,"data-todo-status-text":`1`,children:im[e.status]}),e.priority&&(0,m.jsx)(`span`,{className:`todo-priority`,"data-todo-priority":e.priority,children:om[e.priority]})]})}function lm({tasks:e}){return(0,m.jsx)(`ul`,{className:`bg-list`,"data-bg-task-count":e.length,children:e.map((e,t)=>{let n=e.id||`bg_${t}`,r=e.status?.trim()||`未知状态`;return(0,m.jsxs)(`li`,{className:`bg-item`,"data-bg-task":n,"data-bg-task-status":e.status??`unknown`,children:[(0,m.jsx)(`span`,{className:`bg-title`,children:e.title?.trim()||e.id||`未命名任务 ${t+1}`}),(0,m.jsxs)(`span`,{className:`bg-meta`,children:[e.agentId?.trim()&&(0,m.jsx)(`span`,{className:`bg-agent`,"data-bg-agent":e.agentId,children:e.agentId}),(0,m.jsx)(`span`,{className:`bg-status`,children:r})]})]},n)})})}function um({todos:e,tasks:t,collapsed:n,onToggle:r,workspaceId:i,workspaceLabel:a,connected:o,files:s,onOpenFile:c,onOpenChanged:l,activeTab:u,onSelectTab:d,sendCommand:f,registerTerminalSink:p}){let h=$p;return h.some(e=>e.id===u)||h[0].id,(0,m.jsx)(`div`,{className:`right-rail${n?` right-rail-collapsed`:``}`,role:`complementary`,"aria-label":`右侧栏`,"data-right-rail":`1`,"data-right-rail-collapsed":n,children:n?(0,m.jsx)(`button`,{type:`button`,className:`right-rail-open`,"data-right-rail-open":`1`,title:`展开右侧栏`,"aria-label":`展开右侧栏`,onClick:r,children:`‹`}):(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`right-rail-head`,children:[(0,m.jsx)(`div`,{className:`right-tabs`,role:`tablist`,"aria-label":`右侧栏 tab`,"data-right-tab-count":h.length,children:h.map(e=>(0,m.jsx)(`button`,{type:`button`,role:`tab`,id:`right-tab-${e.id}`,className:`right-tab${e.id===u?` right-tab-active`:``}`,"data-right-tab":e.id,"aria-selected":e.id===u,"aria-controls":`right-panel-${e.id}`,title:e.name,"aria-label":e.name,onClick:()=>d(e.id),children:e.label},e.id))}),(0,m.jsx)(`button`,{type:`button`,className:`right-rail-collapse`,"data-right-rail-collapse":`1`,title:`收起右侧栏(聊天区会变宽)`,"aria-label":`收起右侧栏`,onClick:r,children:`›`})]}),$p.filter(e=>e.id===u).map(n=>(0,m.jsxs)(`div`,{className:`right-rail-body`,role:`tabpanel`,id:`right-panel-${n.id}`,"aria-labelledby":`right-tab-${n.id}`,"data-right-panel":n.id,children:[n.id===`main`&&(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`rail-section-head`,children:[(0,m.jsx)(`h2`,{className:`rail-section-title`,children:`待办任务`}),(0,m.jsx)(`span`,{className:`rail-section-count`,"data-todo-summary":`1`,children:sm(e)})]}),e.length>0?(0,m.jsx)(`ol`,{className:`todo-list`,"data-todo-count":e.length,children:e.map((e,t)=>(0,m.jsx)(cm,{todo:e,index:t},e.id??`todo_${t}`))}):(0,m.jsx)(`p`,{className:`rail-empty`,"data-todo-empty":`1`,children:`暂无待办任务。Agent 开始处理多步骤任务时,会自己把待办写到这里。`}),(0,m.jsxs)(`div`,{className:`rail-section-head`,children:[(0,m.jsx)(`h2`,{className:`rail-section-title`,children:`后台任务`}),(0,m.jsx)(`span`,{className:`rail-section-count`,"data-bg-summary":`1`,children:t.length?`${t.length} 个运行中`:`0 个`})]}),t.length>0?(0,m.jsx)(lm,{tasks:t}):(0,m.jsx)(`p`,{className:`rail-empty`,"data-bg-empty":`1`,children:`当前没有正在运行的后台任务。`})]}),n.id===`tools`&&(0,m.jsx)(pm,{}),n.id===`files`&&(0,m.jsx)(xr,{workspaceId:i,files:s,onOpenFile:c,onOpenChanged:l}),n.id===`git`&&(0,m.jsx)(O,{workspaceId:i??null}),n.id===`terminal`&&(0,m.jsx)(Hf,{workspaceId:i,workspaceLabel:a,connected:o,sendCommand:f,registerSink:p})]},n.id))]})})}function dm(){try{if(typeof window>`u`)return Zr.slice();let e=ri(window.localStorage.getItem(ei));return window.localStorage.getItem(`super-pi:tools:v1`)===null?Zr.slice():e}catch{return Zr.slice()}}function fm(e){try{if(typeof window>`u`)return;window.localStorage.setItem(ei,ii(e))}catch{}}function pm(){let[e,t]=(0,p.useState)(dm),[n,r]=(0,p.useState)([]),[i,a]=(0,p.useState)(),[o,s]=(0,p.useState)(!1),[c,l]=(0,p.useState)(),u=e.find(e=>e.id===i),d=(0,p.useCallback)(async()=>{try{let e=await fetch(`/api/tools`),t=await e.json();e.ok&&Array.isArray(t.tools)&&r(t.tools.filter(e=>e.enabled))}catch{}},[]),f=async e=>{l(void 0);try{let t=await fetch(`/api/tools?id=${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok)throw Error(`HTTP ${t.status}`);a(t=>t===e?void 0:t),await d()}catch(e){l(`移除工具失败:${e instanceof Error?e.message:String(e)}`)}};return(0,p.useEffect)(()=>{fm(e)},[e]),(0,p.useEffect)(()=>{d();let e=()=>{d()};return window.addEventListener(`super-pi-tools-updated`,e),()=>window.removeEventListener(`super-pi-tools-updated`,e)},[d]),(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`rail-section-head`,children:[(0,m.jsx)(`h2`,{className:`rail-section-title`,children:`工具`}),(0,m.jsxs)(`span`,{className:`rail-section-count`,"data-tool-summary":`1`,children:[e.length+n.length,` 个`]})]}),e.length+n.length>0?(0,m.jsxs)(`ul`,{className:`tool-grid`,"data-tool-count":e.length+n.length,children:[e.map(e=>(0,m.jsxs)(`li`,{className:`tool-slot`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`tool-icon`,"data-tool-icon":e.id,"data-tool-kind":e.kind,"data-tool-state":e.id===i?`open`:`idle`,title:`打开${e.name}`,"aria-label":`打开${e.name}`,"aria-current":e.id===i?`true`:void 0,onClick:()=>a(t=>t===e.id?void 0:e.id),children:[(0,m.jsx)(`span`,{className:`tool-icon-glyph`,"aria-hidden":`true`,children:e.glyph}),(0,m.jsx)(`span`,{className:`tool-icon-name`,children:e.name})]}),e.kind===`link`&&(0,m.jsx)(`button`,{type:`button`,className:`tool-remove`,"data-tool-remove":e.id,title:`移除${e.name}`,"aria-label":`移除${e.name}`,onClick:()=>{t(t=>ci(t,e.id)),i===e.id&&a(void 0)},children:`✕`})]},e.id)),n.map(e=>(0,m.jsxs)(`li`,{className:`tool-slot`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`tool-icon`,"data-mounted-tool-icon":e.id,title:`打开${e.name}`,"aria-label":`打开${e.name}`,onClick:()=>a(t=>t===e.id?void 0:e.id),children:[(0,m.jsx)(`span`,{className:`tool-icon-glyph`,"aria-hidden":`true`,children:`🧩`}),(0,m.jsx)(`span`,{className:`tool-icon-name`,children:e.name})]}),(0,m.jsx)(`button`,{type:`button`,className:`tool-remove`,"data-tool-remove":e.id,title:`移除${e.name}`,"aria-label":`移除${e.name}`,onClick:()=>void f(e.id),children:`✕`})]},e.id))]}):(0,m.jsx)(`p`,{className:`rail-empty`,"data-tool-empty":`1`,children:`还没有工具。点下面的「工具设置」添加。`}),(0,m.jsx)(`button`,{type:`button`,className:`tools-settings-btn`,"data-tool-settings-trigger":`1`,title:`添加预置工具、网址工具与说明`,"aria-label":`打开工具设置`,onClick:()=>{a(void 0),s(!0)},children:`⚙ 工具设置`}),c&&(0,m.jsx)(`p`,{role:`alert`,"data-tool-error":`1`,children:c}),o&&(0,m.jsx)(mm,{tools:e,onToolsChange:t,mountedTools:n,onRefreshMountedTools:d,onClose:()=>s(!1)}),u&&(0,m.jsx)(_m,{tool:u,onClose:()=>a(void 0)}),n.find(e=>e.id===i)&&(0,m.jsx)(wm,{tool:n.find(e=>e.id===i),onClose:()=>a(void 0)})]})}function mm({tools:e,onToolsChange:t,mountedTools:n,onRefreshMountedTools:r,onClose:i}){let[a,o]=(0,p.useState)(``),[s,c]=(0,p.useState)(``),[l,u]=(0,p.useState)(),[f,h]=(0,p.useState)(!1),[g,_]=(0,p.useState)(),[v,y]=(0,p.useState)(),[b,x]=(0,p.useState)(),[S,C]=(0,p.useState)(``),[w,T]=(0,p.useState)(),[E,D]=(0,p.useState)(),[ee,O]=(0,p.useState)(!1),[te,ne]=(0,p.useState)(),[re,k]=(0,p.useState)(),ie=(0,p.useRef)(null),ae=(0,p.useRef)(null),oe=async()=>{let e=await yp(`请为 Super Pi 开发一个全局右侧栏工具。不要启动独立 HTTP 服务器,也不要监听端口。
73
+ `)??``),o=(e,t,n)=>{r(r=>{let i=r[e]??[];return n?{...r,[e]:i.includes(t)?i.filter(e=>e!==t):[...i,t]}:{...r,[e]:[t]}})},s=()=>{t(e.items.map(e=>({id:e.id,selected:n[e.id]??[],...e.extraNote&&i.trim()?{note:i.trim()}:{}})),!1)},c=e.items.some(e=>(n[e.id]??[]).length>0);return(0,m.jsxs)(`div`,{className:`question-block question-${e.status}`,"data-question-status":e.status,children:[e.items.map(t=>(0,m.jsxs)(`div`,{className:`question-item`,children:[(0,m.jsx)(`div`,{className:`question-text`,children:t.header?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`question-header`,children:t.header}),(0,m.jsx)(`span`,{className:`question-sep`,children:` · `}),(0,m.jsx)(Ze,{source:t.question})]}):(0,m.jsx)(Ze,{source:t.question})}),(0,m.jsx)(`div`,{className:`question-options`,"data-question-options":t.id,children:t.options.map(r=>{let i=(n[t.id]??[]).includes(r),a=e.status!==`pending`;return(0,m.jsxs)(`label`,{className:i?`is-chosen`:``,"data-chosen":a&&i?`1`:void 0,children:[(0,m.jsx)(`input`,{type:t.multiple?`checkbox`:`radio`,name:`q-${t.id}`,checked:i,disabled:a,onChange:()=>o(t.id,r,t.multiple)}),(0,m.jsx)(Qe,{source:r}),a&&i?(0,m.jsx)(`span`,{className:`question-mark`,"aria-label":`已选择`,children:`✓`}):null]},r)})}),e.status===`pending`&&t.extraNote?(0,m.jsx)(`textarea`,{value:i,placeholder:`补充说明(可选)`,onChange:e=>a(e.target.value)}):e.status===`answered`&&(e.answers??[]).some(e=>e.note)?(0,m.jsxs)(`div`,{className:`question-summary`,"data-question-summary":`1`,children:[`补充:`,(e.answers??[]).map(e=>e.note).filter(Boolean).join(`;`)]}):null,e.status===`cancelled`&&(0,m.jsx)(`div`,{className:`question-summary`,"data-question-summary":`1`,children:`已取消,没有作答。`})]},t.id)),e.status===`pending`&&(0,m.jsxs)(`div`,{className:`question-actions`,children:[(0,m.jsx)(`button`,{type:`button`,onClick:s,disabled:!c,children:`提交`}),(0,m.jsx)(`button`,{type:`button`,className:`question-skip`,onClick:()=>t([],!0),children:`跳过`})]})]})}function Jp({request:e,onAnswer:t,pending:n}){let[r,i]=(0,p.useState)(e.prefill??``),a=e.method===`input`||e.method===`editor`,o=(0,m.jsx)(`button`,{type:`button`,className:`extui-cancel`,onClick:()=>t({cancelled:!0}),children:`取消提问`});return(0,m.jsxs)(`article`,{className:`extui-card extui-${e.method}`,"data-request-id":e.requestId,"data-method":e.method,children:[(0,m.jsxs)(`div`,{className:`extui-head`,children:[(0,m.jsx)(`span`,{className:`extui-badge`,children:`扩展提问`}),e.timeoutMs!==void 0&&(0,m.jsxs)(`span`,{className:`extui-deadline`,children:[Math.round(e.timeoutMs/1e3),`s 超时`]})]}),n&&(0,m.jsx)(`p`,{role:`status`,children:`提交中…`}),(0,m.jsxs)(`fieldset`,{disabled:n,style:{border:0,padding:0,margin:0},children:[(0,m.jsx)(`h3`,{className:`extui-title`,children:e.title||e.method}),e.method===`confirm`&&(0,m.jsx)(`p`,{className:`extui-body`,children:e.message}),e.method===`select`&&(0,m.jsxs)(`div`,{className:`extui-options`,children:[(e.options??[]).map(e=>(0,m.jsx)(`button`,{type:`button`,className:`extui-option`,onClick:()=>t({value:e}),children:e},e)),(e.options??[]).length===0&&(0,m.jsx)(`p`,{className:`extui-body`,children:`扩展没有提供任何选项`})]}),a&&(0,m.jsxs)(`form`,{className:`extui-form`,onSubmit:e=>{e.preventDefault(),!n&&r.trim()&&t({value:r})},children:[e.method===`input`?(0,m.jsx)(`input`,{className:`extui-field`,value:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&ip(e)&&e.preventDefault()},placeholder:e.placeholder??``}):(0,m.jsx)(`textarea`,{className:`extui-field`,value:r,onChange:e=>i(e.target.value),onKeyDown:e=>{e.key===`Enter`&&ip(e)&&e.preventDefault()}}),(0,m.jsxs)(`div`,{className:`extui-actions`,children:[(0,m.jsx)(`button`,{type:`submit`,className:`extui-primary`,disabled:!r.trim(),children:`提交`}),o]})]}),!a&&(0,m.jsxs)(`div`,{className:`extui-actions`,children:[e.method===`confirm`&&(0,m.jsx)(`button`,{type:`button`,className:`extui-primary`,onClick:()=>t({confirmed:!0}),children:`确认`}),e.method===`confirm`&&(0,m.jsx)(`button`,{type:`button`,className:`extui-no`,onClick:()=>t({confirmed:!1}),children:`拒绝`}),o]})]})]})}function Yp({initial:e,label:t,onCommit:n,onClose:r}){let[i,a]=(0,p.useState)(e),o=(0,p.useRef)(null),s=(0,p.useRef)(!1);(0,p.useEffect)(()=>{o.current?.focus(),o.current?.select()},[]);let c=!i.trim(),l=()=>{s.current=!0,r()},u=()=>{if(c)return;let t=i.trim();(t===e||n(t))&&l()};return(0,m.jsxs)(`div`,{className:`inline-edit`,"data-editing":`1`,children:[(0,m.jsx)(`input`,{ref:o,className:`inline-edit-input`,value:i,"aria-label":t,onChange:e=>a(e.target.value),onKeyDown:e=>{if(e.key===`Enter`){if(ip(e))return;e.preventDefault(),u()}else e.key===`Escape`&&(e.preventDefault(),l())},onBlur:()=>{s.current||r()}}),(0,m.jsx)(`button`,{type:`button`,className:`inline-edit-ok`,title:`确认重命名`,"aria-label":`确认重命名`,disabled:c,onMouseDown:e=>e.preventDefault(),onClick:u,children:`✓`}),(0,m.jsx)(`button`,{type:`button`,className:`inline-edit-cancel`,title:`取消重命名`,"aria-label":`取消重命名`,onMouseDown:e=>e.preventDefault(),onClick:l,children:`✗`})]})}function Xp({kind:e,label:t,value:n,detail:r,options:i,disabled:a,note:o,onChoose:s,scope:c}){let[l,u]=(0,p.useState)(!1),[d,f]=(0,p.useState)(``),[h,g]=(0,p.useState)(0),_=(0,p.useRef)(null),v=(0,p.useRef)(null),y=(0,p.useRef)(null),b=(0,p.useRef)(null),x=(0,p.useRef)([]),S=i.find(e=>e.selected),C=Op(i,d),w=C.length===0?-1:Math.min(Math.max(h,0),C.length-1),T=w<0?void 0:C[w],E=(e=!1)=>{u(!1),e&&v.current?.focus()},D=()=>{f(``),g(Math.max(i.findIndex(e=>e.selected),0)),u(!0)},ee=e=>g(t=>C.length?Math.min(Math.max(t+e,0),C.length-1):0);(0,p.useEffect)(()=>{if(!l)return;let e=e=>{_.current?.contains(e.target)||E()};return window.addEventListener(`mousedown`,e),()=>window.removeEventListener(`mousedown`,e)},[l]),(0,p.useEffect)(()=>{if(!l)return;let e=_.current,t=t=>{e?.contains(t.relatedTarget)||E()};return e?.addEventListener(`focusout`,t),()=>e?.removeEventListener(`focusout`,t)},[l]),(0,p.useEffect)(()=>{l&&b.current?.focus()},[l]),(0,p.useEffect)(()=>{l&&w>=0&&x.current[w]?.scrollIntoView({block:`nearest`})},[l,w]),(0,p.useLayoutEffect)(()=>{if(!l)return;let e=y.current;if(!e)return;e.style.setProperty(`--picker-nudge`,`0px`),e.style.setProperty(`--picker-drop`,`0px`);let t=e.getBoundingClientRect(),n=Math.min(window.innerWidth-8-t.right,Math.max(8-t.left,0)),r=Math.min(window.innerHeight-8-t.bottom,Math.max(8-t.top,0));e.style.setProperty(`--picker-nudge`,`${n}px`),e.style.setProperty(`--picker-drop`,`${r}px`)},[l,C.length,i.length]);let O=e=>{if(l){if(e.key===`Escape`)e.preventDefault(),E(!0);else if(e.key===`ArrowDown`)e.preventDefault(),ee(1);else if(e.key===`ArrowUp`)e.preventDefault(),ee(-1);else if(e.key===`Home`)e.preventDefault(),g(0);else if(e.key===`End`)e.preventDefault(),g(Math.max(C.length-1,0));else if(e.key===`Enter`){if(ip(e))return;e.preventDefault(),T&&(s(T.key),E(!0))}}},te=`picker-list-${c??e}`,ne=t=>`picker-option-${c??e}-${t}`;return(0,m.jsxs)(`div`,{className:`session-picker-item session-picker-${e}`,ref:_,onKeyDown:l?O:void 0,children:[(0,m.jsxs)(`button`,{ref:v,type:`button`,className:`session-picker-trigger`,disabled:a,"aria-haspopup":`listbox`,"aria-expanded":l,title:o??`${Sp[e]}:${r?`${t} · ${r}`:t}`,"data-picker-trigger":e,"data-picker-value":n??t,"data-picker-selected":i.some(e=>e.selected),onClick:()=>l?E():D(),children:[(0,m.jsx)(`span`,{className:`session-picker-kind`,children:Sp[e]}),(0,m.jsx)(`span`,{className:`session-picker-name`,children:t}),r&&(0,m.jsx)(`span`,{className:`session-picker-detail`,children:r}),(0,m.jsx)(`span`,{className:`session-picker-caret`,"aria-hidden":`true`,children:`▾`})]}),l&&(0,m.jsxs)(`div`,{className:`picker-menu`,ref:y,"data-picker-menu":e,"data-picker-highlight":w,children:[(0,m.jsxs)(`div`,{className:`picker-filter`,children:[(0,m.jsx)(`span`,{className:`picker-filter-icon`,"aria-hidden":`true`,children:`🔍`}),(0,m.jsx)(`input`,{ref:b,className:`picker-filter-input`,"data-picker-filter":e,role:`combobox`,"aria-label":`筛选${Cp[e]}选项`,"aria-expanded":`true`,"aria-controls":te,"aria-autocomplete":`list`,"aria-activedescendant":T?ne(w):void 0,value:d,placeholder:`输入以筛选…`,autoComplete:`off`,spellCheck:!1,onChange:e=>{f(e.target.value),g(0)}}),d&&(0,m.jsx)(`button`,{type:`button`,className:`picker-filter-clear`,"data-picker-filter-clear":e,title:`清空筛选`,"aria-label":`清空筛选`,onMouseDown:e=>e.preventDefault(),onClick:()=>{f(``),g(0),b.current?.focus()},children:`✕`})]}),S&&!C.some(e=>e.key===S.key)&&(0,m.jsxs)(`div`,{className:`picker-current`,"data-picker-current":e,"data-picker-current-value":S.key,children:[(0,m.jsx)(`span`,{className:`picker-current-label`,children:`当前`}),(0,m.jsx)(`span`,{className:`picker-current-value`,children:S.label})]}),(0,m.jsxs)(`div`,{className:`picker-list`,role:`listbox`,id:te,"aria-label":wp[e],children:[C.map((e,t)=>(0,m.jsxs)(`button`,{id:ne(t),type:`button`,role:`option`,"aria-selected":e.selected,ref:e=>{x.current[t]=e},className:`picker-option${e.selected?` selected`:``}${t===w&&!e.selected?` preview`:``}`,"data-picker-option":e.key,"data-picker-option-selected":e.selected,"data-picker-highlight":t===w,onClick:()=>{s(e.key),E(!0)},children:[e.color&&(0,m.jsx)(`span`,{className:`picker-option-swatch`,style:{background:e.color},"aria-hidden":`true`}),(0,m.jsx)(`span`,{className:`picker-option-name`,children:e.label}),e.badge&&(0,m.jsx)(`span`,{className:`picker-option-badge`,"data-picker-option-badge":e.badge,children:e.badge}),e.detail&&(0,m.jsx)(`span`,{className:`picker-option-detail`,children:e.detail}),e.selected&&(0,m.jsx)(`span`,{className:`picker-option-mark`,"aria-hidden":`true`,children:`✓`})]},e.key)),C.length===0&&(0,m.jsx)(`div`,{className:`picker-empty`,"data-picker-empty":e,children:`没有匹配「${d.trim()}」的${Cp[e]}`})]})]})]})}var Zp=`__pi_default__`;function Qp({workspace:e,catalog:t,agents:n,onSave:r,onRename:i,onClose:a}){let[o,s]=(0,p.useState)(e.defaultAgentId),[c,l]=(0,p.useState)(e.defaultModel),[u,d]=(0,p.useState)(e.defaultThinkingLevel);(0,p.useEffect)(()=>{let e=e=>{e.key===`Escape`&&!e.defaultPrevented&&a()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[a]);let f=t?.source===`pi`,h=[{key:Zp,label:`跟随 Pi 默认`,detail:`不为新会话指定模型`,selected:c===void 0},...(t?.models??[]).map(e=>({key:`${e.provider}/${e.modelId}`,label:e.label,detail:e.detail,badge:Ep(e),selected:c?.provider===e.provider&&c.modelId===e.modelId}))],g=[{key:Zp,label:`跟随 Pi 默认`,detail:`不为新会话指定思考等级`,selected:u===void 0},...(t?.levels??[]).map(e=>({key:e,label:e,selected:e===u}))],_=e=>{if(e===Zp){l(void 0);return}let n=(t?.models??[]).find(t=>t.provider===e.split(`/`)[0]&&t.modelId===e.split(`/`)[1]);n&&l({provider:n.provider,modelId:n.modelId,label:n.label})},v=e=>d(e===Zp?void 0:e),y=[{key:Zp,label:`跟随 Pi 默认`,detail:`新会话不使用任何 agent 角色`,selected:o===void 0},...(n?.agents??[]).map(e=>({key:e.id,label:e.name,detail:e.toolSummary,color:e.color,selected:o===e.id}))];return(0,m.jsx)(`div`,{className:`overlay`,onClick:a,children:(0,m.jsxs)(`div`,{className:`picker settings-dialog`,"data-settings-dialog":`1`,onClick:e=>e.stopPropagation(),children:[(0,m.jsx)(`h2`,{children:`工作区设置`}),(0,m.jsxs)(`div`,{className:`settings-scope`,children:[e.name,` · 默认值只影响之后新建的会话,已有会话不变`]}),(0,m.jsxs)(`div`,{className:`settings-row`,children:[(0,m.jsx)(`span`,{className:`settings-label`,children:`默认智能体`}),(0,m.jsx)(Xp,{kind:`agent`,scope:`settings-agent`,label:n?.agents.find(e=>e.id===o)?.name??`跟随 Pi 默认`,value:o??Zp,detail:o?`${n?.agents.find(e=>e.id===o)?.toolSummary??``}`:void 0,options:y,disabled:!n||n.source===`unavailable`,note:Np(n),onChoose:e=>s(e===Zp?void 0:e)})]}),(0,m.jsxs)(`div`,{className:`settings-row`,children:[(0,m.jsx)(`span`,{className:`settings-label`,children:`默认模型`}),(0,m.jsx)(Xp,{kind:`model`,scope:`settings-model`,label:c?.label??`跟随 Pi 默认`,value:c?`${c.provider}/${c.modelId}`:Zp,detail:c?`${c.provider}/${c.modelId}`:void 0,options:h,disabled:!f,note:Mp(`模型`,t),onChoose:_})]}),(0,m.jsxs)(`div`,{className:`settings-row`,children:[(0,m.jsx)(`span`,{className:`settings-label`,children:`思考强度`}),(0,m.jsx)(Xp,{kind:`thinking`,scope:`settings-thinking`,label:u??`跟随 Pi 默认`,value:u??Zp,options:g,disabled:!f,note:Mp(`思考等级`,t),onChoose:v})]}),(0,m.jsxs)(`div`,{className:`picker-actions`,children:[(0,m.jsx)(`button`,{type:`button`,className:`settings-rename`,"data-settings-rename":`1`,onClick:i,children:`重命名工作区`}),(0,m.jsx)(`button`,{type:`button`,className:`picker-cancel`,"data-settings-cancel":`1`,onClick:a,children:`取消`}),(0,m.jsx)(`button`,{type:`button`,className:`picker-ok`,"data-settings-save":`1`,onClick:()=>r(o,c,u),children:`保存`})]})]})})}var $p=[{id:`main`,label:`主`,name:`主 tab`},{id:`tools`,label:`工具`,name:`工具 tab`},{id:`files`,label:`文件`,name:`文件 tab`},{id:`git`,label:`Git`,name:`Git tab`},{id:`terminal`,label:`终端`,name:`终端 tab`}],em={waiting:`⋯`,running:``,failed:`!`,question:`?`,unread:`•`,idle:``},tm={waiting:`等待 LLM`,running:`进行中`,failed:`出错`,question:`等你回答`,unread:`有未读`,idle:`空闲`};function nm(e,t,n){return t?`question`:e.status===`failed`?`failed`:e.status===`waiting`?`waiting`:e.status===`running`?`running`:e.updatedAt>(n??``)?`unread`:`idle`}function rm({state:e}){let t=em[e];return e===`idle`?null:(0,m.jsx)(`i`,{className:`session-state session-state-${e}`,"data-session-state":e,title:tm[e],"aria-label":tm[e],children:(0,m.jsx)(`i`,{className:`session-state-mark`,"aria-hidden":`true`,children:t})})}var im={pending:`未开始`,in_progress:`进行中`,completed:`已完成`},am={pending:`○`,in_progress:`◐`,completed:`✓`},om={high:`高`,medium:`中`,low:`低`};function sm(e){let t=e.filter(e=>e.status!==`completed`).length;return e.length?t?`${t} 个未完成 / 共 ${e.length} 个`:`全部完成:${e.length} 个`:`0 个待办任务`}function cm({todo:e,index:t}){let n=e.id??`todo_${t}`;return(0,m.jsxs)(`li`,{className:`todo-item todo-${e.status}`,"data-todo-item":n,"data-todo-status":e.status,children:[(0,m.jsx)(`span`,{className:`todo-mark`,"aria-hidden":`true`,children:am[e.status]}),(0,m.jsx)(`span`,{className:`todo-text`,children:e.content}),(0,m.jsx)(`span`,{className:`todo-status`,"data-todo-status-text":`1`,children:im[e.status]}),e.priority&&(0,m.jsx)(`span`,{className:`todo-priority`,"data-todo-priority":e.priority,children:om[e.priority]})]})}function lm({tasks:e,onStop:t}){return(0,m.jsx)(`ul`,{className:`bg-list`,"data-bg-task-count":e.length,children:e.map((e,n)=>{let r=e.id||`bg_${n}`,i=e.status?.trim()||`未知状态`;return(0,m.jsxs)(`li`,{className:`bg-item`,"data-bg-task":r,"data-bg-task-status":e.status??`unknown`,children:[(0,m.jsxs)(`div`,{className:`bg-item-header`,children:[(0,m.jsx)(`span`,{className:`bg-title`,children:e.title?.trim()||e.id||`未命名任务 ${n+1}`}),t&&(0,m.jsx)(`button`,{type:`button`,className:`bg-stop-btn`,"data-bg-task-stop":e.id,title:`终止后台任务`,onClick:()=>t(e.id),children:`终止`})]}),(0,m.jsxs)(`span`,{className:`bg-meta`,children:[e.agentId?.trim()&&(0,m.jsx)(`span`,{className:`bg-agent`,"data-bg-agent":e.agentId,children:e.agentId}),(0,m.jsx)(`span`,{className:`bg-status`,children:i})]})]},r)})})}function um({todos:e,tasks:t,collapsed:n,onToggle:r,workspaceId:i,workspaceLabel:a,connected:o,files:s,onOpenFile:c,onOpenChanged:l,activeTab:u,onSelectTab:d,sendCommand:f,registerTerminalSink:p}){let h=$p;return h.some(e=>e.id===u)||h[0].id,(0,m.jsx)(`div`,{className:`right-rail${n?` right-rail-collapsed`:``}`,role:`complementary`,"aria-label":`右侧栏`,"data-right-rail":`1`,"data-right-rail-collapsed":n,children:n?(0,m.jsx)(`button`,{type:`button`,className:`right-rail-open`,"data-right-rail-open":`1`,title:`展开右侧栏`,"aria-label":`展开右侧栏`,onClick:r,children:`‹`}):(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`right-rail-head`,children:[(0,m.jsx)(`div`,{className:`right-tabs`,role:`tablist`,"aria-label":`右侧栏 tab`,"data-right-tab-count":h.length,children:h.map(e=>(0,m.jsx)(`button`,{type:`button`,role:`tab`,id:`right-tab-${e.id}`,className:`right-tab${e.id===u?` right-tab-active`:``}`,"data-right-tab":e.id,"aria-selected":e.id===u,"aria-controls":`right-panel-${e.id}`,title:e.name,"aria-label":e.name,onClick:()=>d(e.id),children:e.label},e.id))}),(0,m.jsx)(`button`,{type:`button`,className:`right-rail-collapse`,"data-right-rail-collapse":`1`,title:`收起右侧栏(聊天区会变宽)`,"aria-label":`收起右侧栏`,onClick:r,children:`›`})]}),$p.filter(e=>e.id===u).map(n=>(0,m.jsxs)(`div`,{className:`right-rail-body`,role:`tabpanel`,id:`right-panel-${n.id}`,"aria-labelledby":`right-tab-${n.id}`,"data-right-panel":n.id,children:[n.id===`main`&&(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`rail-section-head`,children:[(0,m.jsx)(`h2`,{className:`rail-section-title`,children:`待办任务`}),(0,m.jsx)(`span`,{className:`rail-section-count`,"data-todo-summary":`1`,children:sm(e)})]}),e.length>0?(0,m.jsx)(`ol`,{className:`todo-list`,"data-todo-count":e.length,children:e.map((e,t)=>(0,m.jsx)(cm,{todo:e,index:t},e.id??`todo_${t}`))}):(0,m.jsx)(`p`,{className:`rail-empty`,"data-todo-empty":`1`,children:`暂无待办任务。Agent 开始处理多步骤任务时,会自己把待办写到这里。`}),(0,m.jsxs)(`div`,{className:`rail-section-head`,children:[(0,m.jsx)(`h2`,{className:`rail-section-title`,children:`后台任务`}),(0,m.jsx)(`span`,{className:`rail-section-count`,"data-bg-summary":`1`,children:t.length?`${t.length} 个运行中`:`0 个`})]}),t.length>0?(0,m.jsx)(lm,{tasks:t,onStop:e=>f({type:`backgroundTask.stop`,taskId:e})}):(0,m.jsx)(`p`,{className:`rail-empty`,"data-bg-empty":`1`,children:`当前没有正在运行的后台任务。`})]}),n.id===`tools`&&(0,m.jsx)(pm,{}),n.id===`files`&&(0,m.jsx)(xr,{workspaceId:i,files:s,onOpenFile:c,onOpenChanged:l}),n.id===`git`&&(0,m.jsx)(O,{workspaceId:i??null}),n.id===`terminal`&&(0,m.jsx)(Hf,{workspaceId:i,workspaceLabel:a,connected:o,sendCommand:f,registerSink:p})]},n.id))]})})}function dm(){try{if(typeof window>`u`)return Zr.slice();let e=ri(window.localStorage.getItem(ei));return window.localStorage.getItem(`super-pi:tools:v1`)===null?Zr.slice():e}catch{return Zr.slice()}}function fm(e){try{if(typeof window>`u`)return;window.localStorage.setItem(ei,ii(e))}catch{}}function pm(){let[e,t]=(0,p.useState)(dm),[n,r]=(0,p.useState)([]),[i,a]=(0,p.useState)(),[o,s]=(0,p.useState)(!1),[c,l]=(0,p.useState)(),u=e.find(e=>e.id===i),d=(0,p.useCallback)(async()=>{try{let e=await fetch(`/api/tools`),t=await e.json();e.ok&&Array.isArray(t.tools)&&r(t.tools.filter(e=>e.enabled))}catch{}},[]),f=async e=>{l(void 0);try{let t=await fetch(`/api/tools?id=${encodeURIComponent(e)}`,{method:`DELETE`});if(!t.ok)throw Error(`HTTP ${t.status}`);a(t=>t===e?void 0:t),await d()}catch(e){l(`移除工具失败:${e instanceof Error?e.message:String(e)}`)}};return(0,p.useEffect)(()=>{fm(e)},[e]),(0,p.useEffect)(()=>{d();let e=()=>{d()};return window.addEventListener(`super-pi-tools-updated`,e),()=>window.removeEventListener(`super-pi-tools-updated`,e)},[d]),(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`div`,{className:`rail-section-head`,children:[(0,m.jsx)(`h2`,{className:`rail-section-title`,children:`工具`}),(0,m.jsxs)(`span`,{className:`rail-section-count`,"data-tool-summary":`1`,children:[e.length+n.length,` 个`]})]}),e.length+n.length>0?(0,m.jsxs)(`ul`,{className:`tool-grid`,"data-tool-count":e.length+n.length,children:[e.map(e=>(0,m.jsxs)(`li`,{className:`tool-slot`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`tool-icon`,"data-tool-icon":e.id,"data-tool-kind":e.kind,"data-tool-state":e.id===i?`open`:`idle`,title:`打开${e.name}`,"aria-label":`打开${e.name}`,"aria-current":e.id===i?`true`:void 0,onClick:()=>a(t=>t===e.id?void 0:e.id),children:[(0,m.jsx)(`span`,{className:`tool-icon-glyph`,"aria-hidden":`true`,children:e.glyph}),(0,m.jsx)(`span`,{className:`tool-icon-name`,children:e.name})]}),e.kind===`link`&&(0,m.jsx)(`button`,{type:`button`,className:`tool-remove`,"data-tool-remove":e.id,title:`移除${e.name}`,"aria-label":`移除${e.name}`,onClick:()=>{t(t=>ci(t,e.id)),i===e.id&&a(void 0)},children:`✕`})]},e.id)),n.map(e=>(0,m.jsxs)(`li`,{className:`tool-slot`,children:[(0,m.jsxs)(`button`,{type:`button`,className:`tool-icon`,"data-mounted-tool-icon":e.id,title:`打开${e.name}`,"aria-label":`打开${e.name}`,onClick:()=>a(t=>t===e.id?void 0:e.id),children:[(0,m.jsx)(`span`,{className:`tool-icon-glyph`,"aria-hidden":`true`,children:`🧩`}),(0,m.jsx)(`span`,{className:`tool-icon-name`,children:e.name})]}),(0,m.jsx)(`button`,{type:`button`,className:`tool-remove`,"data-tool-remove":e.id,title:`移除${e.name}`,"aria-label":`移除${e.name}`,onClick:()=>void f(e.id),children:`✕`})]},e.id))]}):(0,m.jsx)(`p`,{className:`rail-empty`,"data-tool-empty":`1`,children:`还没有工具。点下面的「工具设置」添加。`}),(0,m.jsx)(`button`,{type:`button`,className:`tools-settings-btn`,"data-tool-settings-trigger":`1`,title:`添加预置工具、网址工具与说明`,"aria-label":`打开工具设置`,onClick:()=>{a(void 0),s(!0)},children:`⚙ 工具设置`}),c&&(0,m.jsx)(`p`,{role:`alert`,"data-tool-error":`1`,children:c}),o&&(0,m.jsx)(mm,{tools:e,onToolsChange:t,mountedTools:n,onRefreshMountedTools:d,onClose:()=>s(!1)}),u&&(0,m.jsx)(_m,{tool:u,onClose:()=>a(void 0)}),n.find(e=>e.id===i)&&(0,m.jsx)(wm,{tool:n.find(e=>e.id===i),onClose:()=>a(void 0)})]})}function mm({tools:e,onToolsChange:t,mountedTools:n,onRefreshMountedTools:r,onClose:i}){let[a,o]=(0,p.useState)(``),[s,c]=(0,p.useState)(``),[l,u]=(0,p.useState)(),[f,h]=(0,p.useState)(!1),[g,_]=(0,p.useState)(),[v,y]=(0,p.useState)(),[b,x]=(0,p.useState)(),[S,C]=(0,p.useState)(``),[w,T]=(0,p.useState)(),[E,D]=(0,p.useState)(),[ee,O]=(0,p.useState)(!1),[te,ne]=(0,p.useState)(),[re,k]=(0,p.useState)(),ie=(0,p.useRef)(null),ae=(0,p.useRef)(null),oe=async()=>{let e=await yp(`请为 Super Pi 开发一个全局右侧栏工具。不要启动独立 HTTP 服务器,也不要监听端口。
74
74
 
75
75
  工具不属于当前 workspace;通过内置 tool_register 一次性提交完整文件(index.html、JS/CSS,必要时 .py),Super Pi 会保存为全局工具并自动出现在每个 workspace 的工具 Tab。
76
76
 
@@ -8,8 +8,8 @@
8
8
  <link rel="alternate icon" href="/favicon.ico" />
9
9
  <link rel="apple-touch-icon" href="/favicon.svg" />
10
10
  <title>Super Pi</title>
11
- <script type="module" crossorigin src="/assets/index-DBR_t9lF.js"></script>
12
- <link rel="stylesheet" crossorigin href="/assets/index-mo5Dvh_v.css">
11
+ <script type="module" crossorigin src="/assets/index-B1K1OA_6.js"></script>
12
+ <link rel="stylesheet" crossorigin href="/assets/index-Aa8KN3IB.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -133,6 +133,16 @@ export declare class RunService {
133
133
  * transcript - so a `role: "user"` is never impersonated.
134
134
  */
135
135
  enqueueExecResult(sessionId: string, exitCode: number, stdout: string, stderr: string): void;
136
+ /**
137
+ * Stops an active background task (spawned process or detached subagent) on user request.
138
+ *
139
+ * 1. Kills the underlying PTY child process if one exists in `execService`.
140
+ * 2. If the task originated from a tool call in a conversation transcript, marks the tool
141
+ * call as failed with a clear message and broadcasts `message.tools`.
142
+ * 3. Removes the task from `state.backgroundTasks` and broadcasts `state` so the sidebar
143
+ * updates immediately.
144
+ */
145
+ stopBackgroundTask(taskId: string): Promise<void>;
136
146
  /** Per-conversation command lane. All queue mutations and run claims use the same lane, so
137
147
  * two browser tabs cannot both observe an idle conversation and start duplicate turns. */
138
148
  private readonly conversationOps;
@@ -310,6 +310,37 @@ export class RunService {
310
310
  }
311
311
  })());
312
312
  }
313
+ /**
314
+ * Stops an active background task (spawned process or detached subagent) on user request.
315
+ *
316
+ * 1. Kills the underlying PTY child process if one exists in `execService`.
317
+ * 2. If the task originated from a tool call in a conversation transcript, marks the tool
318
+ * call as failed with a clear message and broadcasts `message.tools`.
319
+ * 3. Removes the task from `state.backgroundTasks` and broadcasts `state` so the sidebar
320
+ * updates immediately.
321
+ */
322
+ async stopBackgroundTask(taskId) {
323
+ const tasks = this.store.snapshot().backgroundTasks ?? [];
324
+ const task = tasks.find((t) => t.id === taskId);
325
+ if (this.execService) {
326
+ try {
327
+ this.execService.kill(taskId);
328
+ }
329
+ catch { /* ignore if already exited */ }
330
+ }
331
+ if (task && task.originMessageId !== undefined && task.originCallRow !== undefined) {
332
+ const conv = this.store.snapshot().conversations.find((c) => c.id === task.conversationId);
333
+ const msg = conv?.messages.find((m) => m.id === task.originMessageId);
334
+ if (msg?.toolCalls?.[task.originCallRow]?.backgroundTask) {
335
+ const toolCalls = await this.store.updateToolCall(task.conversationId, task.originMessageId, task.originCallRow, {
336
+ backgroundTask: { id: taskId, status: "failed", output: "已由用户手动终止" },
337
+ });
338
+ this.broadcaster.broadcast({ type: "message.tools", conversationId: task.conversationId, messageId: task.originMessageId, toolCalls });
339
+ }
340
+ }
341
+ await this.store.removeBackgroundTask(taskId);
342
+ this.broadcaster.broadcastState();
343
+ }
313
344
  /** Per-conversation command lane. All queue mutations and run claims use the same lane, so
314
345
  * two browser tabs cannot both observe an idle conversation and start duplicate turns. */
315
346
  conversationOps = new Map();
@@ -108,6 +108,10 @@ export class CommandHandler {
108
108
  sendToSocket({ type: "providers.list", providers: await this.providerService.list(), apis: [...KNOWN_APIS] });
109
109
  return;
110
110
  }
111
+ if (command.type === "backgroundTask.stop") {
112
+ await this.runService.stopBackgroundTask(command.taskId);
113
+ return;
114
+ }
111
115
  if (command.type === "workspace.create") {
112
116
  return await this.workspaceService.createWorkspace(command.name, command.path);
113
117
  }
@@ -283,6 +283,8 @@ async function shutdown(reason) {
283
283
  // The capabilities die AFTER the sessions that carry them: a session that is still alive could
284
284
  // otherwise use a credential the server has already forgotten about.
285
285
  releaseAllCapabilities();
286
+ // Clean up background tasks so the flushed state never freezes running zombies on disk.
287
+ await store.clearBackgroundTasks();
286
288
  await store.flush();
287
289
  wsServer.close();
288
290
  httpServer.closeAllConnections();
@@ -647,6 +647,7 @@ export declare class Store {
647
647
  setWorkflow(plan: WorkflowRun): Promise<WorkflowRun>;
648
648
  setBackgroundTask(summary: AppState["backgroundTasks"][number]): Promise<void>;
649
649
  removeBackgroundTask(id: string): Promise<void>;
650
+ clearBackgroundTasks(): Promise<void>;
650
651
  /**
651
652
  * Applies the fields a run's life can change, and nothing else.
652
653
  *
@@ -498,6 +498,39 @@ function reconcileTodos(state) {
498
498
  const after = JSON.stringify({ todos: state.todos, todosByConversation: state.todosByConversation });
499
499
  return { changed: before !== after };
500
500
  }
501
+ /**
502
+ * Startup reconciliation: cleans up background tasks left over from previous server process.
503
+ *
504
+ * `backgroundTasks` is a LIFECYCLE collection: it tracks active in-flight executions (pty child
505
+ * processes or detached subagents) and is emptied as each task settles. When a server restarts,
506
+ * those processes are dead and cannot report their completion. Leaving them in `backgroundTasks`
507
+ * creates permanent "zombies" in the main sidebar that can never be dismissed.
508
+ *
509
+ * If a task originated from a tool call in a conversation, its tool call block is marked as failed
510
+ * so the chat transcript accurately reflects that the task was interrupted by server restart.
511
+ */
512
+ function reconcileBackgroundTasks(state) {
513
+ const tasks = Array.isArray(state.backgroundTasks) ? state.backgroundTasks : [];
514
+ state.backgroundTasks = [];
515
+ if (!tasks.length)
516
+ return { orphaned: [], changed: false };
517
+ const orphaned = [];
518
+ for (const task of tasks) {
519
+ if (!task)
520
+ continue;
521
+ orphaned.push(task);
522
+ if (task.conversationId && task.originMessageId !== undefined && task.originCallRow !== undefined) {
523
+ const conv = state.conversations?.find((c) => c?.id === task.conversationId);
524
+ const msg = conv?.messages?.find((m) => m?.id === task.originMessageId);
525
+ const call = msg?.toolCalls?.[task.originCallRow];
526
+ if (call?.backgroundTask && call.backgroundTask.status === "running") {
527
+ call.backgroundTask.status = "failed";
528
+ call.backgroundTask.output = "任务随服务重启被终止";
529
+ }
530
+ }
531
+ }
532
+ return { orphaned, changed: true };
533
+ }
501
534
  export class Store {
502
535
  repository;
503
536
  state;
@@ -531,6 +564,7 @@ export class Store {
531
564
  // and the other was not - a half-repaired state that still needs a second restart to finish.
532
565
  const orphaned = reconcileSubagentRuns(state);
533
566
  const orphanedWorkflows = reconcileWorkflows(state);
567
+ const orphanedTasks = reconcileBackgroundTasks(state);
534
568
  const interrupted = reconcileConversations(state);
535
569
  const requeued = reconcileWaitingMessages(state);
536
570
  const todos = reconcileTodos(state);
@@ -538,11 +572,13 @@ export class Store {
538
572
  // Persisted here, in `open`, rather than left for the first unrelated write: a reconciled record that
539
573
  // is only rewritten by a later mutation would still read `running` to anything that opened the file
540
574
  // in the meantime, and would be reconciled a SECOND time on the next restart.
541
- if (defaulted || orphaned.length || orphanedWorkflows.length || interrupted.length || requeued.recovered.length || requeued.changed || todos.changed) {
575
+ if (defaulted || orphaned.length || orphanedWorkflows.length || orphanedTasks.changed || interrupted.length || requeued.recovered.length || requeued.changed || todos.changed) {
542
576
  for (const run of orphaned)
543
577
  console.warn(`Super Pi: sub-agent run ${run.id} was still marked running when the last server stopped - it is now failed, because no child process survived it.`);
544
578
  for (const plan of orphanedWorkflows)
545
579
  console.warn(`Super Pi: workflow ${plan.id} was still marked running when the last server stopped - it is now stopped, because no step can still be executing.`);
580
+ for (const task of orphanedTasks.orphaned)
581
+ console.warn(`Super Pi: background task ${task.id} (${task.title}) was left in flight when the last server stopped - it has been cleaned up.`);
546
582
  // Announced for the same reason: a conversation that failed while nobody was watching is invisible
547
583
  // otherwise, and the user who was watching a spinner when the server died deserves to learn that
548
584
  // their run is over rather than guessing from the fact that it stopped moving.
@@ -1825,6 +1861,12 @@ export class Store {
1825
1861
  this.state.backgroundTasks = this.state.backgroundTasks.filter((item) => item.id !== id);
1826
1862
  await this.persistCollections("backgroundTasks");
1827
1863
  }
1864
+ async clearBackgroundTasks() {
1865
+ if (!this.state.backgroundTasks.length)
1866
+ return;
1867
+ this.state.backgroundTasks = [];
1868
+ await this.persistCollections("backgroundTasks");
1869
+ }
1828
1870
  /**
1829
1871
  * Applies the fields a run's life can change, and nothing else.
1830
1872
  *
@@ -945,6 +945,17 @@ export type ClientCommandBody =
945
945
  | {
946
946
  type: "providers.fetch";
947
947
  }
948
+ /**
949
+ * Stops and removes an active background task (spawned process or background subagent).
950
+ *
951
+ * If the task has a live pty child process, it is killed. If it originated from a tool call in
952
+ * a conversation, that call is marked as stopped/failed in the transcript so the user sees a
953
+ * settled outcome instead of a permanent spinner. The task is then removed from `backgroundTasks`.
954
+ */
955
+ | {
956
+ type: "backgroundTask.stop";
957
+ taskId: string;
958
+ }
948
959
  /**
949
960
  * Sets the app-wide default model. `null` clears it back to "Pi's own default" - the same
950
961
  * "absence, not a frozen copy" convention the workspace defaults use, so removing the default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evandu/super-pi",
3
- "version": "0.1.106",
3
+ "version": "0.1.107",
4
4
  "description": "Web control plane and companion for Pi",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -92,6 +92,8 @@
92
92
  "scripts/file-content-search.test.mjs",
93
93
  "scripts/file-diff-client.test.mjs",
94
94
  "scripts/task-tool.test.mjs",
95
+ "scripts/tool-register-env.test.mjs",
96
+ "scripts/bg-task-zombie.test.mjs",
95
97
  "scripts/fork-server.test.mjs",
96
98
  "scripts/styles-no-dangling.test.mjs",
97
99
  "scripts/theme-no-hardcoded-colours.test.mjs",