agentus 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/README.zh-CN.md +2 -1
- package/docs/installation.md +1 -1
- package/docs/installation.zh-CN.md +1 -1
- package/package.json +2 -1
- package/packages/server/src/acp/agent-owner.ts +141 -0
- package/packages/server/src/acp/session-manager.ts +166 -9
- package/packages/server/src/acp/voice-mode.ts +126 -0
- package/packages/server/src/index.ts +43 -2
- package/packages/server/src/instance-lock.ts +235 -0
- package/packages/server/src/notify/center.ts +19 -0
- package/packages/server/src/store/store.ts +95 -0
- package/packages/web/dist/assets/{index-B2YR8mN4.js → index-D34Kt-uv.js} +2 -2
- package/packages/web/dist/assets/index-Dej-v4qD.css +32 -0
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/assets/index-CDd0dpAg.css +0 -32
|
@@ -122,10 +122,10 @@ click to point this session at another directory`,"aria-label":"change workspace
|
|
|
122
122
|
|
|
123
123
|
旧进程退出、新进程接管同一个会话:对话记录、模型和思考深度都保留,只有进程换新(改完代码或改了后端配置后,用它让槽位吃到新东西)。正在跑的这一轮会被中断。`)&&X.restart(he.id)},onDelete:()=>{te(null),confirm(`删除“${he.title}”?
|
|
124
124
|
|
|
125
|
-
记录会从磁盘上移除,无法撤销。`)&&X.purgeCold(he.id)}}),document.body):null,$e?hl.createPortal(o.jsx("div",{className:"modal-bg",onClick:()=>Ze(""),children:o.jsxs("div",{className:"modal narrow",onClick:ee=>ee.stopPropagation(),children:[o.jsx("h3",{children:"工作目录"}),o.jsx("div",{className:"hint",children:"文件面板与终端以它为根。运行中的 agent 仍留在启动时的目录 —— 新目录对下一次恢复生效。"}),o.jsx(tg,{value:Y?.workspace??Y?.cwd??"",onChange:ee=>{const ve=$e;Ze(""),X.setWorkspace(ve,ee)}}),o.jsx("div",{className:"row",children:o.jsx("button",{className:"cancel",onClick:()=>Ze(""),children:"取消"})})]})}),document.body):null,o.jsxs("footer",{children:[o.jsx("span",{className:`conn ${p}`,children:p==="online"?"● online":p}),y?o.jsx("span",{className:"who",title:`signed in as ${y.username??"?"}`,children:y.username}):null,o.jsx("button",{className:"logout-btn",title:`signed in as ${y?.username??"?"} — sign out`,"aria-label":"sign out",onClick:()=>void X.logout(),children:o.jsx(Ow,{size:14})})]})]})}function JP({onMenu:e,settingsOpen:t,onCloseSettings:s,onPermClick:n,panelWidth:i,panelHandle:r}){const{active:a}=_.useSyncExternalStore(X.subscribe,X.getSnapshot),[l,c]=_.useState(!1),[u,h]=_.useState(null);_.useEffect(()=>RN(y=>{c(!0),h({...y})}),[]);const[d,p]=_.useState(!1),[f,m]=_.useState(!1);return _.useEffect(()=>{vu()},[]),lN(XP(a),!!(a&&!a.busy&&a.loaded)),cN(ZP(a),!!a),t?o.jsx(rD,{onClose:s,sessionId:a?.info.id}):a?o.jsxs("div",{className:"main",children:[o.jsx(e5,{v:a,onMenu:e,panelOpen:l,onTogglePanel:()=>c(y=>!y),onPickWorkspace:()=>p(!0),call:f,onCall:()=>{we.stop(),m(!0)},onPerm:n}),o.jsxs("div",{className:"main-body",children:[o.jsxs("div",{className:"chat-col",children:[o.jsx(i5,{v:a}),o.jsx(T5,{v:a,call:f,onCloseCall:()=>m(!1)})]}),l&&o.jsx(yP,{v:a,onClose:()=>c(!1),onPickWorkspace:()=>p(!0),focus:u,panelWidth:i,panelHandle:r})]}),d&&o.jsx(QP,{v:a,onClose:()=>p(!1)})]}):o.jsxs("div",{className:"main",children:[o.jsxs("div",{className:"chat-head",children:[o.jsx("button",{className:"icon-btn menu-btn",onClick:e,title:"sessions","aria-label":"sessions",children:o.jsx(Rw,{})}),o.jsx("span",{className:"title",children:"Agentus"})]}),o.jsxs("div",{className:"empty",children:[o.jsx("div",{className:"big",children:o.jsx(eg,{size:72})}),o.jsxs("p",{children:["No session selected.",o.jsx("br",{}),"Create one and point it at a real ",o.jsx("code",{children:"hermes acp"})," / ",o.jsx("code",{children:"qodercli --acp"}),"."]})]})]})}function XP(e){if(!e||e.busy||!e.loaded||Date.now()-e.lastAt>3e4)return null;for(let t=e.msgs.length-1;t>=0;t-=1){const s=e.msgs[t];if(s.kind==="agent"&&s.text.trim())return{key:s.key,text:s.text}}return null}function ZP(e){const t=e?.speaks?.[e.speaks.length-1];return t?{key:`brief:${t.id}`,text:t.text}:null}function QP({v:e,onClose:t}){Wo(!0,t);const s=e.info.workspace||e.info.cwd,[n,i]=_.useState(s),[r,a]=_.useState(!1),[l,c]=_.useState(""),u=async()=>{a(!0),c("");try{await X.setWorkspace(e.info.id,n.trim()),t()}catch(h){c(String(h?.message??h))}finally{a(!1)}};return o.jsx("div",{className:"modal-bg",onClick:t,children:o.jsxs("div",{className:"modal narrow",onClick:h=>h.stopPropagation(),children:[o.jsx("h3",{children:"workspace"}),o.jsx("div",{className:"hint",children:"the file panel and terminal work here. A running agent keeps the directory it was started in — the new one applies to this session from the next resume."}),o.jsx(tg,{value:n,onChange:i}),l&&o.jsx("div",{className:"err",children:l}),o.jsxs("div",{className:"row",children:[o.jsx("button",{className:"cancel",onClick:t,children:"cancel"}),o.jsx("button",{className:"go",disabled:r||!n.trim(),onClick:()=>void u(),children:r?"saving…":"use this folder"})]})]})})}function e5({v:e,onMenu:t,panelOpen:s,onTogglePanel:n,onPickWorkspace:i,call:r,onCall:a,onPerm:l}){const c=e.info;(c.workspace||c.cwd).split("/").filter(Boolean).pop()??c.cwd;const[u,h]=lr(),p=_.useSyncExternalStore(LE,Vn).tts.server||typeof window<"u"&&"speechSynthesis"in window,f=u.speakMode??(u.autoRead?"reply":"off"),[m,y]=_.useState(!1),x=_.useRef(null);Br(m,[x],()=>y(!1));const[g,v]=x5(),b=(N,P)=>{y(!1),h({speakMode:N,autoRead:N==="reply"}),N==="brief"&&P!==void 0&&v(P)},w=_.useRef({timer:null,fired:!1}),k=()=>{w.current.timer&&(window.clearTimeout(w.current.timer),w.current.timer=null)};_.useEffect(()=>k,[]);const j=()=>{w.current.fired=!1,k(),w.current.timer=window.setTimeout(()=>{w.current.fired=!0,y(!0)},500)},I=()=>{if(w.current.fired){w.current.fired=!1;return}b(f==="off"?"reply":"off")},A=[{key:"off",mode:"off",interval:null,label:"关"},{key:"reply",mode:"reply",interval:null,label:"自动朗读(点一下就是这个 · 默认)"},{key:"brief",mode:"brief",interval:0,label:"工作播报(有进展就说一句)"},{key:"brief-60",mode:"brief",interval:60,label:"工作播报(每 1 分钟也报一次)"},{key:"brief-120",mode:"brief",interval:120,label:"工作播报(每 2 分钟也报一次)"},{key:"brief-300",mode:"brief",interval:300,label:"工作播报(每 5 分钟也报一次)"}],D=N=>N.mode===f&&(N.mode!=="brief"||N.interval===g),O=f==="brief"&&!A.some(N=>N.mode==="brief"&&N.interval===g),F=f==="off"?"关":f==="reply"?"自动朗读(念整条回复)":g>0?`工作播报 · 每 ${Dd(g)}`:"工作播报(念驾驶舱的一句话)",C=p?`朗读:${F} —— 点一下开/关,长按选档(右键同)`:"朗读:这台设备没有可用语音(浏览器无 speechSynthesis,服务端也没配)";return o.jsxs("div",{className:"chat-head",children:[o.jsx("button",{className:"icon-btn menu-btn",onClick:t,title:"sessions","aria-label":"sessions",children:o.jsx(Rw,{})}),o.jsx("span",{className:"title",title:c.title,children:c.title}),o.jsx(t5,{busy:Rr(e),lastAt:e.lastAt}),e.perms.length>0?o.jsxs("button",{type:"button",className:"chip perm-chip",title:"这个会话有请求等你的答复 —— 点一下打开授权弹窗","aria-label":`有 ${e.perms.length} 个请求等你授权`,onClick:l,children:[o.jsx("span",{className:"perm-pulse"}),"⚿ ",e.perms.length]}):null,o.jsx("span",{className:"head-spacer"}),o.jsxs("span",{className:"head-actions",children:[o.jsx("button",{className:`icon-btn ${r?"on":""}`,title:"语音通话 —— 像打电话一样跟这个会话说话","aria-label":"开始语音通话",onClick:a,children:o.jsx(pE,{})}),o.jsxs("span",{className:"speak-wrap",ref:x,children:[o.jsxs("button",{className:`icon-btn auto-read ${f!=="off"?"on":""}`,title:C,"aria-label":"朗读:点一下开/关,长按选读什么","aria-pressed":f!=="off","aria-haspopup":"menu","aria-expanded":m,"data-speak-mode":f,disabled:!p,onClick:I,onPointerDown:j,onPointerUp:k,onPointerLeave:k,onPointerCancel:k,onContextMenu:N=>{N.preventDefault(),k(),y(!0)},onKeyDown:N=>{(N.key==="F10"&&N.shiftKey||N.key==="ContextMenu")&&(N.preventDefault(),y(!0))},children:[f==="off"?o.jsx(Lw,{}):o.jsx(th,{}),f==="brief"?o.jsx("span",{className:"speak-dot","aria-hidden":!0}):null]}),m?o.jsxs("div",{className:"speak-menu",role:"menu",children:[A.map(N=>o.jsxs("button",{type:"button",role:"menuitemradio","aria-checked":D(N),className:`speak-menu-item ${D(N)?"on":""}`,"data-speak-option":N.key,onClick:()=>b(N.mode,N.interval??void 0),children:[o.jsx("span",{className:"speak-check",children:D(N)?"✓":""}),o.jsx("span",{className:"speak-name",children:N.label})]},N.key)),o.jsxs("button",{type:"button",role:"menuitem","aria-checked":O,className:`speak-menu-item ${O?"on":""}`,"data-speak-option":"custom",onClick:()=>{y(!1),window.dispatchEvent(new CustomEvent("agentus:open-settings",{detail:"voice"}))},children:[o.jsx("span",{className:"speak-check",children:O?"✓":""}),o.jsx("span",{className:"speak-name",children:O?`自定义节拍(现在 · 每 ${Dd(g)})`:"自定义节拍…"})]}),o.jsx("p",{className:"speak-hint",children:f==="brief"?g>0?`有任务在跑时每 ${Dd(g)} 念一句;没任务在跑不念。观察员在 设置 → 观察智能体`:"回合结束、待审批时由一个观察智能体念一句(设置 → 观察智能体)":f==="reply"?"每条回复结束后念全文 —— 长回复会被截断":"不自动出声;点消息旁的喇叭可以按需念"})]}):null]}),o.jsx("button",{className:"icon-btn",title:`workspace: ${c.workspace||c.cwd}
|
|
125
|
+
记录会从磁盘上移除,无法撤销。`)&&X.purgeCold(he.id)}}),document.body):null,$e?hl.createPortal(o.jsx("div",{className:"modal-bg",onClick:()=>Ze(""),children:o.jsxs("div",{className:"modal narrow",onClick:ee=>ee.stopPropagation(),children:[o.jsx("h3",{children:"工作目录"}),o.jsx("div",{className:"hint",children:"文件面板与终端以它为根。运行中的 agent 仍留在启动时的目录 —— 新目录对下一次恢复生效。"}),o.jsx(tg,{value:Y?.workspace??Y?.cwd??"",onChange:ee=>{const ve=$e;Ze(""),X.setWorkspace(ve,ee)}}),o.jsx("div",{className:"row",children:o.jsx("button",{className:"cancel",onClick:()=>Ze(""),children:"取消"})})]})}),document.body):null,o.jsxs("footer",{children:[o.jsx("span",{className:`conn ${p}`,children:p==="online"?"● online":p}),y?o.jsx("span",{className:"who",title:`signed in as ${y.username??"?"}`,children:y.username}):null,o.jsx("button",{className:"logout-btn",title:`signed in as ${y?.username??"?"} — sign out`,"aria-label":"sign out",onClick:()=>void X.logout(),children:o.jsx(Ow,{size:14})})]})]})}function JP({onMenu:e,settingsOpen:t,onCloseSettings:s,onPermClick:n,panelWidth:i,panelHandle:r}){const{active:a}=_.useSyncExternalStore(X.subscribe,X.getSnapshot),[l,c]=_.useState(!1),[u,h]=_.useState(null);_.useEffect(()=>RN(y=>{c(!0),h({...y})}),[]);const[d,p]=_.useState(!1),[f,m]=_.useState(!1);return _.useEffect(()=>{fetch("/api/notify/presence",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify({sessionId:a?.info.id??null,visible:!0,call:f})}).catch(()=>{})},[f,a?.info.id]),_.useEffect(()=>{vu()},[]),lN(XP(a),!!(a&&!a.busy&&a.loaded)),cN(ZP(a),!!a),t?o.jsx(rD,{onClose:s,sessionId:a?.info.id}):a?o.jsxs("div",{className:"main",children:[o.jsx(e5,{v:a,onMenu:e,panelOpen:l,onTogglePanel:()=>c(y=>!y),onPickWorkspace:()=>p(!0),call:f,onCall:()=>{we.stop(),m(!0)},onPerm:n}),o.jsxs("div",{className:"main-body",children:[o.jsxs("div",{className:"chat-col",children:[o.jsx(i5,{v:a}),o.jsx(T5,{v:a,call:f,onCloseCall:()=>m(!1)})]}),l&&o.jsx(yP,{v:a,onClose:()=>c(!1),onPickWorkspace:()=>p(!0),focus:u,panelWidth:i,panelHandle:r})]}),d&&o.jsx(QP,{v:a,onClose:()=>p(!1)})]}):o.jsxs("div",{className:"main",children:[o.jsxs("div",{className:"chat-head",children:[o.jsx("button",{className:"icon-btn menu-btn",onClick:e,title:"sessions","aria-label":"sessions",children:o.jsx(Rw,{})}),o.jsx("span",{className:"title",children:"Agentus"})]}),o.jsxs("div",{className:"empty",children:[o.jsx("div",{className:"big",children:o.jsx(eg,{size:72})}),o.jsxs("p",{children:["No session selected.",o.jsx("br",{}),"Create one and point it at a real ",o.jsx("code",{children:"hermes acp"})," / ",o.jsx("code",{children:"qodercli --acp"}),"."]})]})]})}function XP(e){if(!e||e.busy||!e.loaded||Date.now()-e.lastAt>3e4)return null;for(let t=e.msgs.length-1;t>=0;t-=1){const s=e.msgs[t];if(s.kind==="agent"&&s.text.trim())return{key:s.key,text:s.text}}return null}function ZP(e){const t=e?.speaks?.[e.speaks.length-1];return t?{key:`brief:${t.id}`,text:t.text}:null}function QP({v:e,onClose:t}){Wo(!0,t);const s=e.info.workspace||e.info.cwd,[n,i]=_.useState(s),[r,a]=_.useState(!1),[l,c]=_.useState(""),u=async()=>{a(!0),c("");try{await X.setWorkspace(e.info.id,n.trim()),t()}catch(h){c(String(h?.message??h))}finally{a(!1)}};return o.jsx("div",{className:"modal-bg",onClick:t,children:o.jsxs("div",{className:"modal narrow",onClick:h=>h.stopPropagation(),children:[o.jsx("h3",{children:"workspace"}),o.jsx("div",{className:"hint",children:"the file panel and terminal work here. A running agent keeps the directory it was started in — the new one applies to this session from the next resume."}),o.jsx(tg,{value:n,onChange:i}),l&&o.jsx("div",{className:"err",children:l}),o.jsxs("div",{className:"row",children:[o.jsx("button",{className:"cancel",onClick:t,children:"cancel"}),o.jsx("button",{className:"go",disabled:r||!n.trim(),onClick:()=>void u(),children:r?"saving…":"use this folder"})]})]})})}function e5({v:e,onMenu:t,panelOpen:s,onTogglePanel:n,onPickWorkspace:i,call:r,onCall:a,onPerm:l}){const c=e.info;(c.workspace||c.cwd).split("/").filter(Boolean).pop()??c.cwd;const[u,h]=lr(),p=_.useSyncExternalStore(LE,Vn).tts.server||typeof window<"u"&&"speechSynthesis"in window,f=u.speakMode??(u.autoRead?"reply":"off"),[m,y]=_.useState(!1),x=_.useRef(null);Br(m,[x],()=>y(!1));const[g,v]=x5(),b=(N,P)=>{y(!1),h({speakMode:N,autoRead:N==="reply"}),N==="brief"&&P!==void 0&&v(P)},w=_.useRef({timer:null,fired:!1}),k=()=>{w.current.timer&&(window.clearTimeout(w.current.timer),w.current.timer=null)};_.useEffect(()=>k,[]);const j=()=>{w.current.fired=!1,k(),w.current.timer=window.setTimeout(()=>{w.current.fired=!0,y(!0)},500)},I=()=>{if(w.current.fired){w.current.fired=!1;return}b(f==="off"?"reply":"off")},A=[{key:"off",mode:"off",interval:null,label:"关"},{key:"reply",mode:"reply",interval:null,label:"自动朗读(点一下就是这个 · 默认)"},{key:"brief",mode:"brief",interval:0,label:"工作播报(有进展就说一句)"},{key:"brief-60",mode:"brief",interval:60,label:"工作播报(每 1 分钟也报一次)"},{key:"brief-120",mode:"brief",interval:120,label:"工作播报(每 2 分钟也报一次)"},{key:"brief-300",mode:"brief",interval:300,label:"工作播报(每 5 分钟也报一次)"}],D=N=>N.mode===f&&(N.mode!=="brief"||N.interval===g),O=f==="brief"&&!A.some(N=>N.mode==="brief"&&N.interval===g),F=f==="off"?"关":f==="reply"?"自动朗读(念整条回复)":g>0?`工作播报 · 每 ${Dd(g)}`:"工作播报(念驾驶舱的一句话)",C=p?`朗读:${F} —— 点一下开/关,长按选档(右键同)`:"朗读:这台设备没有可用语音(浏览器无 speechSynthesis,服务端也没配)";return o.jsxs("div",{className:"chat-head",children:[o.jsx("button",{className:"icon-btn menu-btn",onClick:t,title:"sessions","aria-label":"sessions",children:o.jsx(Rw,{})}),o.jsx("span",{className:"title",title:c.title,children:c.title}),o.jsx(t5,{busy:Rr(e),lastAt:e.lastAt}),e.perms.length>0?o.jsxs("button",{type:"button",className:"chip perm-chip",title:"这个会话有请求等你的答复 —— 点一下打开授权弹窗","aria-label":`有 ${e.perms.length} 个请求等你授权`,onClick:l,children:[o.jsx("span",{className:"perm-pulse"}),"⚿ ",e.perms.length]}):null,o.jsx("span",{className:"head-spacer"}),o.jsxs("span",{className:"head-actions",children:[o.jsx("button",{className:`icon-btn ${r?"on":""}`,title:"语音通话 —— 像打电话一样跟这个会话说话","aria-label":"开始语音通话",onClick:a,children:o.jsx(pE,{})}),o.jsxs("span",{className:"speak-wrap",ref:x,children:[o.jsxs("button",{className:`icon-btn auto-read ${f!=="off"?"on":""}`,title:C,"aria-label":"朗读:点一下开/关,长按选读什么","aria-pressed":f!=="off","aria-haspopup":"menu","aria-expanded":m,"data-speak-mode":f,disabled:!p,onClick:I,onPointerDown:j,onPointerUp:k,onPointerLeave:k,onPointerCancel:k,onContextMenu:N=>{N.preventDefault(),k(),y(!0)},onKeyDown:N=>{(N.key==="F10"&&N.shiftKey||N.key==="ContextMenu")&&(N.preventDefault(),y(!0))},children:[f==="off"?o.jsx(Lw,{}):o.jsx(th,{}),f==="brief"?o.jsx("span",{className:"speak-dot","aria-hidden":!0}):null]}),m?o.jsxs("div",{className:"speak-menu",role:"menu",children:[A.map(N=>o.jsxs("button",{type:"button",role:"menuitemradio","aria-checked":D(N),className:`speak-menu-item ${D(N)?"on":""}`,"data-speak-option":N.key,onClick:()=>b(N.mode,N.interval??void 0),children:[o.jsx("span",{className:"speak-check",children:D(N)?"✓":""}),o.jsx("span",{className:"speak-name",children:N.label})]},N.key)),o.jsxs("button",{type:"button",role:"menuitem","aria-checked":O,className:`speak-menu-item ${O?"on":""}`,"data-speak-option":"custom",onClick:()=>{y(!1),window.dispatchEvent(new CustomEvent("agentus:open-settings",{detail:"voice"}))},children:[o.jsx("span",{className:"speak-check",children:O?"✓":""}),o.jsx("span",{className:"speak-name",children:O?`自定义节拍(现在 · 每 ${Dd(g)})`:"自定义节拍…"})]}),o.jsx("p",{className:"speak-hint",children:f==="brief"?g>0?`有任务在跑时每 ${Dd(g)} 念一句;没任务在跑不念。观察员在 设置 → 观察智能体`:"回合结束、待审批时由一个观察智能体念一句(设置 → 观察智能体)":f==="reply"?"每条回复结束后念全文 —— 长回复会被截断":"不自动出声;点消息旁的喇叭可以按需念"})]}):null]}),o.jsx("button",{className:"icon-btn",title:`workspace: ${c.workspace||c.cwd}
|
|
126
126
|
click to point this session at another directory`,"aria-label":"workspace",onClick:i,children:o.jsx($r,{})}),o.jsx("button",{className:`icon-btn ${s?"on":""}`,title:"workspace panel — files and terminal","aria-label":"workspace panel","aria-expanded":s,onClick:n,children:o.jsx(uE,{})})]})]})}const Va={current:()=>{}},cy=4,t5=_.memo(function({busy:t,lastAt:s}){const[,n]=_.useState(0);if(_.useEffect(()=>{if(!t)return;const a=window.setInterval(()=>n(l=>l+1),1e3);return()=>window.clearInterval(a)},[t]),!t)return null;const{quiet:i,said:r}=cD(s,Date.now());return o.jsx("span",{className:`turn-pulse ${i?"quiet":""}`,role:"status","aria-label":r,title:r})}),s5=_.memo(function({busy:t,since:s}){const[n,i]=_.useState(null),[r,a]=_.useState(()=>Date.now());if(_.useEffect(()=>{if(!t){i(null);return}i(s??Date.now()),a(Date.now());const c=window.setInterval(()=>a(Date.now()),1e3);return()=>window.clearInterval(c)},[t,s]),!t)return null;const l=n??s;return o.jsxs("div",{className:"stream-hint",role:"status","data-anchor":l??void 0,children:[o.jsx("span",{className:"stream-spin","aria-hidden":"true"}),o.jsx("span",{children:"处理中"}),l!=null?o.jsxs("span",{className:"elapsed",children:["(",Ru(r-l),")"]}):null]})});function n5({v:e}){const t=e.background??[],[s,n]=_.useState(!1);if(!t.length)return null;const i=t.filter(c=>c.status==="running"),r=t.filter(c=>c.status!=="running"),a=i.reduce((c,u)=>c+(u.kind==="delegation"?u.taskCount??1:0),0),l=i.length?`后台任务 ${i.length} 个运行中${a?`(含 ${a} 个子任务)`:""} · 完成后会唤醒会话`:`${r.length} 个后台任务已结束`;return o.jsxs("div",{className:`bg-row ${s?"open":""}`,"data-count":t.length,children:[o.jsxs("button",{type:"button",className:"bg-head","aria-expanded":s,onClick:()=>n(!s),children:[o.jsx("span",{className:"bg-dot","aria-hidden":"true","data-state":i.length?"running":"exited","data-wake":i.length?"1":void 0}),o.jsx("span",{className:"bg-text",children:l}),i.length&&!e.busy?o.jsx("span",{className:"bg-hint",children:"会话已空闲,后台仍在跑"}):null,o.jsx("span",{className:"bg-caret","aria-hidden":"true",children:s?"▾":"▸"})]}),s&&o.jsx("ul",{className:"bg-list",children:t.map(c=>o.jsxs("li",{className:"bg-item","data-state":c.status,"data-kind":c.kind??"process",children:[c.kind==="delegation"?o.jsx("span",{className:"bg-tag",children:"子任务"}):null,o.jsx("pre",{className:"bg-cmd-full",children:c.command||c.id}),o.jsxs("div",{className:"bg-item-foot",children:[o.jsx("span",{className:"bg-meta",children:c.kind==="delegation"?o.jsxs(o.Fragment,{children:[(c.taskCount??1)>1?`${c.taskCount} 个子代理 · `:"",c.status==="running"?`运行 ${Ru((c.uptimeSeconds??0)*1e3)}${c.phase==="stalling"?" · 停滞中":c.phase==="finalizing"?" · 收尾中":""}`:"已结束"]}):o.jsxs(o.Fragment,{children:[c.pid?`pid ${c.pid} · `:"",c.status==="running"?`运行 ${Ru((c.uptimeSeconds??0)*1e3)}`:`exit ${c.exitCode??"?"}`]})}),c.command?o.jsx(Lu,{text:c.command,what:c.kind==="delegation"?"这个目标":"这条命令"}):null]})]},c.id))})]})}function Cc({n:e}){const t=new Date(e.at),s=`${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}:${String(t.getSeconds()).padStart(2,"0")}`,n=e.items??[],[i,r]=_.useState(!1),a=_.useRef(null),[l,c]=_.useState(!1);return _.useLayoutEffect(()=>{if(!i){c(!1);return}const u=a.current;if(!u)return;const h=()=>c(u.scrollHeight-u.clientHeight>4);h();const d=new ResizeObserver(h);return d.observe(u),()=>d.disconnect()},[i,n.length]),o.jsxs("div",{className:"status-note","data-kind":e.kind||"lifecycle",role:"note",title:t.toLocaleString(),children:[o.jsx("span",{className:"status-note-time",children:s}),o.jsx("span",{className:"status-note-text",children:e.text}),n.length?o.jsxs(o.Fragment,{children:[o.jsx("button",{type:"button",className:"status-note-toggle","aria-expanded":i,"aria-label":`${i?"收起":"展开"}这 ${n.length} 条记忆`,onClick:()=>r(u=>!u),children:i?"收起":`${n.length} 条`}),i?o.jsx("div",{className:"status-note-drawer-wrap",children:o.jsxs("div",{className:"status-note-drawer","data-scroll":l?"1":"0",children:[o.jsxs("div",{className:"status-note-drawer-head",children:[o.jsxs("span",{children:["共 ",n.length," 条"]}),l?o.jsx("span",{className:"status-note-drawer-hint",children:"滚轮查看"}):null]}),o.jsxs("ol",{className:"status-note-items",ref:a,children:[n.map((u,h)=>o.jsxs("li",{className:"status-note-item",children:[o.jsx("span",{className:"status-note-item-n",children:h+1}),o.jsxs("span",{className:"status-note-item-body",children:[o.jsx("span",{className:"status-note-item-text",children:u.text}),u.tags?.length?o.jsx("span",{className:"status-note-item-tags",children:u.tags.join(" · ")}):null]})]},h)),e.truncated?o.jsx("li",{className:"status-note-item more",children:"…还有更多,已截断"}):null]})]})}):null]}):null]})}function _1({msgs:e,sid:t,backend:s,busy:n,base:i,notes:r=[]}){const a=g5(e),l=[];let c=0;for(;c<r.length&&r[c].afterKey===null;)l.push(o.jsx(Cc,{n:r[c]},r[c].key)),c++;for(const u of a){u.kind==="work"?(l.push(o.jsx(_5,{items:u.items},u.key)),l.push(o.jsx(dy,{msgs:u.items},`fc-${u.key}`))):u.m.kind==="note"?l.push(o.jsx(Cc,{n:{key:u.m.key,kind:u.m.category,text:u.m.text,at:u.m.at??Date.now(),hits:u.m.hits,items:u.m.items,truncated:u.m.truncated}},u.m.key)):(l.push(o.jsx(h5,{m:u.m,sid:t,backend:s,busy:n,last:u.tail,live:u.live,base:i},u.m.key)),u.m.kind==="tool"&&l.push(o.jsx(dy,{msgs:[u.m]},`fc-${u.m.key}`)));const h=new Set(u.kind==="msg"?[u.m.key]:u.items.map(d=>d.key));for(let d=r[c];d&&d.afterKey!==null&&h.has(d.afterKey);d=r[c])l.push(o.jsx(Cc,{n:d},d.key)),c++}for(;c<r.length;)l.push(o.jsx(Cc,{n:r[c]},r[c].key)),c++;return o.jsx(o.Fragment,{children:l})}function i5({v:e}){const t=_.useRef(null),s=_.useRef(!0),n=_.useRef(0),i=_.useRef(-1e9),r=_.useRef(0),a=_.useRef(0),l=_.useRef(0),[c,u]=_.useState(!0),[h,d]=_.useState(!1),p=64,f=()=>performance.now(),m=D=>D.scrollHeight-D.scrollTop-D.clientHeight<=p,y=1200,x=D=>{r.current=f()+150,a.current=D.scrollTop,l.current=D.scrollHeight},g=()=>{const D=t.current;D&&(D.scrollTop=D.scrollHeight,x(D))},v=()=>{s.current=!1,n.current=0,u(!1)};Va.current=()=>{s.current=!0,n.current=f()+1200,u(!0),d(!1),g()},_.useEffect(()=>{const D=t.current;if(!D)return;const O=()=>{i.current=f()},F=()=>{const E=D.scrollTop,z=E-a.current;a.current=E;const H=D.scrollHeight,ne=H<l.current-1;if(l.current=H,z<-2&&!ne&&f()-i.current<y){v();return}if(f()<r.current)return;const ae=m(D);ae!==s.current&&(s.current=ae,u(ae)),ae&&d(!1)},C=E=>{O(),E.deltaY<0&&v()};let N=0;const P=E=>{O(),N=E.touches[0]?.clientY??0},B=E=>{O(),(E.touches[0]?.clientY??0)>N+4&&v()},T=E=>{O(),(E.key==="PageUp"||E.key==="ArrowUp"||E.key==="Home")&&v()},$=()=>O();return D.addEventListener("scroll",F,{passive:!0}),D.addEventListener("wheel",C,{passive:!0}),D.addEventListener("touchstart",P,{passive:!0}),D.addEventListener("touchmove",B,{passive:!0}),D.addEventListener("keydown",T),D.addEventListener("pointerdown",$,{passive:!0}),x(D),()=>{D.removeEventListener("scroll",F),D.removeEventListener("wheel",C),D.removeEventListener("touchstart",P),D.removeEventListener("touchmove",B),D.removeEventListener("keydown",T),D.removeEventListener("pointerdown",$)}},[]),_.useEffect(()=>{if(s.current||f()<n.current){g();return}e.msgs.length&&d(!0)},[e.rev,e.busy,e.perms.length]),_.useEffect(()=>{const D=t.current,O=D?.firstElementChild??null;if(!D||!O||typeof ResizeObserver>"u")return;const F=new ResizeObserver(()=>{!s.current&&f()>=n.current||requestAnimationFrame(()=>{(s.current||f()<n.current)&&g()})});return F.observe(O),()=>F.disconnect()},[e.info.id]);const b=async D=>{const O=t.current,F=O?.scrollHeight??0,C=O?.scrollTop??0;D||(s.current=!1,u(!1)),A(!0),await X.loadEarlier(e.info.id),requestAnimationFrame(()=>{const N=t.current;N&&(N.scrollTop=N.scrollHeight-F+C,x(N))})},w=()=>{b(!1)},k=async D=>{const O=[...D.queue];try{const F=await X.createSession(String(D.info.backend),D.info.cwd,"");X.setActive(F);for(const C of O)X.enqueuePrompt(F,C.text,C.attachments);X.purgeCold(D.info.id)}catch{}},j=_.useRef(0),[I,A]=_.useState(!1);return _.useEffect(()=>{j.current=0,A(!1)},[e.info.id]),_.useEffect(()=>{const D=t.current;!D||!e.hasOlder||e.loadingOlder||j.current>=cy||D.scrollHeight>D.clientHeight+80||(j.current+=1,b(!0))},[e.rev,e.hasOlder,e.loadingOlder,e.info.id]),_.useEffect(()=>{const D=t.current;if(!D)return;const O=()=>{!e.hasOlder||e.loadingOlder||j.current>=cy||D.scrollTop>D.clientHeight*1.5||(j.current+=1,b(!0))};return D.addEventListener("scroll",O,{passive:!0}),()=>D.removeEventListener("scroll",O)},[e.info.id,e.hasOlder,e.loadingOlder]),o.jsxs("div",{className:"stream-wrap",children:[o.jsx("div",{className:"stream",ref:t,tabIndex:0,children:o.jsxs("div",{className:"stream-inner",children:[e.info.status==="starting"?o.jsxs("div",{className:"start-hold",role:"status",children:[o.jsx("span",{className:"stream-spin","aria-hidden":"true"}),o.jsx("span",{children:"正在启动 agent 进程…好了会自动把消息发出去"})]}):null,e.info.status==="error"&&e.info.lastError?o.jsxs("div",{className:"start-fail",role:"alert",children:[o.jsxs("div",{className:"start-fail-why",children:["会话启动失败:",e.info.lastError]}),o.jsxs("div",{className:"start-fail-act",children:[o.jsx("button",{className:"ghost-btn",onClick:()=>void k(e),children:"再试一次"}),o.jsx("button",{className:"ghost-btn",onClick:()=>X.purgeCold(e.info.id),children:"删除这个会话"})]})]}):null,e.hasOlder?o.jsx("div",{className:"load-earlier",children:e.loadingOlder?o.jsx("span",{className:"load-earlier-busy",children:"正在加载更早的消息…"}):o.jsx("button",{className:"ghost-btn",onClick:()=>w(),children:"↑ load earlier messages"})}):I&&e.msgs.length?o.jsx("div",{className:"load-earlier",children:o.jsx("span",{className:"load-earlier-end",children:"已到开头"})}):null,o.jsx(_1,{msgs:e.msgs,notes:e.notes,sid:e.info.id,backend:e.info.backend,busy:Rr(e),base:e.info.workspace||e.info.cwd}),o.jsx(s5,{busy:Rr(e),since:e.busySince}),e.perms.filter(D=>!e.msgs.some(O=>O.kind==="approval"&&O.requestId===D.requestId)).map(D=>o.jsx(b1,{sid:e.info.id,req:D},D.requestId))]})}),!c&&o.jsxs("button",{className:`jump-latest ${h?"has-new":""}`,onClick:()=>Va.current(),title:h?"new output — jump to the newest":"jump to the newest","aria-label":"jump to newest output",children:[o.jsx(Pw,{size:14}),h?o.jsx("span",{className:"jump-dot","aria-hidden":"true"}):null]})]})}const v1=_.memo(m5,(e,t)=>e.live===t.live&&e.m.key===t.m.key&&e.m.text===t.m.text&&e.m.at===t.m.at),r5=(e,t)=>{const s=e.m,n=t.m;return s.key===n.key&&s.title===n.title&&s.status===n.status&&s.detail===n.detail&&s.input===n.input&&s.at===n.at},y1=_.memo(p5,r5),o5=(e,t)=>{const s=e.m,n=t.m;return e.busy===t.busy&&s.key===n.key&&s.at===n.at&&s.terminal===n.terminal&&s.explanation===n.explanation&&JSON.stringify(s.items)===JSON.stringify(n.items)},a5=_.memo(f5,o5);function l5({text:e}){const t=jP(e),[s,n]=_.useState(!1);return t?o.jsxs("div",{className:`bg-notice ${s?"open":""}`,"data-ok":t.ok?"ok":"fail",children:[o.jsxs("button",{type:"button",className:"bg-notice-head","aria-expanded":s,onClick:()=>n(!s),children:[o.jsx("span",{className:"bg-notice-dot","aria-hidden":"true"}),o.jsx("span",{className:"bg-notice-title",children:t.kind==="watch"?"后台任务命中":"后台任务完成"}),o.jsx("code",{className:"bg-notice-cmd",title:t.command,children:ry(t.command)}),t.kind==="watch"?o.jsxs("code",{className:"bg-notice-code",title:t.pattern,children:["「",ry(t.pattern,28),"」"]}):t.exitCode===null?o.jsx("span",{className:"bg-notice-code",children:"已结束"}):o.jsxs("span",{className:"bg-notice-code",children:["exit ",t.exitCode]}),o.jsx("span",{className:"bg-notice-caret","aria-hidden":"true",children:s?"▾":"▸"})]}),s?o.jsxs("div",{className:"bg-notice-body",children:[o.jsx("div",{className:"bg-notice-label",children:"命令"}),o.jsx("pre",{className:"bg-notice-pre",children:t.command||"(未报告)"}),o.jsxs("div",{className:"bg-notice-label",children:[t.kind==="watch"?"命中行":"输出",t.output?"":"(空)"]}),t.output?o.jsx("pre",{className:"bg-notice-pre",children:t.output}):null]}):null]}):o.jsx(o.Fragment,{children:e})}function c5({d:e,base:t}){const[s,n]=_.useState(!1),i=e.tasks.filter(r=>!r.ok).length;return o.jsxs("div",{className:`bg-notice deleg-notice ${s?"open":""}`,"data-ok":i?"fail":"ok",children:[o.jsxs("button",{type:"button",className:"bg-notice-head","aria-expanded":s,onClick:()=>n(!s),children:[o.jsx("span",{className:"bg-notice-dot","aria-hidden":"true"}),o.jsx("span",{className:"bg-notice-title",children:"子代理回来了"}),o.jsx("code",{className:"bg-notice-cmd",title:e.tasks.map(r=>r.goal).join(`
|
|
127
127
|
`),children:MP(e)}),o.jsx("span",{className:"bg-notice-caret","aria-hidden":"true",children:s?"▾":"▸"})]}),s?o.jsxs("div",{className:"bg-notice-body",children:[e.dispatched?o.jsxs("div",{className:"bg-notice-label",children:["派发于 ",e.dispatched,e.role?` · ${e.role}`:"",e.total?` · 合计 ${e.total}`:""," · ",e.id]}):null,e.tasks.map(r=>o.jsxs("div",{className:"deleg-task","data-ok":r.ok?"ok":"fail",children:[o.jsxs("div",{className:"deleg-task-head",children:[o.jsx("span",{className:"deleg-mark","aria-hidden":"true",children:r.ok?"✓":"✗"}),o.jsx("span",{className:"deleg-goal",children:r.goal||`任务 ${r.index}`}),o.jsxs("span",{className:"deleg-meta",children:[r.status,r.meta?` · ${r.meta}`:""]})]}),r.body?o.jsx("div",{className:"deleg-body",children:o.jsx(aS,{text:r.body,base:t})}):null]},r.index))]}):null]})}function u5({text:e,base:t}){const s=DP(e);return s?o.jsx(c5,{d:s,base:t}):o.jsx(l5,{text:e})}function h5({m:e,sid:t,backend:s,last:n,busy:i,live:r,base:a}){switch(e.kind){case"user":return o.jsxs("div",{className:`msg user${e.from?" from-agent":""}`,children:[o.jsx("div",{className:"role",title:e.from?`会话 ${e.from.id}`:void 0,children:e.from?`来自「${e.from.title}」`:"YOU"}),o.jsxs("div",{className:"bubble",children:[e.files.length>0?o.jsx("div",{className:"bubble-files",children:e.files.map((l,c)=>o.jsxs("span",{className:"bubble-file",title:l.name,children:[l.kind==="image"?o.jsx(yE,{size:12}):o.jsx(Jn,{size:12}),l.name]},`${l.name}-${c}`))}):null,o.jsx(u5,{text:e.text,base:a}),o.jsxs("div",{className:"bubble-actions",children:[e.at?o.jsx("span",{className:"msg-at",title:Fr(e.at),children:Gf(e.at)}):null,o.jsx(Lu,{text:e.text,what:"这条消息"})]})]})]});case"agent":return o.jsxs("div",{className:"msg agent",children:[o.jsxs("div",{className:"role with-mark",children:[o.jsx(VP,{backend:s}),ah(s).label||"AGENT"]}),o.jsxs("div",{className:"bubble",children:[o.jsx(aS,{text:e.text,base:a}),o.jsxs("div",{className:"bubble-actions",children:[e.at?o.jsx("span",{className:"msg-at",title:Fr(e.at),children:Gf(e.at)}):null,o.jsx(Lu,{text:e.text,what:"这条回复"}),o.jsx(S5,{id:e.key,text:e.text,sid:t}),n&&!i?o.jsx(KP,{sid:t,busy:i}):null]}),o.jsx(k5,{mkey:e.key})]})]});case"thought":return e.text.trim()?o.jsx(v1,{m:e,live:!!r}):null;case"approval":return o.jsx(v5,{m:e,sid:t});case"project-skills":return o.jsx(y5,{m:e,sid:t});case"tool":return o.jsx(y1,{m:e});case"plan":return o.jsx(a5,{m:e,busy:i});case"meta":return o.jsx("div",{className:"msg meta",children:o.jsx("div",{className:"bubble",children:e.text})});default:return null}}function d5({v:e}){const[t,s]=_.useState(!1),n=_.useRef(null),i=e.plan;if(_.useLayoutEffect(()=>{t&&p1(n.current)},[t,i]),!i||!i.items.length)return null;const r=i.items.length,a=i.items.filter(h=>h.status==="completed").length,l=a===r,c=i.terminal==="interrupted"?"已打断":i.terminal==="failed"?"运行出错":i.terminal==="ended"?"回合结束":l?"已完成":e.busy?"进行中":"待命中",u=i.terminal?"terminal":l?"done":e.busy?"running":"";return o.jsxs("div",{className:`plan-bar ${l&&!i.terminal?"completed":""}`,children:[o.jsxs("button",{type:"button",className:"plan-head",onClick:()=>s(h=>!h),"aria-expanded":t,title:"任务计划 · 点击展开/折叠",children:[o.jsx("span",{className:"plan-title",children:"任务计划"}),o.jsx("span",{className:"plan-dots","aria-hidden":"true",children:i.items.map((h,d)=>o.jsx("span",{className:`dot ${h.status}`},d))}),o.jsxs("span",{className:"plan-count",children:[a,"/",r]}),o.jsx("span",{className:`plan-state ${u}`,children:c}),o.jsx(en,{size:11,className:`tool-chev ${t?"open":""}`})]}),t?o.jsxs("ol",{className:"plan-body",ref:n,children:[i.title?o.jsx("li",{className:"plan-name","aria-label":"计划名",children:i.title}):null,i.items.map((h,d)=>o.jsxs("li",{className:`plan-step ${h.status}`,children:[o.jsx("span",{className:"step-icon","aria-hidden":"true",children:h.status==="completed"?"✓":h.status==="in_progress"?"◉":h.status==="cancelled"?"✕":"○"}),o.jsx("span",{className:"step-title",children:h.content})]},d))]}):null,t&&i.explanation?o.jsx("p",{className:"plan-explanation",children:i.explanation}):null]})}function f5({m:e,busy:t}){const[s,n]=_.useState(!1),i=_.useRef(null);_.useLayoutEffect(()=>{s&&p1(i.current)},[s,e]);const r=e.items.length;if(!r)return null;const a=e.items.filter(h=>h.status==="completed").length,l=a===r,c=e.terminal==="interrupted"?"已打断":e.terminal==="failed"?"运行出错":e.terminal==="ended"?"回合结束":l?"已完成":t?"进行中":"",u=e.terminal?"terminal":l?"done":t?"running":"";return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:`plan-card ${l&&!e.terminal?"completed":""}`,children:[o.jsxs("button",{type:"button",className:"plan-head",onClick:()=>n(h=>!h),"aria-expanded":s,title:"任务计划 · click to collapse/expand",children:[o.jsx("span",{className:"plan-title",children:"任务计划"}),o.jsx("span",{className:"plan-dots","aria-hidden":"true",children:e.items.map((h,d)=>o.jsx("span",{className:`dot ${h.status}`},d))}),o.jsxs("span",{className:"plan-count",children:[a,"/",r]}),c?o.jsx("span",{className:`plan-state ${u}`,children:c}):null,o.jsx(en,{size:11,className:`tool-chev ${s?"open":""}`})]}),s?o.jsxs("ol",{className:"plan-body",ref:i,children:[e.title?o.jsx("li",{className:"plan-name","aria-label":"计划名",children:e.title}):null,e.items.map((h,d)=>o.jsxs("li",{className:`plan-step ${h.status}`,children:[o.jsx("span",{className:"step-icon","aria-hidden":"true",children:h.status==="completed"?"✓":h.status==="in_progress"?"◉":h.status==="cancelled"?"✕":"○"}),o.jsx("span",{className:"step-title",children:h.content})]},d))]}):null,s&&e.explanation?o.jsx("p",{className:"plan-explanation",children:e.explanation}):null]})})}function p5({m:e}){const[t,s]=_.useState(!1),n=!!(e.input||e.detail),i=Op(e.status);return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:`tool-card ${e.status}`,children:[o.jsxs("button",{type:"button",className:"tool-head",onClick:()=>n&&s(r=>!r),title:n?`${e.title}
|
|
128
128
|
click for the full call and its result`:e.title,"aria-expanded":n?t:void 0,children:[o.jsx("span",{className:`tool-dot ${i}`,"aria-hidden":"true"}),o.jsx("span",{className:"tool-title",children:e.title}),e.at?o.jsx("span",{className:"msg-at",title:Fr(e.at),children:mi(e.at)}):null,n?o.jsx(en,{size:11,className:`tool-chev ${t?"open":""}`}):null]}),t&&o.jsxs("div",{className:"tool-body",children:[o.jsx("div",{className:"lbl",children:"tool"}),o.jsx("pre",{className:"tool-meta",children:e.title}),o.jsx("div",{className:"lbl",children:"kind · status"}),o.jsxs("pre",{className:"tool-meta",children:[e.kind2?`${e.kind2} · `:"",e.status]}),e.input?o.jsxs(o.Fragment,{children:[o.jsx("div",{className:"lbl",children:"input"}),o.jsx("pre",{children:e.input})]}):null,e.detail?o.jsxs(o.Fragment,{children:[o.jsx("div",{className:"lbl",children:"output"}),o.jsx("pre",{children:e.detail})]}):null]})]})})}function Op(e){const t=String(e||"").toLowerCase();return t==="completed"||t==="success"?"ok":t==="failed"||t==="error"||t==="cancelled"?"err":t==="in_progress"||t==="running"||t==="pending"?"running":"idle"}function m5({m:e,live:t}){const[s,n]=_.useState(null),i=s??t,r=_.useRef(null),[a,l]=_.useState(!0),c=24;_.useEffect(()=>{const h=r.current;if(!h||!t)return;let d=h.scrollTop;const p=()=>h.scrollHeight-h.scrollTop-h.clientHeight<=c,f=()=>{const b=h.scrollTop,w=b-d;if(d=b,w<-2){l(!1);return}l(p())},m=b=>{b.deltaY<0&&l(!1)};let y=0;const x=b=>{y=b.touches[0]?.clientY??0},g=b=>{(b.touches[0]?.clientY??0)>y+4&&l(!1)},v=b=>{(b.key==="PageUp"||b.key==="ArrowUp"||b.key==="Home")&&l(!1)};return h.addEventListener("scroll",f,{passive:!0}),h.addEventListener("wheel",m,{passive:!0}),h.addEventListener("touchstart",x,{passive:!0}),h.addEventListener("touchmove",g,{passive:!0}),h.addEventListener("keydown",v),()=>{h.removeEventListener("scroll",f),h.removeEventListener("wheel",m),h.removeEventListener("touchstart",x),h.removeEventListener("touchmove",g),h.removeEventListener("keydown",v)}},[t,i]),_.useEffect(()=>{if(!t||!a)return;const h=r.current;h&&(h.scrollTop=h.scrollHeight)},[e.text,t,a]);const u=()=>{l(!0);const h=r.current;h&&(h.scrollTop=h.scrollHeight)};return o.jsxs("div",{className:`msg thought${t?" live":""}`,children:[o.jsxs("button",{type:"button",className:"role thought-head","aria-expanded":i,"aria-label":`${i?"fold":"open"} the agent's thinking`,onClick:()=>n(!i),children:[o.jsx(en,{size:11,className:`thought-chev${i?" open":""}`}),"💭 ",t?"思考中…":"思考",o.jsxs("span",{className:"thought-meta",children:[e.at?`${Gf(e.at)} · `:"",e.text.length," 字"]})]}),i&&o.jsxs("div",{className:`bubble${t?" live":""}`,ref:r,children:[e.text,t?null:o.jsx("div",{className:"bubble-actions",children:o.jsx(Lu,{text:e.text,what:"这段思考"})})]}),t&&i&&!a&&o.jsxs("button",{type:"button",className:"thought-stick",onClick:u,title:"follow the newest thinking again","aria-label":"follow the newest thinking again",children:[o.jsx(Pw,{size:11})," 回到最新"]})]})}const Ad=e=>e.kind==="thought"||e.kind==="tool";function g5(e){const t=[];let s=0;for(;s<e.length;){const c=e[s];if(!Ad(c)){t.push({kind:"msg",m:c}),s++;continue}let u=s;for(;u<e.length&&Ad(e[u]);)u++;t.push({kind:"work",items:e.slice(s,u).filter(Ad),current:!1}),s=u}const n=t.map(c=>c.kind).lastIndexOf("work");let i=-1;if(t.forEach((c,u)=>{c.kind==="msg"&&c.m.kind==="user"&&(i=u)}),n>i){const c=t[n];c.kind==="work"&&(c.current=!0)}const r=[],a=c=>({kind:"msg",m:c,live:!1,tail:!1});for(const c of t){if(c.kind==="msg"){r.push(a(c.m));continue}const u=c.current?c.items.slice(-5):[],h=c.items.slice(0,c.items.length-u.length);h.length>=(c.current?1:2)?r.push({kind:"work",key:`work-${r.length}`,items:h,tail:!1}):h.forEach(d=>r.push(a(d))),u.forEach(d=>r.push(a(d)))}const l=[...r].reverse().find(c=>c.kind==="msg");l&&l.kind==="msg"&&(l.tail=!0);for(const c of r)c.kind==="msg"&&(c.m.kind==="agent"||c.m.kind==="thought")&&(c.live=!!c.m.open);return r}function _5({items:e}){const[t,s]=_.useState(!1),n=e.filter(m=>m.kind==="tool"),i=e.filter(m=>m.kind==="thought"),r=n.filter(m=>Op(m.status)==="err").length,a=n.some(m=>Op(m.status)==="running"),l=i.reduce((m,y)=>m+y.text.length,0),c=[...new Set(n.map(m=>m.title.replace(/\s+/g," ").trim()))],u=c.slice(0,2).map(m=>m.length>34?`${m.slice(0,33)}…`:m).join(" · "),h=n.length&&i.length?`${n.length} 次工具调用 · ${i.length} 段思考`:n.length?`${n.length} 次工具调用`:`${i.length} 段思考`,d=e.map(m=>m.at).filter(m=>typeof m=="number"),p=d.length?Math.min(...d):null,f=d.length?Math.max(...d):null;return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:"work-run",children:[o.jsxs("button",{type:"button",className:"work-run-head","aria-expanded":t,title:[`折叠了 ${n.length} 次工具调用、${i.length} 段思考(${l} 字)`,"点开看它们",...n.map(m=>`· ${m.title}`)].join(`
|
|
129
|
-
`),onClick:()=>s(m=>!m),children:[o.jsx(en,{size:11,className:`work-chev${t?" open":""}`}),o.jsx("span",{className:"work-run-icon","aria-hidden":"true",children:n.length?"⚙":"💭"}),o.jsx("span",{className:"work-run-count",children:h}),c.length?o.jsx("span",{className:"work-run-names",children:c.length>2?`${u} +${c.length-2}`:u}):o.jsxs("span",{className:"work-run-chars",children:[l," 字"]}),o.jsx("span",{className:`work-run-state ${r?"err":a?"run":"ok"}`,"aria-hidden":"true",children:r?`✗ ${r}`:a?"•••":"✓"}),p?o.jsxs("span",{className:"msg-at",title:`${Fr(p)}${f&&f!==p?` → ${Fr(f)}`:""}`,children:[mi(p),f&&f-p>=6e4?`–${mi(f)}`:""]}):null]}),t&&o.jsx("div",{className:"work-run-items",children:e.map(m=>m.kind==="thought"?o.jsx(v1,{m,live:!1},m.key):o.jsx(y1,{m},m.key))})]})})}function b1({sid:e,req:t}){return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:"perm-card",children:[o.jsxs("div",{className:"q",children:["🔑 agent 要执行:",o.jsx("b",{children:t.toolCallTitle}),"(",t.kind,")"]}),o.jsx(fg,{req:t}),o.jsx("div",{className:"opts",children:o.jsx(w1,{sid:e,req:t})})]})})}function v5({m:e,sid:t}){const s=_.useSyncExternalStore(X.subscribe,X.getSnapshot),n=s.active?.info.id===t&&!!s.active?.perms.some(r=>r.requestId===e.requestId),i={requestId:e.requestId,sessionId:t,toolCallTitle:e.title,kind:e.kind2,options:e.options,createdAt:e.at??Date.now(),path:e.path,diff:e.diff};return e.decision?o.jsx(uy,{m:e}):n||!s.active?o.jsx(b1,{sid:t,req:i}):o.jsx(uy,{m:e,lapsed:!0})}function uy({m:e,lapsed:t}){const s=e.decision&&e.decision.outcome==="selected"?e.decision.optionId:null,n=e.options.find(a=>a.optionId===s),i=t?"已作废(服务端不再等这个请求了)":e.decision?.outcome==="selected"?`已答:${n?.name??"已选"}`:"已取消",r=t||e.decision?.outcome!=="selected"?"no":"yes";return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:`perm-card done ${r}`,children:[o.jsxs("div",{className:"q",children:["🔑 agent 曾要执行:",o.jsx("b",{children:e.title}),"(",e.kind2,")"]}),o.jsx(fg,{req:{requestId:e.requestId,sessionId:"",toolCallTitle:e.title,kind:e.kind2,options:e.options,createdAt:e.at??0,path:e.path,diff:e.diff}}),o.jsx("div",{className:"perm-decision",children:i})]})})}function y5({m:e,sid:t}){const s=e.state==="trusted"||e.state==="ignore",n=i=>{X.send({t:"set-config",sessionId:t,configId:"project_skills",value:i})};return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:`perm-card skills ${s?"done":""} ${e.state==="trusted"?"yes":e.state==="ignore"?"no":""}`,children:[o.jsxs("div",{className:"q",children:["📦 ",e.text]}),e.root?o.jsxs("div",{className:"perm-file",title:e.root,children:[o.jsx(Jn,{size:12}),o.jsx("code",{children:e.root})]}):null,s?o.jsx("div",{className:"perm-decision",children:e.state==="trusted"?"已信任:这个仓库的 skill 会随会话加载":"已忽略:不再问,也不加载"}):o.jsxs("div",{className:"opts",children:[o.jsxs("button",{className:"opt primary",onClick:()=>n("trusted"),children:["信任这个仓库(",e.count," 个 skill)"]}),o.jsx("button",{className:"opt",onClick:()=>n("ignore"),children:"这个仓库不用问"})]})]})})}function fg({req:e}){if(e.diff)return o.jsx(b5,{diff:e.diff});const t=e.path??null;return t?o.jsxs("div",{className:"perm-file",title:t,children:[o.jsx(Jn,{size:12}),o.jsx("code",{children:t})]}):null}function w1({sid:e,req:t,onAnswered:s}){const n=(a,l,c)=>{const u=X.permAnswer(t.requestId);if(u&&!u.lapsed)return;const h=X.send({t:"respond-permission",sessionId:e,requestId:t.requestId,decision:a,...c?{optionKind:c.kind,signature:`${t.kind}:${t.toolCallTitle}`}:{}});X.markPermAnswered(t.requestId,l,h),s?.(l)},i=X.permAnswer(t.requestId),[,r]=_.useState(0);return _.useEffect(()=>{if(!i||i.lapsed)return;const a=window.setInterval(()=>r(l=>l+1),1e3);return()=>window.clearInterval(a)},[i?.lapsed,t.requestId]),i&&!i.lapsed?o.jsxs("div",{className:"perm-answered",role:"status","aria-live":"polite",children:[o.jsx("span",{className:"perm-answered-tick","aria-hidden":"true",children:"✓"}),o.jsxs("span",{children:["已提交「",i.label,"」—— 正在等 agent 那边回应"]})]}):o.jsxs(o.Fragment,{children:[i?.lapsed&&o.jsxs("div",{className:"perm-unconfirmed",role:"status","aria-live":"polite",children:["还没收到 agent 那边的确认(等了 ",Math.max(1,Math.round((Date.now()-i.at)/1e3))," 秒) —— 可能是这一次答复没送出去,可以再点一次。"]}),t.options.map(a=>o.jsx("button",{className:a.kind.startsWith("allow")?"allow":"reject",onClick:()=>n({outcome:"selected",optionId:a.optionId},a.name,a),children:a.name},a.optionId)),o.jsx("button",{title:"不选任何一项:agent 会收到 cancelled,这一轮就停在这里",onClick:()=>n({outcome:"cancelled"},"取消这次请求"),children:"取消这次请求"})]})}function x1({lines:e}){return o.jsx("div",{className:"perm-diff",role:"region","aria-label":"变更内容",children:e.map((t,s)=>t.kind==="gap"?o.jsx("div",{className:"perm-diff-gap",children:t.text},s):o.jsxs("div",{className:`perm-diff-line ${t.kind}`,children:[o.jsx("span",{className:"no",children:t.oldNo??""}),o.jsx("span",{className:"no",children:t.newNo??""}),o.jsx("span",{className:"sig",children:t.kind==="add"?"+":t.kind==="del"?"−":" "}),o.jsx("span",{className:"txt",children:t.text||" "})]},s))})}function b5({diff:e}){const[t,s]=_.useState(!1),n=e.oldText??"",i=e.newText??"",r=i.length>0&&n.length===0,a=Om(n,i),l=a.filter(u=>u.kind==="add").length,c=a.filter(u=>u.kind==="del").length;return o.jsxs("div",{className:"perm-changes",children:[o.jsxs("button",{type:"button",className:"perm-change-row","aria-expanded":t,"aria-label":`${t?"收起":"查看"} ${e.path??"这份文件"} 的变更`,onClick:()=>s(u=>!u),children:[o.jsx(Jn,{size:13}),o.jsx("code",{title:e.path??"",children:e.path??"(未命名文件)"}),o.jsx("span",{className:"perm-counts",children:r?o.jsxs("span",{className:"add",children:["新文件 · ",l," 行"]}):o.jsxs(o.Fragment,{children:[o.jsxs("span",{className:"add",children:["+",l]}),o.jsxs("span",{className:"del",children:["−",c]})]})}),o.jsx("span",{className:"perm-caret","aria-hidden":"true",children:t?"▾":"▸"})]}),t?o.jsx(x1,{lines:a}):null,e.truncated?o.jsx("div",{className:"perm-cut",children:"agent 发来的是整份文件,这里只保留了改动附近的部分"}):null]})}function hy({f:e}){const[t,s]=_.useState(!1),n=e.oldText.length===0&&e.newText.length>0,i=n||e.oldText.length>0||e.newText.length>0,r=_.useMemo(()=>i?Om(e.oldText,e.newText):[],[i,e.oldText,e.newText]),a=e.path===e.name?"":e.path.slice(0,e.path.length-e.name.length).replace(/[\\/]+$/,"");return o.jsxs("div",{className:"fc-row",children:[o.jsxs("div",{className:"fc-line",children:[o.jsx("span",{className:"fc-dot","aria-hidden":"true"}),o.jsxs("button",{type:"button",className:"fc-name",title:`在右侧面板打开 ${e.path}`,onClick:()=>sx({path:e.path}),children:[e.name,a?o.jsx("span",{className:"fc-dir",children:a}):null,e.edits>1?o.jsxs("span",{className:"fc-edits",children:["改了 ",e.edits," 次"]}):null]}),o.jsx("button",{type:"button",className:"fc-counts","aria-expanded":t,"aria-label":`${t?"收起":"查看"} ${e.path} 的变更`,disabled:!i,onClick:()=>s(l=>!l),children:n?o.jsxs("span",{className:"add",children:["新文件 · ",e.insertions," 行"]}):o.jsxs(o.Fragment,{children:[o.jsxs("span",{className:"add",children:["+",e.insertions]}),o.jsxs("span",{className:"del",children:["−",e.deletions]})]})})]}),t&&i?o.jsx(x1,{lines:r}):null]})}function dy({msgs:e}){const t=_.useMemo(()=>{const a=[];for(const l of e)l.kind==="tool"&&l.changes?.length&&a.push(...l.changes);return PE(a)},[e]),[s,n]=_.useState(!0);if(!t.length)return null;if(t.length===1)return o.jsx("div",{className:"file-changes one",children:o.jsx(hy,{f:t[0]})});const i=t.reduce((a,l)=>a+l.insertions,0),r=t.reduce((a,l)=>a+l.deletions,0);return o.jsxs("div",{className:"file-changes",children:[o.jsxs("button",{type:"button",className:"fc-head","aria-expanded":s,"aria-label":`${s?"收起":"展开"} ${t.length} 个文件变更`,onClick:()=>n(a=>!a),children:[o.jsx(Jn,{size:13}),o.jsxs("span",{className:"fc-title",children:[t.length," 个文件变更"]}),o.jsxs("span",{className:"fc-counts static",children:[o.jsxs("span",{className:"add",children:["+",i]}),o.jsxs("span",{className:"del",children:["−",r]})]}),o.jsx("span",{className:"perm-caret","aria-hidden":"true",children:s?"▾":"▸"})]}),s?t.map(a=>o.jsx(hy,{f:a},a.path)):null]})}function w5({req:e,sessionTitle:t,waiting:s,onSkip:n}){Wo(!0,n);const[i,r]=_.useState(()=>Date.now());_.useEffect(()=>{const u=window.setInterval(()=>r(Date.now()),1e3);return()=>window.clearInterval(u)},[e.requestId]);const a=Math.max(0,Math.round((i-e.createdAt)/1e3)),l=X.permAnswer(e.requestId),c=Math.max(0,s-1);return o.jsx("div",{className:"modal-bg perm-bg",onClick:n,children:o.jsxs("div",{className:"modal perm-dialog",role:"dialog","aria-modal":"true","aria-label":"agent 请求授权","data-request-id":e.requestId,"data-session-id":e.sessionId,"data-waiting":s,onClick:u=>u.stopPropagation(),children:[o.jsx("h3",{children:"Agent 请求授权"}),o.jsxs("div",{className:"perm-ask",children:["「",t,"」里的 agent 停在这里等你答复 —— 它要执行 ",o.jsx("b",{children:e.toolCallTitle}),"(",e.kind,")。"]}),o.jsx(fg,{req:e}),o.jsx("div",{className:"opts perm-opts",children:o.jsx(w1,{sid:e.sessionId,req:e})}),c>0&&o.jsxs("div",{className:"perm-queue",role:"note",children:["这个会话还有 ",o.jsx("b",{children:c})," 个请求等着答复 —— 答完这个,下一个会接着显示在这里。"]}),o.jsxs("div",{className:"perm-note",children:["已等待 ",a," 秒。一直不答复的话,agent 那边会自己放弃这次请求(等同拒绝),这一轮就停在这里。"]}),!l&&o.jsx("div",{className:"row",children:o.jsx("button",{className:"cancel",onClick:n,children:"稍后处理"})})]})})}function Dd(e){if(e<=0)return"";if(e%60===0){const t=e/60;return t<60?`${t} 分钟`:`${Math.round(t/60)} 小时`}return`${e} 秒`}function x5(){const[e,t]=_.useState(null);_.useEffect(()=>{let n=!0;return fetch("/api/settings",{credentials:"same-origin"}).then(i=>i.ok?i.json():null).then(i=>{n&&t(Number(i?.observer?.intervalSec??0))}).catch(()=>{n&&t(0)}),()=>{n=!1}},[]);const s=_.useCallback(n=>{t(n),fetch("/api/settings",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify({observer:{intervalSec:n}})}).catch(()=>{})},[]);return[e??0,s]}function S5({id:e,text:t,sid:s}){const[n]=lr(),i=Bm(),[r,a]=_.useState(!1),[l,c]=_.useState(!1),[u,h]=_.useState(null),d=_.useRef(null);Br(r,[d],()=>a(!1));const p=_.useRef({timer:null,fired:!1}),f=()=>{p.current.timer&&(window.clearTimeout(p.current.timer),p.current.timer=null)};_.useEffect(()=>f,[]);const m=()=>{p.current.fired=!1,f(),p.current.timer=window.setTimeout(()=>{p.current.fired=!0,a(!0)},500)};if(!t.trim())return null;const y=i.speaking&&i.speakingId===e;if(typeof window<"u"&&!("speechSynthesis"in window)&&!n.serverTts)return o.jsx("span",{className:"bubble-note",title:"this browser has no speech synthesis",children:"no voices"});const x=async g=>{if(l)return;const v=PP(m1(e,g));if(v){a(!1),Mt.speak(v.text,`${e}#summary:${g??"cfg"}`,n);return}c(!0),h(null);try{const b=await FP(s,e,g);a(!1),Mt.speak(b.text,`${e}#summary:${g??"cfg"}`,n)}catch(b){const w=b;h({msg:w?.message??String(b),hint:w?.hint}),a(!1)}finally{c(!1)}};return o.jsxs(o.Fragment,{children:[o.jsxs("span",{className:"speak-wrap bubble-speak",ref:d,children:[o.jsx("button",{className:`bubble-btn speak ${y?"on":""} ${l?"working":""}`,title:l?"正在生成语音播报总结…":y?"stop reading(长按:语音播报总结)":"read this reply aloud(长按:语音播报总结)","aria-label":y?"stop reading":"read aloud","aria-haspopup":"menu","aria-expanded":r,onClick:()=>{if(p.current.fired){p.current.fired=!1;return}y?Mt.stop():Mt.speak(t,e,n)},onPointerDown:m,onPointerUp:f,onPointerLeave:f,onPointerCancel:f,onContextMenu:g=>{g.preventDefault(),f(),a(!0)},onKeyDown:g=>{(g.key==="F10"&&g.shiftKey||g.key==="ContextMenu")&&(g.preventDefault(),a(!0))},children:l?o.jsx(Po,{size:13,className:"spin"}):y?o.jsx(Lw,{size:13}):o.jsx(th,{size:13})}),r?o.jsxs("div",{className:"speak-menu bubble-menu",role:"menu",children:[o.jsxs("button",{type:"button",role:"menuitem",className:"speak-menu-item","data-speak-summary":"verbatim",onClick:()=>{a(!1),Mt.speak(t,e,n)},children:[o.jsx("span",{className:"speak-check",children:"›"}),o.jsx("span",{className:"speak-name",children:"读整条"})]}),[100,150,200].map(g=>o.jsxs("button",{type:"button",role:"menuitem",className:"speak-menu-item",disabled:l,"data-speak-summary":String(g),onClick:()=>void x(g),children:[o.jsx("span",{className:"speak-check",children:l?"•":"›"}),o.jsx("span",{className:"speak-name",children:l?"总结中…":`语音播报总结 · 约 ${g} 字`})]},g)),o.jsxs("button",{type:"button",role:"menuitem",className:"speak-menu-item",disabled:l,"data-speak-summary":"cfg",onClick:()=>void x(),children:[o.jsx("span",{className:"speak-check",children:"›"}),o.jsx("span",{className:"speak-name",children:l?"总结中…":"语音播报总结 · 按设置"})]}),o.jsx("p",{className:"speak-hint",children:"把这条压成一段能听完的话;字数写进提示词交给模型(提示词在 设置 → 语音总结)"})]}):null]}),u?o.jsxs("span",{className:"bubble-note err",role:"status",children:[u.msg,u.hint?` · ${u.hint}`:""]}):null]})}function k5({mkey:e}){const t=_.useSyncExternalStore(IP,ay,ay),[s,n]=_.useState(!1),i=OP(e);if(!i)return null;const r=i.route==="session"?`${i.provider??""}${i.provider?" · ":""}${i.model??""}`:i.model?`语音端点 · ${i.model}`:"",a=i.maxChars?` · 按 ${i.maxChars} 字压`:"",l=i.via==="verbatim"?"原文本身就够短,直接念":`${i.chars} 字${a} · ${(i.ms/1e3).toFixed(1)}s${r?` · ${r}`:""}`;return o.jsxs("div",{className:`bubble-note speech-note${s?" open":""}`,"data-summary-chars":i.chars,children:[o.jsx("button",{type:"button",className:"speech-note-tag","aria-expanded":s,onClick:()=>n(c=>!c),children:"播报稿"}),o.jsx("span",{className:"speech-note-text",onClick:()=>n(c=>!c),title:"点击展开/收起",children:i.text}),o.jsx("span",{className:"speech-note-meta",title:i.routeNote??void 0,children:l}),o.jsx("button",{type:"button",className:"speech-note-x",title:"丢掉这份稿子(下次长按会重新生成)","aria-label":"drop this summary",onClick:()=>BP(e),children:o.jsx(wn,{size:11})}),o.jsx("span",{hidden:!0,children:t})]})}const pg=["image/png","image/jpeg","image/webp","image/gif"],C5=4*1024*1024,E5=256*1024;function mg(){const e=_.useRef(!1);return{handlers:{onCompositionStart:()=>{e.current=!0},onCompositionEnd:()=>{e.current=!1}},isComposing:t=>e.current||t.nativeEvent.isComposing===!0}}function S1(e){return pg.includes(e.type)?e.size>C5?Promise.resolve({error:`${e.name}: image larger than 4MB`}):new Promise(s=>{const n=new FileReader;n.onload=()=>{const i=String(n.result??"");s({id:`${e.name}-${e.size}-${Math.random().toString(36).slice(2,7)}`,name:e.name,kind:"image",mimeType:e.type,preview:i,payload:i.slice(i.indexOf(",")+1),bytes:e.size})},n.onerror=()=>s({error:`${e.name}: could not be read`}),n.readAsDataURL(e)}):e.size>E5?Promise.resolve({error:`${e.name}: larger than 256kB — attach it as a path instead`}):new Promise(s=>{const n=new FileReader;n.onload=()=>s({id:`${e.name}-${e.size}-${Math.random().toString(36).slice(2,7)}`,name:e.name,kind:"text",mimeType:e.type||"text/plain",payload:String(n.result??""),bytes:e.size}),n.onerror=()=>s({error:`${e.name}: could not be read`}),n.readAsText(e)})}function k1(e){if(!e)return[];const t=Array.from(e.files??[]);for(const s of Array.from(e.items??[])){if(s.kind!=="file")continue;const n=s.getAsFile();n&&!t.some(i=>i.name===n.name&&i.size===n.size&&i.type===n.type)&&t.push(n)}return t}function C1(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(0)} kB`:`${(e/1048576).toFixed(1)} MB`}const ir=["#7f8c98","#5fb3a1","#7fb069","#d9a441","#e8843c","#f0603f","#ff4d4d"];function E1(e,t){const s=Math.max(1,t.length),n=t.findIndex(a=>String(a.value)===String(e)),i=n<0?0:n+1;return{color:n<0?"var(--text-dim)":ir[Math.min(n,ir.length-1)],level:i,total:s}}function N1({level:e,total:t,color:s}){const n=Math.min(7,t),i=Math.max(0,Math.min(n,Math.round(e/t*n)));return o.jsx("span",{className:"tb-pips","aria-hidden":"true",children:Array.from({length:n}).map((r,a)=>o.jsx("i",{style:{background:a<i?s:"var(--line)"}},a))})}function Cl(e,t){const s=t==="effort"?["thought_level","reasoning"]:["model","model_config"],n=t==="effort"?/reason|effort|think|depth/i:/model/i;return e.find(i=>i.type==="select"&&i.category&&s.includes(String(i.category)))??e.find(i=>i.type==="select"&&n.test(i.id))}function R1({label:e,title:t,icon:s,value:n,children:i,open:r,onToggle:a,testId:l}){const c=_.useRef(null);return Br(r,[c],a),o.jsxs("div",{className:"tb-wrap",ref:c,children:[o.jsxs("button",{type:"button",className:`tb-btn ${r?"on":""}`,title:t,"aria-label":t,"aria-expanded":r,"data-testid":l,onClick:a,children:[s,o.jsx("span",{className:"tb-label",children:n||e}),o.jsx(Io,{size:11,className:"tb-chev"})]}),r?i:null]})}function Bu({items:e,current:t,onPick:s,empty:n}){const i=Nw();return e.length?o.jsx("div",{className:"tb-list",role:"listbox",ref:i,children:e.map(r=>o.jsxs("button",{role:"option","aria-selected":r.value===t,className:`tb-opt ${r.value===t?"sel":""}`,title:r.hint?`${r.name} — ${r.hint}`:r.name,onClick:()=>s(r.value),children:[o.jsxs("span",{className:"tb-opt-name",children:[r.color?o.jsx("i",{className:"tb-dot",style:{background:r.color}}):null,r.name]}),r.hint?o.jsx("span",{className:"tb-opt-hint",children:r.hint}):null]},r.value))}):o.jsx("div",{className:"tb-list",ref:i,children:o.jsx("div",{className:"tb-empty",children:n})})}function j1(e){return e.category==="_context_window"?!0:/budget|context/i.test(`${e.id} ${e.name??""}`)}function N5({v:e}){const t=e.info.usage,s=e.info.configOptions.find(j1),[n,i]=_.useState(!1),r=_.useRef(null),[a,l]=_.useState(!1),[c,u]=_.useState(""),[h,d]=_.useState(!0),[p,f]=_.useState(""),[m,y]=_.useState(""),x=mg(),g=e.trace;if(Br(n,[r],()=>{i(!1),l(!1)}),!t||!t.used&&!t.size)return null;const v=e.info.contextLimit&&e.info.contextLimit>0?e.info.contextLimit:null,b=e.info.modelContextLimit&&e.info.modelContextLimit>0?e.info.modelContextLimit:null,w=v?"session":b?"model":"agent",k=v??b??t.size,j=k>0?Math.min(100,Math.round(t.used/k*100)):0,I=j>=85?"hot":j>=65?"warn":"ok",A=k>0?Math.max(0,k-t.used):0,D=e.info.commands??[],O=T=>D.some($=>$.name===T),F=w==="session"?"你为本会话声明":w==="model"?"你为这个模型记下的":"agent 上报(usage_update)",C=async(T,$={})=>{f($.forgetModel?"forget":"save"),y("");try{await X.setContextLimit(e.info.id,T,$),l(!1)}catch(E){y(String(E?.message??E))}finally{f("")}},N=T=>{if(e.info.cold){i(!1),X.resume(e.info.id);return}X.send({t:"prompt",sessionId:e.info.id,text:`/${T}`}),i(!1)},P=(T,$)=>{const E=$.trim();E&&(X.send({t:"set-config",sessionId:e.info.id,configId:T,value:E}),u(""))},B=String(s?.currentValue??"");return o.jsxs("div",{className:`usage-row ${I}`,ref:r,children:[o.jsxs("button",{className:"usage-text",onClick:()=>i(T=>!T),title:"上下文窗口 — 点这里改",children:[o.jsx(E_,{size:12,className:"usage-icon"}),k>0?`${xa(t.used)} / ${xa(k)}`:`${xa(t.used)} / —`,k>0?` · ${j}%`:"",w==="session"?" · 声明":w==="model"?" · 模型记录":""]}),k>0?o.jsx("div",{className:"usage-bar",title:`${t.used} / ${k} tokens (${j}%)`,children:o.jsx("i",{style:{width:`${j}%`}})}):null,I==="hot"&&O("compress")&&!e.busy?o.jsxs("button",{className:"usage-act",onClick:()=>N("compress"),title:"发送 /compress:让 agent 压缩上下文(这是它自己公告的命令)",children:[o.jsx(Im,{size:11})," 压缩上下文"]}):null,n?o.jsxs("div",{className:"usage-detail",children:[o.jsxs("div",{className:"usage-set",children:[o.jsxs("div",{className:"usage-set-head",children:[o.jsx(E_,{size:12})," 上下文窗口",o.jsx("span",{className:"usage-set-scope",children:s?String(s.meta?.scope??"")==="model"?"按模型":"":"仅声明"})]}),s?o.jsxs(o.Fragment,{children:[o.jsx("div",{className:"usage-set-chips",children:(s.options??[]).map(T=>o.jsx("button",{className:`usage-chip ${B===String(T.value)?"sel":""}`,onClick:()=>P(s.id,String(T.value)),children:String(T.value)==="auto"?"自动":T.name},String(T.value)))}),o.jsxs("div",{className:"usage-edit",children:[o.jsx("input",{value:c,inputMode:"numeric","aria-label":"context window in tokens",placeholder:s.meta?.freeform===!0?"任意 token 数,如 300000":"填一个数",onChange:T=>u(T.target.value),onKeyDown:T=>{x.isComposing(T)||(T.key==="Enter"&&P(s.id,c),T.key==="Escape"&&(T.stopPropagation(),i(!1)))}}),o.jsx("button",{className:"usage-edit-btn",disabled:!c.trim(),onClick:()=>P(s.id,c),children:"set"})]}),o.jsx("div",{className:"settings-note",children:"常用:256k / 512k / 768k / 1m;填 auto 回到模型自己的窗口。"}),o.jsxs("div",{className:"usage-note",children:["改的是",o.jsx("b",{children:"这个模型"}),":同模型的所有会话(含新开的、别的槽位)都用同一个上限。它只会让 Hermes 更早压缩,不会把窗口撑过模型本身。"]})]}):o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"usage-note",children:["这个后端没公告上下文旋钮,所以下面这个数只是仪表盘的",o.jsx("b",{children:"声明"}),",只影响百分比;真减上下文用压缩命令或换模型。"]}),a?o.jsxs("div",{className:"usage-edit",children:[o.jsx("input",{autoFocus:!0,value:c,inputMode:"numeric","aria-label":"context window in tokens",placeholder:String(t.size||e.info.contextLimit||2e5),onChange:T=>u(T.target.value),...x.handlers,onKeyDown:T=>{if(!x.isComposing(T)){if(T.key==="Enter"){const $=Number(c.replace(/[^0-9]/g,""));$>0&&C($,{remember:h})}T.key==="Escape"&&(T.stopPropagation(),l(!1))}}}),o.jsx("button",{className:"usage-edit-btn",disabled:p!==""||!Number(c.replace(/[^0-9]/g,"")),onClick:()=>void C(Number(c.replace(/[^0-9]/g,"")),{remember:h}),children:p==="save"?"…":"set"}),o.jsxs("label",{className:"usage-check",title:"像 studio 那样按模型记住:下次用这个模型自动带回来",children:[o.jsx("input",{type:"checkbox",checked:h,onChange:T=>d(T.target.checked)}),"记到本模型"]}),b?o.jsx("button",{className:"usage-edit-btn",disabled:p!=="",onClick:()=>void C(null,{forgetModel:!0}),children:p==="forget"?"…":"忘掉本模型记录"}):null]}):o.jsx("button",{className:"usage-edit-btn",onClick:()=>{u(String(k||2e5)),l(!0)},children:"声明窗口长度"})]})]}),o.jsxs("div",{children:["已用 ",t.used," / ",k||"—"," tokens(",j,"%)"]}),o.jsxs("div",{children:["剩余:",k>0?A:"unknown"," tokens"]}),o.jsxs("div",{children:["窗口来源:",o.jsx("b",{children:F})]}),t.size>0&&w!=="agent"?o.jsxs("div",{children:["agent 上报:",xa(t.size)," tokens (usage_update)"]}):null,b&&w==="session"?o.jsxs("div",{children:["本模型记录:",xa(b)," tokens"]}):null,t.cost!=null?o.jsxs("div",{children:["本轮花费:$",t.cost.toFixed(6)]}):null,g?.model?o.jsxs("div",{children:["model:",g.model]}):null,g&&(g.effort||g.mode)?o.jsxs("div",{children:["本轮:",[g.effort&&`思考强度 ${g.effort}`,g.mode&&`模式 ${g.mode}`].filter(Boolean).join(",")]}):null,O("compress")||O("context")?o.jsxs("div",{className:"usage-actions",children:[O("compress")?o.jsx("button",{className:"usage-act",onClick:()=>N("compress"),title:"让 agent 压缩上下文(/compress,它自己公告的命令)",children:"压缩上下文"}):null,O("context")?o.jsx("button",{className:"usage-act",onClick:()=>N("context"),title:"看消息按角色分布(/context)",children:"消息分布"}):null]}):null,m?o.jsx("div",{className:"usage-edit-err",children:m}):null]}):null]})}function R5({o:e,sessionId:t}){const s=e.meta??{},n=s.freeform===!0,[i,r]=_.useState(""),a=String(e.currentValue??""),l=typeof s.unit=="string"?s.unit:"tokens",c=h=>X.send({t:"set-config",sessionId:t,configId:e.id,value:h}),u=mg();return o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(Al,{size:13})," ",e.name||e.id]}),e.options?.map(h=>o.jsx("button",{className:`settings-opt ${a===String(h.value)?"sel":""}`,onClick:()=>c(String(h.value)),children:h.name},String(h.value))),n?o.jsxs("div",{className:"settings-freeform",children:[o.jsx("input",{className:"settings-input",type:"number",inputMode:"numeric",min:typeof s.min=="number"?s.min:void 0,step:typeof s.step=="number"?s.step:1024,placeholder:`任意 ${l}`,"aria-label":`${e.name||e.id} value`,value:i,onChange:h=>r(h.target.value),...u.handlers,onKeyDown:h=>{u.isComposing(h)||h.key==="Enter"&&i.trim()&&c(i.trim())}}),o.jsx("button",{className:"settings-opt",disabled:!i.trim(),onClick:()=>c(i.trim()),children:"set"})]}):null]})}function j5({v:e,prefs:t,setPrefs:s,onClose:n,panelRef:i}){const r=e.info,a=r.modes?.availableModes??[],l=Cl(r.configOptions,"effort"),c=Cl(r.configOptions,"model"),h=_.useSyncExternalStore(Mt.subscribeVoices,()=>Mt.voices().length)?Mt.voices():[],d=Vn();return o.jsxs("div",{className:"settings-pop",role:"dialog","aria-label":"chat settings",ref:i,children:[o.jsxs("div",{className:"settings-head",children:[o.jsx("span",{children:"chat settings"}),o.jsx("span",{className:"head-spacer"}),o.jsx("button",{className:"icon-btn",title:"close","aria-label":"close",onClick:n,children:o.jsx(wn,{size:13})})]}),a.length>0&&o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(Mw,{size:13})," permission mode"]}),a.map(p=>o.jsx("button",{className:`settings-opt ${r.modes?.currentModeId===p.id?"sel":""}`,onClick:()=>X.send({t:"set-mode",sessionId:r.id,modeId:p.id}),children:p.name},p.id))]}),l?.options?.length?o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(wE,{size:13})," thinking depth"]}),l.options.map((p,f)=>o.jsxs("button",{className:`settings-opt ${String(l.currentValue??"")===String(p.value)?"sel":""}`,onClick:()=>X.send({t:"set-config",sessionId:r.id,configId:l.id,value:String(p.value)}),children:[o.jsx("i",{className:"settings-dot",style:{"--effort":ir[Math.min(f,ir.length-1)]}}),p.name]},String(p.value))),o.jsx("div",{className:"settings-note",children:"只列这个路由真支持的档;改的是本会话。"})]}):null,r.configOptions.filter(p=>p.type==="select"&&p.options&&p!==l&&p!==c&&!j1(p)).map(p=>o.jsx(R5,{o:p,sessionId:r.id},p.id)),o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(th,{size:13})," read replies aloud"]}),o.jsxs("label",{className:"settings-toggle",children:[o.jsx("input",{type:"checkbox",checked:t.autoRead,onChange:p=>s({autoRead:p.target.checked})}),o.jsx("span",{children:"speak every finished reply"})]}),h.length>0&&o.jsxs("select",{className:"settings-select",value:t.voiceURI,onChange:p=>s({voiceURI:p.target.value}),"aria-label":"voice",children:[o.jsxs("option",{value:"",children:["auto voice (",t.lang,")"]}),h.map(p=>o.jsxs("option",{value:p.voiceURI,children:[p.name," — ",p.lang]},p.voiceURI))]}),h.length===0?o.jsx("div",{className:"settings-note",children:"this browser exposes no voices"}):null,o.jsxs("label",{className:"settings-range",children:[o.jsxs("span",{children:["speed ",t.rate.toFixed(2),"×"]}),o.jsx("input",{type:"range",min:.5,max:2,step:.05,value:t.rate,onChange:p=>s({rate:Number(p.target.value)})})]}),d.tts.server?o.jsxs("label",{className:"settings-toggle",children:[o.jsx("input",{type:"checkbox",checked:t.serverTts,onChange:p=>s({serverTts:p.target.checked})}),o.jsxs("span",{children:["use the server voice (",d.tts.model??"configured",")"]})]}):null]}),o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(sr,{size:13})," dictation"]}),o.jsxs("select",{className:"settings-select",value:t.stt,onChange:p=>s({stt:p.target.value}),"aria-label":"dictation engine",children:[o.jsx("option",{value:"auto",children:"auto — 服务端流式 > 浏览器 > 批量"}),o.jsxs("option",{value:"stream",children:["stream",d.stt.streaming?` (${d.stt.model??"百炼"})`:" (not configured)"]}),o.jsxs("option",{value:"browser",children:["browser",Rf()?"":" (unavailable)"]}),o.jsxs("option",{value:"server",children:["server",d.stt.server?` (${d.stt.batchModel??"configured"})`:" (not configured)"]})]}),o.jsx("input",{className:"settings-input",value:t.lang,onChange:p=>s({lang:p.target.value}),placeholder:"language, e.g. zh-CN","aria-label":"speech language"}),o.jsxs("div",{className:"settings-note",children:["browser dictation ",Rf()?"available":"unavailable"," · ",d.provider," STT"," ",d.stt.streaming?"streaming":d.stt.server?"batch":"not configured"]})]})]})}const Ec=new Map;function T5({v:e,call:t,onCloseCall:s}){const[n,i]=_.useState(()=>Ec.get(e.info.id)??""),r=window.innerWidth<720?"message… (/ for commands)":"message… (Enter send, Shift+Enter newline, / for commands)",a=/Mac|iPhone|iPad/.test(navigator.platform??"")?"⌘":"Ctrl+",l=window.innerWidth<720?"message… (Enter queues)":`message… (${a}Enter interrupts · Enter queues)`,[c,u]=_.useState(0),[h,d]=_.useState(!1),p=_.useRef(null),f=_.useRef(null),m=_.useRef(null),y=_.useRef(!1),x=_.useRef(null),g=_.useRef(""),v=_.useRef(!1),b=_.useMemo(()=>e.msgs.filter(R=>R.kind==="user").map(R=>R.text).filter(R=>R.trim()),[e.msgs]),w=_.useRef(e.info.id);_.useEffect(()=>{Ec.set(w.current,n)},[n]),_.useEffect(()=>{w.current!==e.info.id&&(Ec.set(w.current,n),w.current=e.info.id,i(Ec.get(e.info.id)??""),x.current=null,g.current="",d(!1),u(0))},[e.info.id,n]);const[k,j]=_.useState([]),[I,A]=_.useState(null),[D,O]=_.useState(""),[F,C]=_.useState(!1),[N,P]=_.useState(!1),[B,T]=_.useState(null);_.useEffect(()=>{const R=Ie.current;R&&(R.style.height="42px",R.style.height=`${Math.min(R.scrollHeight,window.innerHeight*.4)}px`)},[n]);const[$,E]=_.useState(!1),[z,H]=_.useState(null),[ne,ae]=_.useState({});_.useEffect(()=>{ae({}),H(null)},[e.info.id]);const[G,q]=lr(),te=Fm(),ue=Bm(),Ie=_.useRef(null),lt=_.useRef(null),Je=async R=>{const Z=Array.from(R);if(!Z.length)return;const _e=await Promise.all(Z.map(et=>S1(et))),Pe=[],qe=[];for(const et of _e)"error"in et?qe.push(et.error):Pe.push(et);Pe.length&&j(et=>[...et,...Pe]),O(qe.join(" · "))},$e=()=>k.map(R=>R.kind==="image"?{kind:"image",mimeType:R.mimeType,data:R.payload,name:R.name}:{kind:"text",name:R.name,text:R.payload}),Ze=R=>{if(R.key!=="ArrowUp"&&R.key!=="ArrowDown"||R.shiftKey||R.altKey||R.metaKey||R.ctrlKey||!b.length)return!1;const Z=R.currentTarget,_e=Z.selectionStart??0;if(R.key==="ArrowUp"&&Z.value.slice(0,_e).includes(`
|
|
129
|
+
`),onClick:()=>s(m=>!m),children:[o.jsx(en,{size:11,className:`work-chev${t?" open":""}`}),o.jsx("span",{className:"work-run-icon","aria-hidden":"true",children:n.length?"⚙":"💭"}),o.jsx("span",{className:"work-run-count",children:h}),c.length?o.jsx("span",{className:"work-run-names",children:c.length>2?`${u} +${c.length-2}`:u}):o.jsxs("span",{className:"work-run-chars",children:[l," 字"]}),o.jsx("span",{className:`work-run-state ${r?"err":a?"run":"ok"}`,"aria-hidden":"true",children:r?`✗ ${r}`:a?"•••":"✓"}),p?o.jsxs("span",{className:"msg-at",title:`${Fr(p)}${f&&f!==p?` → ${Fr(f)}`:""}`,children:[mi(p),f&&f-p>=6e4?`–${mi(f)}`:""]}):null]}),t&&o.jsx("div",{className:"work-run-items",children:e.map(m=>m.kind==="thought"?o.jsx(v1,{m,live:!1},m.key):o.jsx(y1,{m},m.key))})]})})}function b1({sid:e,req:t}){return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:"perm-card",children:[o.jsxs("div",{className:"q",children:["🔑 agent 要执行:",o.jsx("b",{children:t.toolCallTitle}),"(",t.kind,")"]}),o.jsx(fg,{req:t}),o.jsx("div",{className:"opts",children:o.jsx(w1,{sid:e,req:t})})]})})}function v5({m:e,sid:t}){const s=_.useSyncExternalStore(X.subscribe,X.getSnapshot),n=s.active?.info.id===t&&!!s.active?.perms.some(r=>r.requestId===e.requestId),i={requestId:e.requestId,sessionId:t,toolCallTitle:e.title,kind:e.kind2,options:e.options,createdAt:e.at??Date.now(),path:e.path,diff:e.diff};return e.decision?o.jsx(uy,{m:e}):n||!s.active?o.jsx(b1,{sid:t,req:i}):o.jsx(uy,{m:e,lapsed:!0})}function uy({m:e,lapsed:t}){const s=e.decision&&e.decision.outcome==="selected"?e.decision.optionId:null,n=e.options.find(a=>a.optionId===s),i=t?"已作废(服务端不再等这个请求了)":e.decision?.outcome==="selected"?`已答:${n?.name??"已选"}`:"已取消",r=t||e.decision?.outcome!=="selected"?"no":"yes";return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:`perm-card done ${r}`,children:[o.jsxs("div",{className:"q",children:["🔑 agent 曾要执行:",o.jsx("b",{children:e.title}),"(",e.kind2,")"]}),o.jsx(fg,{req:{requestId:e.requestId,sessionId:"",toolCallTitle:e.title,kind:e.kind2,options:e.options,createdAt:e.at??0,path:e.path,diff:e.diff}}),o.jsx("div",{className:"perm-decision",children:i})]})})}function y5({m:e,sid:t}){const s=e.state==="trusted"||e.state==="ignore",n=i=>{X.send({t:"set-config",sessionId:t,configId:"project_skills",value:i})};return o.jsx("div",{className:"msg",children:o.jsxs("div",{className:`perm-card skills ${s?"done":""} ${e.state==="trusted"?"yes":e.state==="ignore"?"no":""}`,children:[o.jsxs("div",{className:"q",children:["📦 ",e.text]}),e.root?o.jsxs("div",{className:"perm-file",title:e.root,children:[o.jsx(Jn,{size:12}),o.jsx("code",{children:e.root})]}):null,s?o.jsx("div",{className:"perm-decision",children:e.state==="trusted"?"已信任:这个仓库的 skill 会随会话加载":"已忽略:不再问,也不加载"}):o.jsxs("div",{className:"opts",children:[o.jsxs("button",{className:"opt primary",onClick:()=>n("trusted"),children:["信任这个仓库(",e.count," 个 skill)"]}),o.jsx("button",{className:"opt",onClick:()=>n("ignore"),children:"这个仓库不用问"})]})]})})}function fg({req:e}){if(e.diff)return o.jsx(b5,{diff:e.diff});const t=e.path??null;return t?o.jsxs("div",{className:"perm-file",title:t,children:[o.jsx(Jn,{size:12}),o.jsx("code",{children:t})]}):null}function w1({sid:e,req:t,onAnswered:s}){const n=(a,l,c)=>{const u=X.permAnswer(t.requestId);if(u&&!u.lapsed)return;const h=X.send({t:"respond-permission",sessionId:e,requestId:t.requestId,decision:a,...c?{optionKind:c.kind,signature:`${t.kind}:${t.toolCallTitle}`}:{}});X.markPermAnswered(t.requestId,l,h),s?.(l)},i=X.permAnswer(t.requestId),[,r]=_.useState(0);return _.useEffect(()=>{if(!i||i.lapsed)return;const a=window.setInterval(()=>r(l=>l+1),1e3);return()=>window.clearInterval(a)},[i?.lapsed,t.requestId]),i&&!i.lapsed?o.jsxs("div",{className:"perm-answered",role:"status","aria-live":"polite",children:[o.jsx("span",{className:"perm-answered-tick","aria-hidden":"true",children:"✓"}),o.jsxs("span",{children:["已提交「",i.label,"」—— 正在等 agent 那边回应"]})]}):o.jsxs(o.Fragment,{children:[i?.lapsed&&o.jsxs("div",{className:"perm-unconfirmed",role:"status","aria-live":"polite",children:["还没收到 agent 那边的确认(等了 ",Math.max(1,Math.round((Date.now()-i.at)/1e3))," 秒) —— 可能是这一次答复没送出去,可以再点一次。"]}),t.options.map(a=>o.jsx("button",{className:a.kind.startsWith("allow")?"allow":"reject",onClick:()=>n({outcome:"selected",optionId:a.optionId},a.name,a),children:a.name},a.optionId)),o.jsx("button",{title:"不选任何一项:agent 会收到 cancelled,这一轮就停在这里",onClick:()=>n({outcome:"cancelled"},"取消这次请求"),children:"取消这次请求"})]})}function x1({lines:e}){return o.jsx("div",{className:"perm-diff",role:"region","aria-label":"变更内容",children:e.map((t,s)=>t.kind==="gap"?o.jsx("div",{className:"perm-diff-gap",children:t.text},s):o.jsxs("div",{className:`perm-diff-line ${t.kind}`,children:[o.jsx("span",{className:"no",children:t.oldNo??""}),o.jsx("span",{className:"no",children:t.newNo??""}),o.jsx("span",{className:"sig",children:t.kind==="add"?"+":t.kind==="del"?"−":" "}),o.jsx("span",{className:"txt",children:t.text||" "})]},s))})}function b5({diff:e}){const[t,s]=_.useState(!1),n=e.oldText??"",i=e.newText??"",r=i.length>0&&n.length===0,a=Om(n,i),l=a.filter(u=>u.kind==="add").length,c=a.filter(u=>u.kind==="del").length;return o.jsxs("div",{className:"perm-changes",children:[o.jsxs("button",{type:"button",className:"perm-change-row","aria-expanded":t,"aria-label":`${t?"收起":"查看"} ${e.path??"这份文件"} 的变更`,onClick:()=>s(u=>!u),children:[o.jsx(Jn,{size:13}),o.jsx("code",{title:e.path??"",children:e.path??"(未命名文件)"}),o.jsx("span",{className:"perm-counts",children:r?o.jsxs("span",{className:"add",children:["新文件 · ",l," 行"]}):o.jsxs(o.Fragment,{children:[o.jsxs("span",{className:"add",children:["+",l]}),o.jsxs("span",{className:"del",children:["−",c]})]})}),o.jsx("span",{className:"perm-caret","aria-hidden":"true",children:t?"▾":"▸"})]}),t?o.jsx(x1,{lines:a}):null,e.truncated?o.jsx("div",{className:"perm-cut",children:"agent 发来的是整份文件,这里只保留了改动附近的部分"}):null]})}function hy({f:e}){const[t,s]=_.useState(!1),n=e.oldText.length===0&&e.newText.length>0,i=n||e.oldText.length>0||e.newText.length>0,r=_.useMemo(()=>i?Om(e.oldText,e.newText):[],[i,e.oldText,e.newText]),a=e.path===e.name?"":e.path.slice(0,e.path.length-e.name.length).replace(/[\\/]+$/,"");return o.jsxs("div",{className:"fc-row",children:[o.jsxs("div",{className:"fc-line",children:[o.jsx("span",{className:"fc-dot","aria-hidden":"true"}),o.jsxs("button",{type:"button",className:"fc-name",title:`在右侧面板打开 ${e.path}`,onClick:()=>sx({path:e.path}),children:[e.name,a?o.jsx("span",{className:"fc-dir",children:a}):null,e.edits>1?o.jsxs("span",{className:"fc-edits",children:["改了 ",e.edits," 次"]}):null]}),o.jsx("button",{type:"button",className:"fc-counts","aria-expanded":t,"aria-label":`${t?"收起":"查看"} ${e.path} 的变更`,disabled:!i,onClick:()=>s(l=>!l),children:n?o.jsxs("span",{className:"add",children:["新文件 · ",e.insertions," 行"]}):o.jsxs(o.Fragment,{children:[o.jsxs("span",{className:"add",children:["+",e.insertions]}),o.jsxs("span",{className:"del",children:["−",e.deletions]})]})})]}),t&&i?o.jsx(x1,{lines:r}):null]})}function dy({msgs:e}){const t=_.useMemo(()=>{const a=[];for(const l of e)l.kind==="tool"&&l.changes?.length&&a.push(...l.changes);return PE(a)},[e]),[s,n]=_.useState(!0);if(!t.length)return null;if(t.length===1)return o.jsx("div",{className:"file-changes one",children:o.jsx(hy,{f:t[0]})});const i=t.reduce((a,l)=>a+l.insertions,0),r=t.reduce((a,l)=>a+l.deletions,0);return o.jsxs("div",{className:"file-changes",children:[o.jsxs("button",{type:"button",className:"fc-head","aria-expanded":s,"aria-label":`${s?"收起":"展开"} ${t.length} 个文件变更`,onClick:()=>n(a=>!a),children:[o.jsx(Jn,{size:13}),o.jsxs("span",{className:"fc-title",children:[t.length," 个文件变更"]}),o.jsxs("span",{className:"fc-counts static",children:[o.jsxs("span",{className:"add",children:["+",i]}),o.jsxs("span",{className:"del",children:["−",r]})]}),o.jsx("span",{className:"perm-caret","aria-hidden":"true",children:s?"▾":"▸"})]}),s?t.map(a=>o.jsx(hy,{f:a},a.path)):null]})}function w5({req:e,sessionTitle:t,waiting:s,onSkip:n}){Wo(!0,n);const[i,r]=_.useState(()=>Date.now());_.useEffect(()=>{const u=window.setInterval(()=>r(Date.now()),1e3);return()=>window.clearInterval(u)},[e.requestId]);const a=Math.max(0,Math.round((i-e.createdAt)/1e3)),l=X.permAnswer(e.requestId),c=Math.max(0,s-1);return o.jsx("div",{className:"modal-bg perm-bg",onClick:n,children:o.jsxs("div",{className:"modal perm-dialog",role:"dialog","aria-modal":"true","aria-label":"agent 请求授权","data-request-id":e.requestId,"data-session-id":e.sessionId,"data-waiting":s,onClick:u=>u.stopPropagation(),children:[o.jsx("h3",{children:"Agent 请求授权"}),o.jsxs("div",{className:"perm-ask",children:["「",t,"」里的 agent 停在这里等你答复 —— 它要执行 ",o.jsx("b",{children:e.toolCallTitle}),"(",e.kind,")。"]}),o.jsx(fg,{req:e}),o.jsx("div",{className:"opts perm-opts",children:o.jsx(w1,{sid:e.sessionId,req:e})}),c>0&&o.jsxs("div",{className:"perm-queue",role:"note",children:["这个会话还有 ",o.jsx("b",{children:c})," 个请求等着答复 —— 答完这个,下一个会接着显示在这里。"]}),o.jsxs("div",{className:"perm-note",children:["已等待 ",a," 秒。一直不答复的话,agent 那边会自己放弃这次请求(等同拒绝),这一轮就停在这里。"]}),!l&&o.jsx("div",{className:"row",children:o.jsx("button",{className:"cancel",onClick:n,children:"稍后处理"})})]})})}function Dd(e){if(e<=0)return"";if(e%60===0){const t=e/60;return t<60?`${t} 分钟`:`${Math.round(t/60)} 小时`}return`${e} 秒`}function x5(){const[e,t]=_.useState(null);_.useEffect(()=>{let n=!0;return fetch("/api/settings",{credentials:"same-origin"}).then(i=>i.ok?i.json():null).then(i=>{n&&t(Number(i?.observer?.intervalSec??0))}).catch(()=>{n&&t(0)}),()=>{n=!1}},[]);const s=_.useCallback(n=>{t(n),fetch("/api/settings",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify({observer:{intervalSec:n}})}).catch(()=>{})},[]);return[e??0,s]}function S5({id:e,text:t,sid:s}){const[n]=lr(),i=Bm(),[r,a]=_.useState(!1),[l,c]=_.useState(!1),[u,h]=_.useState(null),d=_.useRef(null);Br(r,[d],()=>a(!1));const p=_.useRef({timer:null,fired:!1}),f=()=>{p.current.timer&&(window.clearTimeout(p.current.timer),p.current.timer=null)};_.useEffect(()=>f,[]);const m=()=>{p.current.fired=!1,f(),p.current.timer=window.setTimeout(()=>{p.current.fired=!0,a(!0)},500)};if(!t.trim())return null;const y=i.speaking&&i.speakingId===e;if(typeof window<"u"&&!("speechSynthesis"in window)&&!n.serverTts)return o.jsx("span",{className:"bubble-note",title:"this browser has no speech synthesis",children:"no voices"});const x=async g=>{if(l)return;const v=PP(m1(e,g));if(v){a(!1),Mt.speak(v.text,`${e}#summary:${g??"cfg"}`,n);return}c(!0),h(null);try{const b=await FP(s,e,g);a(!1),Mt.speak(b.text,`${e}#summary:${g??"cfg"}`,n)}catch(b){const w=b;h({msg:w?.message??String(b),hint:w?.hint}),a(!1)}finally{c(!1)}};return o.jsxs(o.Fragment,{children:[o.jsxs("span",{className:"speak-wrap bubble-speak",ref:d,children:[o.jsx("button",{className:`bubble-btn speak ${y?"on":""} ${l?"working":""}`,title:l?"正在生成语音播报总结…":y?"stop reading(长按:语音播报总结)":"read this reply aloud(长按:语音播报总结)","aria-label":y?"stop reading":"read aloud","aria-haspopup":"menu","aria-expanded":r,onClick:()=>{if(p.current.fired){p.current.fired=!1;return}y?Mt.stop():Mt.speak(t,e,n)},onPointerDown:m,onPointerUp:f,onPointerLeave:f,onPointerCancel:f,onContextMenu:g=>{g.preventDefault(),f(),a(!0)},onKeyDown:g=>{(g.key==="F10"&&g.shiftKey||g.key==="ContextMenu")&&(g.preventDefault(),a(!0))},children:l?o.jsx(Po,{size:13,className:"spin"}):y?o.jsx(Lw,{size:13}):o.jsx(th,{size:13})}),r?o.jsxs("div",{className:"speak-menu bubble-menu",role:"menu",children:[o.jsxs("button",{type:"button",role:"menuitem",className:"speak-menu-item","data-speak-summary":"verbatim",onClick:()=>{a(!1),Mt.speak(t,e,n)},children:[o.jsx("span",{className:"speak-check",children:"›"}),o.jsx("span",{className:"speak-name",children:"读整条"})]}),[100,150,200].map(g=>o.jsxs("button",{type:"button",role:"menuitem",className:"speak-menu-item",disabled:l,"data-speak-summary":String(g),onClick:()=>void x(g),children:[o.jsx("span",{className:"speak-check",children:l?"•":"›"}),o.jsx("span",{className:"speak-name",children:l?"总结中…":`语音播报总结 · 约 ${g} 字`})]},g)),o.jsxs("button",{type:"button",role:"menuitem",className:"speak-menu-item",disabled:l,"data-speak-summary":"cfg",onClick:()=>void x(),children:[o.jsx("span",{className:"speak-check",children:"›"}),o.jsx("span",{className:"speak-name",children:l?"总结中…":"语音播报总结 · 按设置"})]}),o.jsx("p",{className:"speak-hint",children:"把这条压成一段能听完的话;字数写进提示词交给模型(提示词在 设置 → 语音总结)"})]}):null]}),u?o.jsxs("span",{className:"bubble-note err",role:"status",children:[u.msg,u.hint?` · ${u.hint}`:""]}):null]})}function k5({mkey:e}){const t=_.useSyncExternalStore(IP,ay,ay),[s,n]=_.useState(!1),i=OP(e);if(!i)return null;const r=i.route==="session"?`${i.provider??""}${i.provider?" · ":""}${i.model??""}`:i.model?`语音端点 · ${i.model}`:"",a=i.maxChars?` · 按 ${i.maxChars} 字压`:"",l=i.via==="verbatim"?"原文本身就够短,直接念":`${i.chars} 字${a} · ${(i.ms/1e3).toFixed(1)}s${r?` · ${r}`:""}`;return o.jsxs("div",{className:`bubble-note speech-note${s?" open":""}`,"data-summary-chars":i.chars,children:[o.jsx("button",{type:"button",className:"speech-note-tag","aria-expanded":s,onClick:()=>n(c=>!c),children:"播报稿"}),o.jsx("span",{className:"speech-note-text",onClick:()=>n(c=>!c),title:"点击展开/收起",children:i.text}),o.jsx("span",{className:"speech-note-meta",title:i.routeNote??void 0,children:l}),o.jsx("button",{type:"button",className:"speech-note-x",title:"丢掉这份稿子(下次长按会重新生成)","aria-label":"drop this summary",onClick:()=>BP(e),children:o.jsx(wn,{size:11})}),o.jsx("span",{hidden:!0,children:t})]})}const pg=["image/png","image/jpeg","image/webp","image/gif"],C5=4*1024*1024,E5=256*1024;function mg(){const e=_.useRef(!1);return{handlers:{onCompositionStart:()=>{e.current=!0},onCompositionEnd:()=>{e.current=!1}},isComposing:t=>e.current||t.nativeEvent.isComposing===!0}}function S1(e){return pg.includes(e.type)?e.size>C5?Promise.resolve({error:`${e.name}: image larger than 4MB`}):new Promise(s=>{const n=new FileReader;n.onload=()=>{const i=String(n.result??"");s({id:`${e.name}-${e.size}-${Math.random().toString(36).slice(2,7)}`,name:e.name,kind:"image",mimeType:e.type,preview:i,payload:i.slice(i.indexOf(",")+1),bytes:e.size})},n.onerror=()=>s({error:`${e.name}: could not be read`}),n.readAsDataURL(e)}):e.size>E5?Promise.resolve({error:`${e.name}: larger than 256kB — attach it as a path instead`}):new Promise(s=>{const n=new FileReader;n.onload=()=>s({id:`${e.name}-${e.size}-${Math.random().toString(36).slice(2,7)}`,name:e.name,kind:"text",mimeType:e.type||"text/plain",payload:String(n.result??""),bytes:e.size}),n.onerror=()=>s({error:`${e.name}: could not be read`}),n.readAsText(e)})}function k1(e){if(!e)return[];const t=Array.from(e.files??[]);for(const s of Array.from(e.items??[])){if(s.kind!=="file")continue;const n=s.getAsFile();n&&!t.some(i=>i.name===n.name&&i.size===n.size&&i.type===n.type)&&t.push(n)}return t}function C1(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(0)} kB`:`${(e/1048576).toFixed(1)} MB`}const ir=["#7f8c98","#5fb3a1","#7fb069","#d9a441","#e8843c","#f0603f","#ff4d4d"];function E1(e,t){const s=Math.max(1,t.length),n=t.findIndex(a=>String(a.value)===String(e)),i=n<0?0:n+1;return{color:n<0?"var(--text-dim)":ir[Math.min(n,ir.length-1)],level:i,total:s}}function N1({level:e,total:t,color:s}){const n=Math.min(7,t),i=Math.max(0,Math.min(n,Math.round(e/t*n)));return o.jsx("span",{className:"tb-pips","aria-hidden":"true",children:Array.from({length:n}).map((r,a)=>o.jsx("i",{style:{background:a<i?s:"var(--line)"}},a))})}function Cl(e,t){const s=t==="effort"?["thought_level","reasoning"]:["model","model_config"],n=t==="effort"?/reason|effort|think|depth/i:/model/i;return e.find(i=>i.type==="select"&&i.category&&s.includes(String(i.category)))??e.find(i=>i.type==="select"&&n.test(i.id))}function R1({label:e,title:t,icon:s,value:n,children:i,open:r,onToggle:a,testId:l}){const c=_.useRef(null);return Br(r,[c],a),o.jsxs("div",{className:"tb-wrap",ref:c,children:[o.jsxs("button",{type:"button",className:`tb-btn ${r?"on":""}`,title:t,"aria-label":t,"aria-expanded":r,"data-testid":l,onClick:a,children:[s,o.jsx("span",{className:"tb-label",children:n||e}),o.jsx(Io,{size:11,className:"tb-chev"})]}),r?i:null]})}function Bu({items:e,current:t,onPick:s,empty:n}){const i=Nw();return e.length?o.jsx("div",{className:"tb-list",role:"listbox",ref:i,children:e.map(r=>o.jsxs("button",{role:"option","aria-selected":r.value===t,className:`tb-opt ${r.value===t?"sel":""}`,title:r.hint?`${r.name} — ${r.hint}`:r.name,onClick:()=>s(r.value),children:[o.jsxs("span",{className:"tb-opt-name",children:[r.color?o.jsx("i",{className:"tb-dot",style:{background:r.color}}):null,r.name]}),r.hint?o.jsx("span",{className:"tb-opt-hint",children:r.hint}):null]},r.value))}):o.jsx("div",{className:"tb-list",ref:i,children:o.jsx("div",{className:"tb-empty",children:n})})}function j1(e){return e.category==="_context_window"?!0:/budget|context/i.test(`${e.id} ${e.name??""}`)}function N5({v:e}){const t=e.info.usage,s=e.info.configOptions.find(j1),[n,i]=_.useState(!1),r=_.useRef(null),[a,l]=_.useState(!1),[c,u]=_.useState(""),[h,d]=_.useState(!0),[p,f]=_.useState(""),[m,y]=_.useState(""),x=mg(),g=e.trace;if(Br(n,[r],()=>{i(!1),l(!1)}),!t||!t.used&&!t.size)return null;const v=e.info.contextLimit&&e.info.contextLimit>0?e.info.contextLimit:null,b=e.info.modelContextLimit&&e.info.modelContextLimit>0?e.info.modelContextLimit:null,w=v?"session":b?"model":"agent",k=v??b??t.size,j=k>0?Math.min(100,Math.round(t.used/k*100)):0,I=j>=85?"hot":j>=65?"warn":"ok",A=k>0?Math.max(0,k-t.used):0,D=e.info.commands??[],O=T=>D.some($=>$.name===T),F=w==="session"?"你为本会话声明":w==="model"?"你为这个模型记下的":"agent 上报(usage_update)",C=async(T,$={})=>{f($.forgetModel?"forget":"save"),y("");try{await X.setContextLimit(e.info.id,T,$),l(!1)}catch(E){y(String(E?.message??E))}finally{f("")}},N=T=>{if(e.info.cold){i(!1),X.resume(e.info.id);return}X.send({t:"prompt",sessionId:e.info.id,text:`/${T}`}),i(!1)},P=(T,$)=>{const E=$.trim();E&&(X.send({t:"set-config",sessionId:e.info.id,configId:T,value:E}),u(""))},B=String(s?.currentValue??"");return o.jsxs("div",{className:`usage-row ${I}`,ref:r,children:[o.jsxs("button",{className:"usage-text",onClick:()=>i(T=>!T),title:"上下文窗口 — 点这里改",children:[o.jsx(E_,{size:12,className:"usage-icon"}),k>0?`${xa(t.used)} / ${xa(k)}`:`${xa(t.used)} / —`,k>0?` · ${j}%`:"",w==="session"?" · 声明":w==="model"?" · 模型记录":""]}),k>0?o.jsx("div",{className:"usage-bar",title:`${t.used} / ${k} tokens (${j}%)`,children:o.jsx("i",{style:{width:`${j}%`}})}):null,I==="hot"&&O("compress")&&!e.busy?o.jsxs("button",{className:"usage-act",onClick:()=>N("compress"),title:"发送 /compress:让 agent 压缩上下文(这是它自己公告的命令)",children:[o.jsx(Im,{size:11})," 压缩上下文"]}):null,n?o.jsxs("div",{className:"usage-detail",children:[o.jsxs("div",{className:"usage-set",children:[o.jsxs("div",{className:"usage-set-head",children:[o.jsx(E_,{size:12})," 上下文窗口",o.jsx("span",{className:"usage-set-scope",children:s?String(s.meta?.scope??"")==="model"?"按模型":"":"仅声明"})]}),s?o.jsxs(o.Fragment,{children:[o.jsx("div",{className:"usage-set-chips",children:(s.options??[]).map(T=>o.jsx("button",{className:`usage-chip ${B===String(T.value)?"sel":""}`,onClick:()=>P(s.id,String(T.value)),children:String(T.value)==="auto"?"自动":T.name},String(T.value)))}),o.jsxs("div",{className:"usage-edit",children:[o.jsx("input",{value:c,inputMode:"numeric","aria-label":"context window in tokens",placeholder:s.meta?.freeform===!0?"任意 token 数,如 300000":"填一个数",onChange:T=>u(T.target.value),onKeyDown:T=>{x.isComposing(T)||(T.key==="Enter"&&P(s.id,c),T.key==="Escape"&&(T.stopPropagation(),i(!1)))}}),o.jsx("button",{className:"usage-edit-btn",disabled:!c.trim(),onClick:()=>P(s.id,c),children:"set"})]}),o.jsx("div",{className:"settings-note",children:"常用:256k / 512k / 768k / 1m;填 auto 回到模型自己的窗口。"}),o.jsxs("div",{className:"usage-note",children:["改的是",o.jsx("b",{children:"这个模型"}),":同模型的所有会话(含新开的、别的槽位)都用同一个上限。它只会让 Hermes 更早压缩,不会把窗口撑过模型本身。"]})]}):o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"usage-note",children:["这个后端没公告上下文旋钮,所以下面这个数只是仪表盘的",o.jsx("b",{children:"声明"}),",只影响百分比;真减上下文用压缩命令或换模型。"]}),a?o.jsxs("div",{className:"usage-edit",children:[o.jsx("input",{autoFocus:!0,value:c,inputMode:"numeric","aria-label":"context window in tokens",placeholder:String(t.size||e.info.contextLimit||2e5),onChange:T=>u(T.target.value),...x.handlers,onKeyDown:T=>{if(!x.isComposing(T)){if(T.key==="Enter"){const $=Number(c.replace(/[^0-9]/g,""));$>0&&C($,{remember:h})}T.key==="Escape"&&(T.stopPropagation(),l(!1))}}}),o.jsx("button",{className:"usage-edit-btn",disabled:p!==""||!Number(c.replace(/[^0-9]/g,"")),onClick:()=>void C(Number(c.replace(/[^0-9]/g,"")),{remember:h}),children:p==="save"?"…":"set"}),o.jsxs("label",{className:"usage-check",title:"像 studio 那样按模型记住:下次用这个模型自动带回来",children:[o.jsx("input",{type:"checkbox",checked:h,onChange:T=>d(T.target.checked)}),"记到本模型"]}),b?o.jsx("button",{className:"usage-edit-btn",disabled:p!=="",onClick:()=>void C(null,{forgetModel:!0}),children:p==="forget"?"…":"忘掉本模型记录"}):null]}):o.jsx("button",{className:"usage-edit-btn",onClick:()=>{u(String(k||2e5)),l(!0)},children:"声明窗口长度"})]})]}),o.jsxs("div",{children:["已用 ",t.used," / ",k||"—"," tokens(",j,"%)"]}),o.jsxs("div",{children:["剩余:",k>0?A:"unknown"," tokens"]}),o.jsxs("div",{children:["窗口来源:",o.jsx("b",{children:F})]}),t.size>0&&w!=="agent"?o.jsxs("div",{children:["agent 上报:",xa(t.size)," tokens (usage_update)"]}):null,b&&w==="session"?o.jsxs("div",{children:["本模型记录:",xa(b)," tokens"]}):null,t.cost!=null?o.jsxs("div",{children:["本轮花费:$",t.cost.toFixed(6)]}):null,g?.model?o.jsxs("div",{children:["model:",g.model]}):null,g&&(g.effort||g.mode)?o.jsxs("div",{children:["本轮:",[g.effort&&`思考强度 ${g.effort}`,g.mode&&`模式 ${g.mode}`].filter(Boolean).join(",")]}):null,O("compress")||O("context")?o.jsxs("div",{className:"usage-actions",children:[O("compress")?o.jsx("button",{className:"usage-act",onClick:()=>N("compress"),title:"让 agent 压缩上下文(/compress,它自己公告的命令)",children:"压缩上下文"}):null,O("context")?o.jsx("button",{className:"usage-act",onClick:()=>N("context"),title:"看消息按角色分布(/context)",children:"消息分布"}):null]}):null,m?o.jsx("div",{className:"usage-edit-err",children:m}):null]}):null]})}function R5({o:e,sessionId:t}){const s=e.meta??{},n=s.freeform===!0,[i,r]=_.useState(""),a=String(e.currentValue??""),l=typeof s.unit=="string"?s.unit:"tokens",c=h=>X.send({t:"set-config",sessionId:t,configId:e.id,value:h}),u=mg();return o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(Al,{size:13})," ",e.name||e.id]}),e.options?.map(h=>o.jsx("button",{className:`settings-opt ${a===String(h.value)?"sel":""}`,onClick:()=>c(String(h.value)),children:h.name},String(h.value))),n?o.jsxs("div",{className:"settings-freeform",children:[o.jsx("input",{className:"settings-input",type:"number",inputMode:"numeric",min:typeof s.min=="number"?s.min:void 0,step:typeof s.step=="number"?s.step:1024,placeholder:`任意 ${l}`,"aria-label":`${e.name||e.id} value`,value:i,onChange:h=>r(h.target.value),...u.handlers,onKeyDown:h=>{u.isComposing(h)||h.key==="Enter"&&i.trim()&&c(i.trim())}}),o.jsx("button",{className:"settings-opt",disabled:!i.trim(),onClick:()=>c(i.trim()),children:"set"})]}):null]})}function j5({v:e,prefs:t,setPrefs:s,onClose:n,panelRef:i}){const r=e.info,a=r.modes?.availableModes??[],l=Cl(r.configOptions,"effort"),c=Cl(r.configOptions,"model"),h=_.useSyncExternalStore(Mt.subscribeVoices,()=>Mt.voices().length)?Mt.voices():[],d=Vn();return o.jsxs("div",{className:"settings-pop",role:"dialog","aria-label":"chat settings",ref:i,children:[o.jsxs("div",{className:"settings-head",children:[o.jsx("span",{children:"chat settings"}),o.jsx("span",{className:"head-spacer"}),o.jsx("button",{className:"icon-btn",title:"close","aria-label":"close",onClick:n,children:o.jsx(wn,{size:13})})]}),a.length>0&&o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(Mw,{size:13})," permission mode"]}),a.map(p=>o.jsx("button",{className:`settings-opt ${r.modes?.currentModeId===p.id?"sel":""}`,onClick:()=>X.send({t:"set-mode",sessionId:r.id,modeId:p.id}),children:p.name},p.id))]}),l?.options?.length?o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(wE,{size:13})," thinking depth"]}),l.options.map((p,f)=>o.jsxs("button",{className:`settings-opt ${String(l.currentValue??"")===String(p.value)?"sel":""}`,onClick:()=>X.send({t:"set-config",sessionId:r.id,configId:l.id,value:String(p.value)}),children:[o.jsx("i",{className:"settings-dot",style:{"--effort":ir[Math.min(f,ir.length-1)]}}),p.name]},String(p.value))),o.jsx("div",{className:"settings-note",children:"只列这个路由真支持的档;改的是本会话。"})]}):null,r.configOptions.filter(p=>p.type==="select"&&p.options&&p!==l&&p!==c&&!j1(p)).map(p=>o.jsx(R5,{o:p,sessionId:r.id},p.id)),o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(th,{size:13})," read replies aloud"]}),o.jsxs("label",{className:"settings-toggle",children:[o.jsx("input",{type:"checkbox",checked:t.autoRead,onChange:p=>s({autoRead:p.target.checked})}),o.jsx("span",{children:"speak every finished reply"})]}),h.length>0&&o.jsxs("select",{className:"settings-select",value:t.voiceURI,onChange:p=>s({voiceURI:p.target.value}),"aria-label":"voice",children:[o.jsxs("option",{value:"",children:["auto voice (",t.lang,")"]}),h.map(p=>o.jsxs("option",{value:p.voiceURI,children:[p.name," — ",p.lang]},p.voiceURI))]}),h.length===0?o.jsx("div",{className:"settings-note",children:"this browser exposes no voices"}):null,o.jsxs("label",{className:"settings-range",children:[o.jsxs("span",{children:["speed ",t.rate.toFixed(2),"×"]}),o.jsx("input",{type:"range",min:.5,max:2,step:.05,value:t.rate,onChange:p=>s({rate:Number(p.target.value)})})]}),d.tts.server?o.jsxs("label",{className:"settings-toggle",children:[o.jsx("input",{type:"checkbox",checked:t.serverTts,onChange:p=>s({serverTts:p.target.checked})}),o.jsxs("span",{children:["use the server voice (",d.tts.model??"configured",")"]})]}):null]}),o.jsxs("div",{className:"settings-group",children:[o.jsxs("div",{className:"settings-label",children:[o.jsx(sr,{size:13})," dictation"]}),o.jsxs("select",{className:"settings-select",value:t.stt,onChange:p=>s({stt:p.target.value}),"aria-label":"dictation engine",children:[o.jsx("option",{value:"auto",children:"auto — 服务端流式 > 浏览器 > 批量"}),o.jsxs("option",{value:"stream",children:["stream",d.stt.streaming?` (${d.stt.model??"百炼"})`:" (not configured)"]}),o.jsxs("option",{value:"browser",children:["browser",Rf()?"":" (unavailable)"]}),o.jsxs("option",{value:"server",children:["server",d.stt.server?` (${d.stt.batchModel??"configured"})`:" (not configured)"]})]}),o.jsx("input",{className:"settings-input",value:t.lang,onChange:p=>s({lang:p.target.value}),placeholder:"language, e.g. zh-CN","aria-label":"speech language"}),o.jsxs("div",{className:"settings-note",children:["browser dictation ",Rf()?"available":"unavailable"," · ",d.provider," STT"," ",d.stt.streaming?"streaming":d.stt.server?"batch":"not configured"]})]})]})}const Ec=new Map;function T5({v:e,call:t,onCloseCall:s}){const[n,i]=_.useState(()=>Ec.get(e.info.id)??""),r=window.innerWidth<720?"message… (/ for commands)":"message… (Enter send, Shift+Enter newline, / for commands)",a=/Mac|iPhone|iPad/.test(navigator.platform??"")?"⌘":"Ctrl+",l=window.innerWidth<=720?"message… (Enter queues)":`message… (${a}Enter interrupts · Enter queues)`,[c,u]=_.useState(0),[h,d]=_.useState(!1),p=_.useRef(null),f=_.useRef(null),m=_.useRef(null),y=_.useRef(!1),x=_.useRef(null),g=_.useRef(""),v=_.useRef(!1),b=_.useMemo(()=>e.msgs.filter(R=>R.kind==="user").map(R=>R.text).filter(R=>R.trim()),[e.msgs]),w=_.useRef(e.info.id);_.useEffect(()=>{Ec.set(w.current,n)},[n]),_.useEffect(()=>{w.current!==e.info.id&&(Ec.set(w.current,n),w.current=e.info.id,i(Ec.get(e.info.id)??""),x.current=null,g.current="",d(!1),u(0))},[e.info.id,n]);const[k,j]=_.useState([]),[I,A]=_.useState(null),[D,O]=_.useState(""),[F,C]=_.useState(!1),[N,P]=_.useState(!1),[B,T]=_.useState(null);_.useEffect(()=>{const R=Ie.current;R&&(R.style.height="42px",R.style.height=`${Math.min(R.scrollHeight,window.innerHeight*.4)}px`)},[n]);const[$,E]=_.useState(!1),[z,H]=_.useState(null),[ne,ae]=_.useState({});_.useEffect(()=>{ae({}),H(null)},[e.info.id]);const[G,q]=lr(),te=Fm(),ue=Bm(),Ie=_.useRef(null),lt=_.useRef(null),Je=async R=>{const Z=Array.from(R);if(!Z.length)return;const _e=await Promise.all(Z.map(et=>S1(et))),Pe=[],qe=[];for(const et of _e)"error"in et?qe.push(et.error):Pe.push(et);Pe.length&&j(et=>[...et,...Pe]),O(qe.join(" · "))},$e=()=>k.map(R=>R.kind==="image"?{kind:"image",mimeType:R.mimeType,data:R.payload,name:R.name}:{kind:"text",name:R.name,text:R.payload}),Ze=R=>{if(R.key!=="ArrowUp"&&R.key!=="ArrowDown"||R.shiftKey||R.altKey||R.metaKey||R.ctrlKey||!b.length)return!1;const Z=R.currentTarget,_e=Z.selectionStart??0;if(R.key==="ArrowUp"&&Z.value.slice(0,_e).includes(`
|
|
130
130
|
`)||R.key==="ArrowDown"&&Z.value.slice(_e).includes(`
|
|
131
131
|
`))return!1;if(R.preventDefault(),R.key==="ArrowUp")x.current===null?(g.current=Z.value,x.current=b.length-1):x.current=Math.max(0,x.current-1);else{if(x.current===null)return!0;if(x.current>=b.length-1)return x.current=null,v.current=!0,i(g.current),requestAnimationFrame(()=>Ie.current?.setSelectionRange(g.current.length,g.current.length)),!0;x.current+=1}const Pe=b[x.current];return v.current=!0,i(Pe),requestAnimationFrame(()=>Ie.current?.setSelectionRange(Pe.length,Pe.length)),!0},Xe=()=>{const R=n.trim();if(!R&&!k.length)return;const Z=$e();if(e.info.cold){X.sendToCold(e.info.id,R,Z),i(""),j([]),O(""),u(0),Va.current();return}if(Rr(e)||e.info.status!=="ready"){if(!R&&!Z.length)return;X.enqueuePrompt(e.info.id,R,Z)}else X.sendPrompt(e.info.id,R,Z);i(""),j([]),O(""),u(0),x.current=null,g.current="",Va.current()},xe=()=>{const R=n.trim();if(!R&&!k.length)return;const Z=$e();e.info.cold?X.sendToCold(e.info.id,R,Z):X.sendNow(e.info.id,R,Z),i(""),j([]),O(""),u(0),Va.current()};_.useEffect(()=>{if(t||!we.owns("chat")||te.status!=="idle"||!te.text)return;const R=we.consume();R&&(i(Z=>Z.trim()?`${Z.trim()} ${R}`:R),Ie.current?.focus())},[te.status,te.text,t]);const Se=/^\/\S*$/.test(n)?n.slice(1).toLowerCase():null,Fe=Se===null?[]:e.info.commands.filter(R=>R.name.toLowerCase().includes(Se)).slice(0,8),je=Se!==null&&e.info.status==="ready"&&!h;Br(je,[p],()=>d(!0)),Br(N||B!==null,[f,m],()=>{T(null),P(!1)}),_.useEffect(()=>{T(null),P(!1),d(!1)},[e.info.id]);const ht=R=>{i(`/${R} `),u(0),Ie.current?.focus()},fe=te.status==="listening"||te.status==="recording"||te.status==="requesting",Qe=Cl(e.info.configOptions,"effort"),ke=Cl(e.info.configOptions,"model"),be=e.info.models?.availableModels??[],W=e.info.models?.currentModelId??"",he=be.find(R=>R.modelId===W)?.name??ke?.options?.find(R=>String(R.value)===String(ke.currentValue??""))?.name??W,Ae=Pm(he,W),Oe=Qe?.options?.find(R=>String(R.value)===String(Qe.currentValue??""))?.name??"",Y=Qe?E1(String(Qe.currentValue??""),Qe.options??[]):null;return o.jsxs("div",{className:`composer ${F?"drop-active":""}`,onDragOver:R=>{R.preventDefault(),C(!0)},onDragLeave:()=>C(!1),onDrop:R=>{R.preventDefault(),C(!1),R.dataTransfer?.files?.length&&Je(R.dataTransfer.files)},onPaste:R=>{const Z=k1(R.clipboardData);Z.length&&(R.preventDefault(),Je(Z))},children:[o.jsx(n5,{v:e}),o.jsx(d5,{v:e}),o.jsx(N5,{v:e}),o.jsxs("div",{className:"composer-inner",ref:p,children:[je&&o.jsx("div",{className:"slash-palette",role:"listbox","aria-label":"slash commands",children:Fe.length?Fe.map((R,Z)=>o.jsxs("div",{role:"option","aria-selected":Z===c,className:`slash-item ${Z===c?"sel":""}`,onMouseEnter:()=>u(Z),onClick:()=>ht(R.name),children:[o.jsxs("span",{className:"cmd",children:["/",R.name]}),R.description?o.jsx("span",{className:"desc",children:R.description}):null,o.jsx("span",{className:"src",title:"advertised by the agent over ACP",children:"agent"})]},R.name)):o.jsx("div",{className:"slash-item empty",children:e.info.commands.length?`no command matches “/${Se}”`:"this agent advertises no slash commands"})}),N&&o.jsx(j5,{v:e,prefs:G,setPrefs:q,onClose:()=>P(!1),panelRef:f}),k.length>0&&o.jsxs("div",{className:"draft-row",children:[k.map(R=>o.jsxs("span",{className:`draft ${R.kind}`,title:`${R.name} · ${C1(R.bytes)}`,children:[R.preview?o.jsx("img",{src:R.preview,alt:R.name}):o.jsx(Jn,{size:13}),o.jsx("span",{className:"draft-name",children:R.name}),o.jsx("button",{className:"draft-x","aria-label":`remove ${R.name}`,onClick:()=>j(Z=>Z.filter(_e=>_e.id!==R.id)),children:o.jsx(wn,{size:11})})]},R.id)),o.jsx("button",{className:"draft-clear",onClick:()=>j([]),children:"clear"})]}),D&&o.jsx("div",{className:"composer-note err",children:D}),e.queue.length>0&&o.jsxs("div",{className:"queue-list","aria-label":"queued messages",children:[o.jsxs("div",{className:"queue-head",children:[o.jsxs("span",{className:"queue-title",children:["Queued · ",e.queue.length]}),o.jsx("span",{className:"queue-hint",children:e.queue.some(R=>R.unsure)?"未确认送达 — 点 ↑ 重发,或 ✕ 丢掉":e.queue.some(R=>R.inflight)?"sending…":e.resuming?"waking the agent — sends once it is up":e.info.cold?"sends when you wake this session":e.info.status!=="ready"?"process starting — sends once ready":"goes out when this turn ends"})]}),e.queue.map((R,Z)=>o.jsxs("div",{className:`queue-row${R.inflight?" inflight":""}${R.unsure?" unsure":""}`,"data-queue-id":R.id,children:[o.jsx("span",{className:"queue-idx","aria-hidden":"true",children:Z+1}),I?.id===R.id?o.jsx("textarea",{className:"queue-edit",rows:1,autoFocus:!0,value:I.text,"aria-label":"edit the queued message",onChange:_e=>A({id:R.id,text:_e.target.value}),onKeyDown:_e=>{if(_e.key==="Escape"){_e.preventDefault(),A(null);return}_e.key==="Enter"&&!_e.shiftKey&&(_e.preventDefault(),X.editQueued(e.info.id,R.id,I.text),A(null))},onBlur:()=>{X.editQueued(e.info.id,R.id,I.text),A(null)}}):o.jsx("span",{className:"queue-text",title:R.text,children:R.text}),R.unsure?o.jsx("span",{className:"queue-flag",title:"服务器没回执 —— 点 ↑ 重发",children:"未送达"}):null,o.jsxs("span",{className:"queue-actions",children:[o.jsx("button",{className:"queue-btn",title:"send now — stops the running turn and takes the floor","aria-label":"send this one now",onClick:()=>X.sendQueuedNow(e.info.id,R.id),children:o.jsx(Iw,{size:13})}),o.jsx("button",{className:"queue-btn",title:"edit this message","aria-label":"edit this queued message",onClick:()=>A(I?.id===R.id?null:{id:R.id,text:R.text}),children:o.jsx(jw,{size:13})}),o.jsx("button",{className:"queue-btn danger",title:"drop it — it will not be sent","aria-label":"drop this queued message",onClick:()=>X.dropQueued(e.info.id,R.id),children:o.jsx(wn,{size:13})})]})]},R.id))]}),ue.note?o.jsx("div",{className:"composer-note",children:ue.note}):null,ue.error?o.jsx("div",{className:"composer-note err",children:ue.error}):null,fe||te.status==="transcribing"||te.error?o.jsxs("div",{className:`dict-chip ${te.error?"err":""}`,children:[o.jsx(sr,{size:13}),te.error?te.error:te.status==="requesting"?"waiting for the microphone…":te.status==="transcribing"?"transcribing…":o.jsxs(o.Fragment,{children:[te.text," ",o.jsx("span",{className:"interim",children:te.interim}),te.engine==="stream"?" · 流式":"",te.engine==="server"?` · ${te.seconds}s`:""]}),fe?o.jsx("button",{className:"dict-stop",onClick:()=>we.stop(),children:"stop"}):null]}):null,o.jsxs("div",{className:"composer-box",children:[o.jsx("textarea",{ref:Ie,rows:1,value:n,onFocus:()=>d(!1),placeholder:e.resuming?"waking the agent…":e.info.cold?"no ACP process — Enter wakes it":Rr(e)?l:e.info.status==="ready"?r:e.info.status,onChange:R=>{i(R.target.value),d(!1),u(0),v.current?v.current=!1:x.current=null},onCompositionStart:()=>{y.current=!0},onCompositionEnd:()=>{y.current=!1},onKeyDown:R=>{if(!(y.current||R.nativeEvent.isComposing)){if(R.key==="Enter"&&(R.metaKey||R.ctrlKey)&&!R.shiftKey){R.preventDefault(),xe();return}if(je&&Fe.length){if(R.key==="ArrowDown"){R.preventDefault(),u(Z=>(Z+1)%Fe.length);return}if(R.key==="ArrowUp"){R.preventDefault(),u(Z=>(Z-1+Fe.length)%Fe.length);return}if(R.key==="Tab"||R.key==="Enter"&&!R.shiftKey){R.preventDefault(),ht(Fe[c].name);return}if(R.key==="Escape"){R.preventDefault(),i("");return}}if(!Ze(R)){if(R.key==="Escape"&&x.current!==null){R.preventDefault(),x.current=null,i(g.current);return}R.key==="Enter"&&!R.shiftKey&&(R.preventDefault(),Xe())}}}}),o.jsxs("div",{className:"composer-bar",ref:m,children:[o.jsx("input",{ref:lt,type:"file",multiple:!0,hidden:!0,accept:`${pg.join(",")},.txt,.md,.json,.log,.csv,.ts,.tsx,.js,.jsx,.py,.rb,.go,.rs,.java,.c,.cpp,.h,.sh,.yaml,.yml,.toml,.ini,.html,.css`,onChange:R=>{const Z=R.target.files;Z&&Z.length?Je(Z):O("选择器没有返回文件 —— 再试一次,或从相册 / 文件管理里选"),R.target.value=""}}),o.jsx("button",{className:"icon-btn",title:"attach an image or a text file","aria-label":"attach",onClick:()=>lt.current?.click(),children:o.jsx(_u,{size:16})}),Qe&&Y?o.jsxs("div",{className:"tb-wrap",style:{"--effort":Y.color},children:[o.jsxs("button",{type:"button",className:`tb-btn tb-effort ${B==="effort"?"on":""}`,style:{color:Y.level?Y.color:void 0},title:`thinking depth — ${Oe||"agent default"}`,"aria-label":`thinking depth: ${Oe||"agent default"}`,"aria-expanded":B==="effort","data-testid":"tb-effort",onClick:()=>{P(!1),T(R=>R==="effort"?null:"effort")},children:[o.jsx(N1,{level:Y.level,total:Y.total,color:Y.color}),o.jsx(Io,{size:11,className:"tb-chev"})]}),B==="effort"?o.jsx(Bu,{items:(Qe.options??[]).map((R,Z)=>({value:String(R.value),name:R.name,hint:null,color:ir[Math.min(Z,ir.length-1)]})),current:String(Qe.currentValue??""),empty:"the agent advertises no levels",onPick:R=>{X.send({t:"set-config",sessionId:e.info.id,configId:Qe.id,value:R}),T(null)}}):null]}):null,o.jsx("button",{className:`icon-btn ${N?"on":""}`,title:"chat settings — permission mode, voice","aria-label":"chat settings","aria-expanded":N,onClick:()=>{T(null),P(R=>!R)},children:o.jsx(Al,{size:16})}),be.length>0||ke?o.jsx(R1,{label:"model",title:`model — currently ${Ae||"unknown"}`,icon:o.jsx(Im,{size:15}),value:$?`${Ae} …`:Ae,testId:"tb-model",open:B==="model",onToggle:()=>{P(!1),T(R=>R==="model"?null:"model")},children:be.length>0?o.jsx(zw,{models:be,current:W,bad:ne,err:z,onPick:R=>{if(R===W){T(null);return}E(!0),H(null),X.setModel(e.info.id,R).then(()=>{T(null),H(null),O("")}).catch(Z=>{const _e=String(Z?.message??Z);H({id:R,text:_e}),ae(Pe=>({...Pe,[R]:_e})),O(`model switch failed: ${_e}`)}).finally(()=>E(!1))}}):o.jsx(Bu,{items:(ke?.options??[]).map(R=>({value:String(R.value),name:R.name})),current:String(ke?.currentValue??""),empty:"the agent lists no models",onPick:R=>{ke&&X.send({t:"set-config",sessionId:e.info.id,configId:ke.id,value:R}),T(null)}})}):null,o.jsx("span",{className:"head-spacer"}),ue.speaking?o.jsx("button",{className:"icon-btn on",title:"stop reading aloud","aria-label":"stop reading",onClick:()=>Mt.stop(),children:o.jsx(vE,{size:14})}):null,o.jsx("button",{className:`icon-btn ${fe?"on rec":""}`,title:te.error?te.error:fe?"stop dictation":"dictate a prompt","aria-label":"dictate",onClick:()=>{we.cancel(),we.start(G,e.info.id)},children:o.jsx(sr,{size:16})}),t?o.jsx(KD,{sessionId:e.info.id,onClose:s,onKeyboard:()=>{s(),window.setTimeout(()=>Ie.current?.focus(),30)},renderTranscript:R=>o.jsx(_1,{...R,notes:e.notes})}):null,Rr(e)?o.jsx("button",{className:"send-btn stop",title:"stop this turn","aria-label":"stop this turn",onClick:()=>X.send({t:"cancel",sessionId:e.info.id}),children:o.jsx(Am,{size:14})}):o.jsx("button",{className:"send-btn",onClick:Xe,disabled:!n.trim()&&!k.length||e.resuming||!e.info.cold&&e.info.status!=="ready",title:e.resuming?"正在唤醒 agent 进程…":e.info.cold?"唤醒会话 (Enter)":"send (Enter)","aria-label":"send",children:o.jsx(Dm,{size:16})})]})]})]})]})}function A5({backend:e}){const t=ah(e),[s,n]=_.useState(!1);return o.jsx("span",{className:"be-card-mark","data-backend":e,"data-letter":t.letter,children:t.icon&&!s?o.jsx("img",{src:t.icon,alt:"",draggable:!1,onError:()=>n(!0)}):t.letter})}function D5({cwd:e,onClose:t}){Wo(!0,t);const[s,n]=_.useState(""),[i,r]=_.useState(e??""),a=e??"",[l,c]=_.useState(""),[u,h]=_.useState([]),[d,p]=_.useState(""),[f,m]=_.useState(!1),[y,x]=_.useState(""),[g,v]=_.useState(!0),[b,w]=_.useState([]),[k,j]=_.useState(!1),[I,A]=_.useState(!1),[D,O]=_.useState(null),[F,C]=_.useState(null),[N,P]=_.useState(null),[B,T]=_.useState(null),[$]=lr(),E=Fm(),z=E.status==="listening"||E.status==="recording"||E.status==="requesting",H=_.useRef(!1),ne=_.useRef(null),ae=_.useRef(null);_.useEffect(()=>{const W=ne.current;W&&(W.style.height="42px",W.style.height=`${Math.min(W.scrollHeight,window.innerHeight*.4)}px`)},[l]);const G=()=>{v(!0),x(""),Promise.all([X.loadBackends(),fetch("/api/version",{cache:"no-store"}).then(W=>W.json()).catch(()=>({dev:!1})),fetch("/api/fs/dirs",{cache:"no-store"}).then(W=>W.json()).catch(()=>({}))]).then(([W,he,Ae])=>{w(W),j(!!he?.dev),n(Oe=>Oe||qv(W,!!he?.dev)[0]?.id||""),r(Oe=>Oe||Ae?.home||"")}).catch(W=>x(`后端列表拉取失败:${String(W.message??W)}`)).finally(()=>v(!1))};_.useEffect(G,[]),_.useLayoutEffect(()=>(we.setOwner("start"),()=>we.setOwner("chat")),[]),_.useEffect(()=>{if(!we.owns("start")||E.status!=="idle"||!E.text)return;const W=we.consume();W&&(c(he=>he.trim()?`${he.trim()} ${W}`:W),ne.current?.focus())},[E.status,E.text]);const q=qv(b,k),te=b.find(W=>W.id===s)??null,ue=te?.handshake??null,Ie=ue?.configOptions??[],lt=Cl(Ie,"effort"),Je=lt?.options??[],$e=F??String(lt?.currentValue??""),Ze=lt?E1($e,Je):null,Xe=Je.find(W=>String(W.value)===$e)?.name??"",xe=ue?.modes?.available??[],Se=N??ue?.modes?.currentModeId??"",Fe=Se?ue?.modes?.names?.[Se]??Se:"默认权限",je=ue?.models?.available??[],ht=D??ue?.models?.currentModelId??"",fe=ht?Pm(ht):"默认模型",Qe=()=>{const W=[];return D&&W.push({kind:"model",value:D}),F&<&&W.push({kind:"config",id:String(lt.id),value:F}),N&&W.push({kind:"mode",value:N}),W},ke=async W=>{const he=Array.from(W);if(!he.length)return;const Ae=await Promise.all(he.map(R=>S1(R))),Oe=[],Y=[];for(const R of Ae)"error"in R?Y.push(R.error):Oe.push(R);Oe.length&&h(R=>[...R,...Oe]),p(Y.join(" · "))},be=async()=>{const W=l.trim();if(!(!W&&!u.length||!s||!i.trim())){m(!0),x("");try{z&&we.stop();const he=u.map(Oe=>Oe.kind==="image"?{kind:"image",mimeType:Oe.mimeType,data:Oe.payload,name:Oe.name}:{kind:"text",name:Oe.name,text:Oe.payload}),Ae=await X.createSession(s,i.trim(),"");X.queueSetup(Ae,Qe()),X.setActive(Ae),X.enqueuePrompt(Ae,W,he),t()}catch(he){x(String(he.message??he))}finally{m(!1)}}};return o.jsx("div",{className:"modal-bg",onClick:t,children:o.jsxs("div",{className:"modal start-page",onClick:W=>W.stopPropagation(),children:[o.jsxs("div",{className:"start-head",children:[o.jsx("h3",{children:"新建会话"}),o.jsx(JD,{value:a||i,onChange:r,locked:!!a})]}),o.jsx("div",{className:"composer start-composer",onPaste:W=>{const he=k1(W.clipboardData);he.length&&(W.preventDefault(),ke(he))},children:o.jsxs("div",{className:"composer-inner",children:[u.length>0&&o.jsxs("div",{className:"draft-row",children:[u.map(W=>o.jsxs("span",{className:`draft ${W.kind}`,title:`${W.name} · ${C1(W.bytes)}`,children:[W.preview?o.jsx("img",{src:W.preview,alt:W.name}):o.jsx(Jn,{size:13}),o.jsx("span",{className:"draft-name",children:W.name}),o.jsx("button",{className:"draft-x","aria-label":`remove ${W.name}`,onClick:()=>h(he=>he.filter(Ae=>Ae.id!==W.id)),children:o.jsx(wn,{size:11})})]},W.id)),o.jsx("button",{className:"draft-clear",onClick:()=>h([]),children:"clear"})]}),d&&o.jsx("div",{className:"composer-note err",children:d}),o.jsxs("div",{className:"composer-box",children:[o.jsx("textarea",{ref:ne,rows:1,autoFocus:!0,value:l,"aria-label":"first message",placeholder:"say something to start… (Enter sends)",onChange:W=>c(W.target.value),onCompositionStart:()=>{H.current=!0},onCompositionEnd:()=>{H.current=!1},onKeyDown:W=>{H.current||W.nativeEvent.isComposing||W.key==="Enter"&&!W.shiftKey&&(W.preventDefault(),be())}}),o.jsxs("div",{className:"composer-bar",children:[o.jsx("input",{ref:ae,type:"file",multiple:!0,hidden:!0,accept:`${pg.join(",")},.txt,.md,.json,.log,.csv,.ts,.tsx,.js,.jsx,.py,.rb,.go,.rs,.java,.c,.cpp,.h,.sh,.yaml,.yml,.toml,.ini,.html,.css`,onChange:W=>{const he=W.target.files;he&&he.length?ke(he):p("选择器没有返回文件 —— 再试一次,或从相册 / 文件管理里选"),W.target.value=""}}),o.jsx("button",{className:"icon-btn",title:"attach an image or a text file","aria-label":"attach",onClick:()=>ae.current?.click(),children:o.jsx(_u,{size:16})}),lt&&Je.length?o.jsxs("div",{className:"tb-wrap",style:{"--effort":Ze?.color},children:[o.jsxs("button",{type:"button",className:`tb-btn tb-effort ${B==="effort"?"on":""}`,style:{color:$e?Ze?.color:void 0},title:`thinking depth — ${Xe||"agent default"}`,"aria-label":`thinking depth: ${Xe||"agent default"}`,"aria-expanded":B==="effort","data-testid":"start-effort",onClick:()=>T(W=>W==="effort"?null:"effort"),children:[o.jsx(N1,{level:Ze?.level??0,total:Ze?.total??1,color:Ze?.color??"var(--text-dim)"}),o.jsx(Io,{size:11,className:"tb-chev"})]}),B==="effort"?o.jsx(Bu,{items:Je.map((W,he)=>({value:String(W.value),name:String(W.name??W.value),hint:null,color:ir[Math.min(he,ir.length-1)]})),current:$e,empty:"the agent advertises no levels",onPick:W=>{C(W),T(null)}}):null]}):null,xe.length?o.jsxs("div",{className:"tb-wrap",children:[o.jsxs("button",{type:"button",className:`tb-btn ${B==="mode"?"on":""}`,title:`权限模式 — ${Fe}`,"aria-label":`permission mode: ${Fe}`,"aria-expanded":B==="mode","data-testid":"start-mode",onClick:()=>T(W=>W==="mode"?null:"mode"),children:[o.jsx(Mw,{size:14}),o.jsx("span",{className:"tb-label",children:Fe}),o.jsx(Io,{size:11,className:"tb-chev"})]}),B==="mode"?o.jsx(Bu,{items:xe.map(W=>({value:W,name:ue?.modes?.names?.[W]??W})),current:Se,empty:"the agent lists no modes",onPick:W=>{P(W),T(null)}}):null]}):null,je.length?o.jsx(R1,{label:"model",title:`model — ${fe}`,icon:o.jsx(Im,{size:15}),value:fe,testId:"start-model",open:B==="model",onToggle:()=>T(W=>W==="model"?null:"model"),children:o.jsx(zw,{models:je.map(W=>({modelId:W})),current:ht,onPick:W=>{O(W),T(null)}})}):null,o.jsx("span",{className:"head-spacer"}),o.jsx("button",{className:`icon-btn ${z?"on rec":""}`,title:E.error?E.error:z?"stop dictation":"dictate a prompt","aria-label":"dictate",onClick:()=>{we.cancel(),we.start($)},children:o.jsx(sr,{size:16})}),o.jsx("button",{className:"send-btn",onClick:()=>void be(),disabled:f||!l.trim()&&!u.length||!i.trim(),title:f?"创建中…":"创建并发送 (Enter)","aria-label":"send",children:o.jsx(Dm,{size:16})})]})]}),z||E.status==="transcribing"||E.error?o.jsxs("div",{className:`dict-chip ${E.error?"err":""}`,children:[o.jsx(sr,{size:13}),E.error?E.error:E.status==="requesting"?"waiting for the microphone…":E.status==="transcribing"?"transcribing…":o.jsxs(o.Fragment,{children:[E.text," ",o.jsx("span",{className:"interim",children:E.interim})]}),z?o.jsx("button",{className:"dict-stop",onClick:()=>we.stop(),children:"stop"}):null]}):null]})}),o.jsxs("div",{className:"backend-pick",role:"radiogroup","aria-label":"backend",children:[g&&!b.length&&o.jsx("span",{className:"dim",children:"loading…"}),!g&&!q.length&&o.jsx("span",{className:"dim",children:"no backends"}),q.map(W=>o.jsxs("button",{type:"button",role:"radio","aria-checked":s===W.id,"data-backend":W.id,title:W.home?`${W.label} · home: ${W.home}`:W.label,className:`be-card ${s===W.id?"sel":""}`,onClick:()=>n(W.id),children:[o.jsx(A5,{backend:W.kind||W.id}),o.jsx("span",{className:"be-card-label",children:W.label})]},W.id)),o.jsx("button",{type:"button",className:"be-card reload",title:"重新拉取后端列表","aria-label":"重新拉取后端列表",onClick:G,children:"⟳"})]}),(te?.warnings??[]).map((W,he)=>o.jsx("div",{className:"hint-warn",children:W},he)),te?o.jsxs("div",{className:`be-detail ${I?"open":""}`,children:[o.jsxs("button",{type:"button",className:"be-detail-head","aria-expanded":I,onClick:()=>A(W=>!W),children:[o.jsx(en,{size:12,className:"be-detail-arrow"})," 后端详情"]}),I?o.jsxs("div",{className:"hint be-hint",children:[o.jsxs("div",{children:["runs: ",o.jsxs("code",{children:[te.cmd," ",(te.args??[]).join(" ")]}),te.profile?o.jsxs(o.Fragment,{children:[" · profile ",o.jsx("code",{children:te.profile})]}):null]}),te.home?o.jsxs("div",{children:["home: ",o.jsx("code",{children:te.home})]}):null,te.cwd?o.jsxs("div",{children:["cwd: ",o.jsx("code",{children:te.cwd})]}):null,(te.env??[]).length?o.jsxs("div",{children:["env: ",o.jsx("code",{children:(te.env??[]).join(", ")})]}):null,ue&&!Ie.length&&!je.length?o.jsx("div",{children:"这个后端还没真跑过,所以没有可选的模型 / 设置 —— 建会话后由 agent 自己的清单决定"}):null]}):null]}):null,y&&o.jsx("div",{className:"err",children:y})]})})}DA();window.__cockpit=X;window.__voice={dictation:we,loadVoiceCaps:vu,resampleToPcm16:Xw,voiceCaps:Vn};window.__renderMarkdown=Xm;Ew(document.getElementById("root")).render(o.jsx(K1.StrictMode,{children:o.jsx(zP,{})}));
|