diff --git a/cloud/console-react/src/tokens.css b/cloud/console-react/src/tokens.css
index e7d56bf..b988ac6 100644
--- a/cloud/console-react/src/tokens.css
+++ b/cloud/console-react/src/tokens.css
@@ -123,6 +123,14 @@ pre{background:var(--inset-bg);color:var(--text);border:1px solid var(--line);bo
.search-box input:focus{box-shadow:none}
.list-section-head{display:flex;align-items:center;justify-content:space-between;font-size:14px;font-weight:600;margin:12px 0 4px}
.issue-list{list-style:none;margin:0;padding:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden}
+/* Unbounded lists get their own scrollbar instead of stretching the
+ whole column (and the whole page) indefinitely: the task list is
+ capped at 60vh, the API Key list at 320px. Search/filter bars sit
+ outside these containers, so they stay visible while the list
+ scrolls. overscroll-behavior:contain keeps a list scroll from
+ immediately dragging the page (or the column) with it. */
+.issue-list{max-height:60vh;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}
+.api-key-list{max-height:320px;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:8px}
.issue-item{padding:8px 16px;border-bottom:1px solid var(--line);cursor:pointer;display:flex;gap:10px;align-items:flex-start;background:#fff}
.issue-item:last-child{border-bottom:0}
.issue-item:hover{background:var(--subtle-bg)}
@@ -190,15 +198,26 @@ pre{background:var(--inset-bg);color:var(--text);border:1px solid var(--line);bo
every grid width. Nothing is duplicated or hidden at any width. */
.dash-col{display:flex;flex-direction:column;gap:20px;min-width:0}
.dash-col > *{min-width:0}
+/* Equal-height columns (wide/medium only; narrow stays a single
+ page-scrolled column, see the max-width:899px block): every column
+ is the same fixed height — viewport height minus the sticky
+ topbar, the data-cards row and page padding (260px, floored at
+ 480px so short viewports still get a usable pane) — and scrolls
+ internally when its sections exceed it, instead of growing
+ indefinitely and leaving the other columns ending far above it.
+ Together with the capped task/API Key lists above, no single
+ list can push one column (and the page) to infinite height. */
@media (min-width:900px) and (max-width:1399px){
- .dash-page{display:grid;grid-template-columns:320px minmax(0,1fr);align-items:start}
+ .dash-page{display:grid;grid-template-columns:320px minmax(0,1fr);align-items:stretch}
.dash-page > .dash-cards{grid-column:1 / -1;grid-row:1}
+ .dash-col{height:calc(100vh - 260px);min-height:480px;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}
.dash-col-left{grid-column:1;grid-row:2}
.dash-col-mid{grid-column:2;grid-row:2}
.dash-col-right{grid-column:2;grid-row:3}
}
@media (min-width:1400px){
- .dash-page{max-width:1560px;display:grid;grid-template-columns:310px minmax(0,1fr) 330px;align-items:start}
+ .dash-page{max-width:1560px;display:grid;grid-template-columns:310px minmax(0,1fr) 330px;align-items:stretch}
+ .dash-col{height:calc(100vh - 260px);min-height:480px;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}
.dash-page > .dash-cards{grid-column:1 / -1;grid-row:1}
.dash-cards{grid-template-columns:repeat(6,1fr)}
.dash-col-left{grid-column:1;grid-row:2}
diff --git a/cloud/console.html b/cloud/console.html
index 7d5f77e..7504ba5 100644
--- a/cloud/console.html
+++ b/cloud/console.html
@@ -69,8 +69,8 @@ Error generating stack: `+a.message+`
`),D.error_text&&(L+=`=== error ===
`+D.error_text.slice(0,8e3)+`
`),C(L||"(暂无 result/error 输出)")}catch{}Kt(H.id),Pe(H.id),we(H.id),Tl(H.id),da(H),sl(H.id),fl(H.id),kt(H.id),Ul(H.id),Dl(H.id)}},[Kt,Pe,we,Tl,da,sl,fl,kt,Ul,Dl]),ma=v.useCallback(async H=>{const D=ue.current;if(!D)return;const L={cancel:"确定取消该任务吗?",merge:"确定把 completed 任务标为 merged 吗?",pr:"确定为该任务提 PR 吗?(会在仓库真实建 PR)"};if(!(L[H]&&!window.confirm(L[H])))try{const J=await lt(P.taskAction(D.id,H),"POST",{});b(H+" 已提交:"+JSON.stringify(J).slice(0,300)),r(),await Se(D.id)}catch(J){b(H+" 失败:"+J.message)}},[Se,r]),su=v.useCallback(async()=>{const H=ue.current;if(H)try{const D=await lt(P.taskCost(H.id));j(JSON.stringify(D,null,2).slice(0,4e3))}catch(D){j("查成本失败:"+D.message)}},[]),fu=v.useCallback(async H=>{const D=ue.current;if(D){if(!H.trim()){dt("分支消息必填");return}if(!uu.includes(D.status)){dt("仅终态任务可分支");return}try{const L=await lt(P.taskFork(D.id),"POST",{message:H.trim()});dt("分支任务已建:"+L.id.slice(0,8)),r()}catch(L){dt("分支失败:"+L.message)}}},[r]),Fl=v.useCallback(async H=>{const D=ue.current;if(D)try{await lt(P.taskReviews(D.id),"POST",H),Vt("评审已登记(requested)"),await we(D.id)}catch(L){Vt("登记评审需求失败:"+L.message)}},[we]),Ne=v.useCallback(H=>{const D=ue.current;if(!D)return;const L=window.prompt("输入该条评审的 findings(将写回记录并标为 completed):");L!==null&<(P.taskReviewFindings(D.id,H),"POST",{findings:L}).then(()=>void we(D.id)).catch(J=>Vt("写 findings 失败:"+J.message))},[we]),rl=v.useCallback((H,D)=>{const L=ue.current;if(!L)return;const J=D==="approved"?"approve":"deny";lt(P.taskApprovalDecision(L.id,H,J),"POST",{}).then(()=>{mt("已记录"+(D==="approved"?"允许":"拒绝")+"(当前版本只留回执,不拦截实时行为)"),Tl(L.id)}).catch(O=>mt("决定失败:"+O.message))},[Tl]),Ce=v.useCallback(async(H,D,L)=>{const J=ue.current;if(J){if(!D.trim()){ne("目标任务 id 不能为空");return}if(!L.trim()){ne("消息正文不能为空");return}try{const O=await lt(P.taskMessagesTo(D.trim()),"POST",{from_task_id:J.id,body:L.trim(),mode:H});ne("已发送("+O.delivery+")"),await fl(J.id)}catch(O){ne("发送失败:"+O.message)}}},[fl]),ru=v.useCallback((H,D)=>{const L=ue.current;if(!L)return;if(!["completed","failed","interrupted"].includes(L.status)){de("仅 completed/failed/interrupted 任务可操作线程(merged/merge-failed 不可改,服务端同样 409)");return}const J={};if(H==="rename"){if(!D.trim()){de("新线程名不能为空");return}J.name=D.trim()}lt(P.taskThreadAction(L.id,H),"POST",J).then(O=>{de(H+" 已提交:"+JSON.stringify(O).slice(0,300)),kt(L.id),Ul(L.id)}).catch(O=>de(H+" 失败:"+O.message))},[kt,Ul]),ou=v.useCallback(async H=>{const D=ue.current;if(!D)return;const L=H.trim();if(!L){Ve("消息不能为空");return}try{uu.includes(D.status)&&D.status!=="merged"?(await lt(P.taskContinue(D.id),"POST",{message:L}),Ve("已重新排队,同一会话继续"),r(),await Se(D.id)):["queued","running"].includes(D.status)?(await lt(P.taskFollowups(D.id),"POST",{body:L,mode:"direct"}),Ve("已直接发送"),await Kt(D.id),await Pe(D.id)):Ve("merged/merge-failed 任务不可继续,也不可发后续消息")}catch(J){Ve("发送失败:"+J.message)}},[Se,r,Kt,Pe]),du=v.useCallback(async()=>{const H=ue.current;if(!H){Ee("先选一个任务");return}try{const D=await lt(P.taskTrace(H.id)),L=new Blob([JSON.stringify({task_id:H.id,status:D.status,note:D.note||"",count:(D.entries||[]).length,entries:D.entries||[]},null,2)],{type:"application/json"}),J=document.createElement("a");J.href=URL.createObjectURL(L),J.download="trace-"+H.id.slice(0,8)+".json",document.body.appendChild(J),J.click(),J.remove(),setTimeout(()=>URL.revokeObjectURL(J.href),1e3),Ee("已下载完整链路 "+(D.entries||[]).length+" 条")}catch(D){Ee("下载失败:"+D.message)}},[]);return v.useEffect(()=>()=>ie(),[ie]),{currentTask:m,detailBody:_,actionMsg:N,actionReasons:B,costBox:k,costSummary:q,forkVisible:X,setForkVisible:W,forkMsg:G,coordChildren:Mt,agents:nt,agentsNote:ee,reviews:yt,reviewMsg:ve,reviewError:Wt,traceEntries:Ie,traceNote:Y,traceDone:at,traceKind:St,setTraceKind:ye,traceMsg:He,followups:y,approvals:I,approvalMsg:pt,peerMessages:_t,peerMsg:ut,threadText:Ga,threadGateNote:Xe,threadMsg:zt,threadList:Kl,chatMsg:oa,chatHistory:zl,showDetail:Se,refreshDetailLists:Xa,doAction:ma,taskCost:su,forkTask:fu,postReview:Fl,submitFindings:Ne,decideApproval:rl,postPeer:Ce,threadAction:ru,sendChatMessage:ou,downloadTrace:du,refreshReviews:()=>void we(),refreshApprovals:()=>void Tl()}}function Iy(i){const[r,m]=v.useState([]),[o,_]=v.useState(""),[C,N]=v.useState(null),[b,B]=v.useState(""),U=v.useCallback(async tt=>{const X=tt!==void 0?tt:i();if(!X){m([]);return}try{const W=await lt(P.projectAutomations(X));m(W.automations||[])}catch(W){_("自动化加载失败:"+W.message)}},[i]),k=v.useCallback(async(tt,X,W,G)=>{const dt=i();if(!dt){_("先选项目");return}if(!tt.trim()){_("自动化名称必填");return}if(!X.trim()){_("定时任务内容必填");return}const Mt={name:tt.trim(),prompt:X.trim()};W.trim()&&(Mt.interval_seconds=parseInt(W.trim(),10)),G.trim()&&(Mt.repo_url=G.trim());try{await lt(P.projectAutomations(dt),"POST",Mt),_("自动化已创建(登记定义,到期后由执行器认领)"),await U(dt)}catch(Ft){_("创建失败:"+Ft.message)}},[i,U]),j=v.useCallback(tt=>{const X=i();X&<(P.projectAutomationCancel(X,tt),"POST",{}).then(()=>{_("自动化已取消"),U(X)}).catch(W=>_("取消失败:"+W.message))},[i,U]),q=v.useCallback(async tt=>{const X=tt!==void 0?tt:i();if(!X){N(null);return}try{const W=await lt(P.projectTriage(X));N(W),B("")}catch(W){B("分诊加载失败:"+W.message)}},[i]);return{automations:r,autoMsg:o,triage:C,triageError:b,refreshAutomations:U,createAutomation:k,cancelAutomation:j,refreshTriage:q}}function Py(i,r){const m=v.useRef(i);m.current=i,v.useEffect(()=>{const o=setInterval(()=>{const _=document.activeElement;m.current(_?_.tagName==="SELECT":!1)},r);return()=>clearInterval(o)},[r])}function tg(i,r){const m=v.useRef(i);m.current=i,v.useEffect(()=>{const o=setInterval(()=>m.current(),r);return()=>clearInterval(o)},[r])}function eg(i){const r=m=>String(m).padStart(2,"0");return r(i.getHours())+":"+r(i.getMinutes())+":"+r(i.getSeconds())}function lg(){var W;const i=Fy(),r=Wy(),m=v.useRef("");m.current=i.projectId;const o=v.useCallback(()=>m.current,[]),_=Iy(o),C=v.useCallback(G=>{const dt=i.projects.find(Mt=>Mt.id===G);return dt&&dt.my_role||null},[i.projects]),N=v.useCallback(()=>{r.refreshTasks(void 0,m.current)},[r]),b=$y(C,N),[B,U]=v.useState("--:--:--"),k=v.useCallback(G=>{i.setProjectId(G),m.current=G,r.refreshTasks(G),i.refreshEnvs(G),i.refreshMembers(G),i.refreshSkills(G),_.refreshAutomations(G),_.refreshTriage(G)},[i,r,_]),j=(W=i.projects[0])==null?void 0:W.id;v.useEffect(()=>{!i.projectId&&j&&k(j)},[i.projectId,j,k]);const q=v.useCallback(G=>{i.saveKeyInput(G),G.trim()&&(i.refreshHealth(),i.refreshProjects(),i.refreshWorkers(),m.current&&(r.refreshTasks(m.current),i.refreshEnvs(m.current),i.refreshMembers(m.current)),i.loadRelayModels(),i.loadQuota(),i.loadGithubRepos(),i.probeAdmin())},[i,r]),tt=v.useCallback(G=>{if(U(eg(new Date)),!bl()){i.refreshHealth();return}r.refreshTasks(void 0,m.current),i.refreshHealth(),i.loadQuota(),i.refreshWorkers(),i.refreshMembers(),i.refreshSkills(),_.refreshAutomations(),_.refreshTriage(),b.refreshDetailLists(),G||(i.refreshProjects(),i.refreshEnvs())},[i,r,_,b]),X=v.useCallback(()=>{bl()&&(i.loadRelayModels(),i.loadGithubRepos())},[i]);return v.useEffect(()=>{i.refreshHealth(),i.refreshProjects(),i.refreshWorkers(),i.loadQuota(),i.loadGithubRepos(),bl()&&i.loadRelayModels(),i.probeAdmin()},[]),{keySaved:i.keySaved,keyState:i.keyState,saveKeyInput:q,clearKeyInput:i.clearKeyInput,quotaText:i.quotaText,healthText:i.healthText,refreshHealth:i.refreshHealth,adminGate:i.adminGate,adminBody:i.adminBody,adminResult:i.adminResult,adminUserId:i.adminUserId,setAdminUserId:i.setAdminUserId,adminQuota:i.adminQuota,adminSweep:i.adminSweep,adminBackup:i.adminBackup,projects:i.projects,projectId:i.projectId,projectMsg:i.projectMsg,selectProject:k,refreshProjects:i.refreshProjects,createProject:i.createProject,githubRepos:i.githubRepos,workers:i.workers,workersSummary:i.workersSummary,workersError:i.workersError,refreshWorkers:i.refreshWorkers,members:i.members,memberMsg:i.memberMsg,memberError:i.memberError,refreshMembers:()=>void i.refreshMembers(),inviteMember:i.inviteMember,changeMemberRole:i.changeMemberRole,skills:i.skills,apps:i.apps,mcpServers:i.mcpServers,skillMsg:i.skillMsg,skillError:i.skillError,mcpMsg:i.mcpMsg,mcpOauthMsg:i.mcpOauthMsg,mcpOauthBox:i.mcpOauthBox,refreshSkills:()=>void i.refreshSkills(),reloadMcp:i.reloadMcp,mcpOauth:i.mcpOauth,envs:i.envs,envCount:i.envCount,envMsg:i.envMsg,envRepoLine:i.envRepoLine,envRepoBar:i.envRepoBar,envRepoMsg:i.envRepoMsg,envSelect:i.envSelect,setEnvSelect:i.setEnvSelect,refreshEnvs:()=>void i.refreshEnvs(),createEnv:i.createEnv,archiveEnv:i.archiveEnv,saveEnvRepo:i.saveEnvRepo,models:i.models,modelCustomVisible:i.modelCustomVisible,tasks:r.tasks,taskCountText:r.taskCountText,taskError:r.taskError,refreshTasks:()=>void r.refreshTasks(void 0,m.current),statusFilter:r.statusFilter,setStatusFilter:r.setStatusFilter,executorFilter:r.executorFilter,setExecutorFilter:r.setExecutorFilter,searchText:r.searchText,setSearchText:r.setSearchText,filteredTasks:r.filteredTasks,currentTask:b.currentTask,detailBody:b.detailBody,actionMsg:b.actionMsg,actionReasons:b.actionReasons,showDetail:G=>void b.showDetail(G),doAction:b.doAction,taskCost:b.taskCost,costBox:b.costBox,costSummary:b.costSummary,forkVisible:b.forkVisible,setForkVisible:b.setForkVisible,forkTask:b.forkTask,forkMsg:b.forkMsg,coordChildren:b.coordChildren,coordText:"",agents:b.agents,agentsNote:b.agentsNote,reviews:b.reviews,reviewMsg:b.reviewMsg,reviewError:b.reviewError,refreshReviews:b.refreshReviews,postReview:b.postReview,submitFindings:b.submitFindings,traceEntries:b.traceEntries,traceNote:b.traceNote,traceDone:b.traceDone,traceKind:b.traceKind,setTraceKind:b.setTraceKind,downloadTrace:b.downloadTrace,traceMsg:b.traceMsg,sendChatMessage:b.sendChatMessage,chatMsg:b.chatMsg,chatHistory:b.chatHistory,followups:b.followups,approvals:b.approvals,approvalMsg:b.approvalMsg,refreshApprovals:b.refreshApprovals,decideApproval:b.decideApproval,peerMessages:b.peerMessages,peerMsg:b.peerMsg,postPeer:b.postPeer,automations:_.automations,autoMsg:_.autoMsg,refreshAutomations:()=>void _.refreshAutomations(),createAutomation:_.createAutomation,cancelAutomation:_.cancelAutomation,triage:_.triage,triageError:_.triageError,refreshTriage:()=>void _.refreshTriage(),threadText:b.threadText,threadGateNote:b.threadGateNote,threadMsg:b.threadMsg,threadList:b.threadList,threadAction:b.threadAction,dispatch:async(G,dt)=>{const Mt=await r.dispatch(G,dt);return r.refreshTasks(m.current),Mt},dispatchMsg:"",refreshAll:tt,refreshSlow:X,refreshStamp:B}}function nu({label:i,value:r,sub:m}){return c.jsxs("div",{className:"dash-card data-card",children:[c.jsx("div",{className:"dash-card-label",children:i}),c.jsx("div",{className:"dash-card-value",children:r}),c.jsx("div",{className:"muted",children:m})]})}function ag(){const i=Ut(),r=i.healthText==="未加载"?"未加载":i.healthText.includes("worker_ok=true")?"正常":i.healthText.includes("worker_ok=false")?"异常":i.healthText.includes("加载失败")?"加载失败":"未知",m=i.quotaText.match(/剩余 \$([0-9.]+)/),o=i.quotaText.includes("加载失败")?"加载失败":i.quotaText.includes("未填 key")||i.quotaText==="未加载"?"未加载":m?"$"+m[1]:"配额",_=["running","completed","failed","queued","merged","interrupted"].map(j=>i.tasks.filter(q=>q.status===j).length).map((j,q)=>["running","completed","failed","queued","merged","interrupted"][q]+" "+j).join(" | "),C=i.projects.find(j=>j.id===i.projectId),N=i.taskError?{value:"加载失败",sub:i.taskError}:i.projectId?{value:String(i.tasks.length),sub:i.taskCountText+" | "+_+(C?" | "+C.name:"")}:{value:"先选项目",sub:i.projectMsg||"项目加载后自动选第一个"};let b;if(i.workersError)b={value:"加载失败",sub:i.workersError};else if(i.workers===null)b={value:i.workersSummary||"未加载",sub:"完整 worker 清单仅全局管理员可见"};else{const j=i.workers.filter(q=>{if(q.alive!==void 0&&q.alive!==null)return!!q.alive;const tt=Qh(q).age;return tt!==null&&tt<=120}).length;b={value:j+" 在线 / "+i.workers.length,sub:i.workers.length-j+" 离线"}}const B=i.projectMsg.includes("加载失败")?{value:"加载失败",sub:i.projectMsg}:{value:i.projects.length+" 个",sub:C?"当前项目:"+C.name:"未选项目(加载后自动选第一个)"},U=[i.envMsg,i.memberError,i.skillError].filter(j=>j&&j.includes("失败")),k=i.projectId?U.length?{value:"部分加载失败",sub:U.join(" | ")}:{value:i.envs.length+" 个环境",sub:i.members.length+" 成员 | "+i.skills.length+" 技能 | "+i.apps.length+" 应用 | "+i.mcpServers.length+" MCP"}:{value:"先选项目",sub:"选项目后显示环境 / 成员 / 技能计数"};return c.jsxs("section",{className:"dash-cards","aria-label":"数据卡片",children:[c.jsx(nu,{label:"健康",value:r,sub:i.healthText}),c.jsx(nu,{label:"配额",value:o,sub:i.quotaText}),c.jsx(nu,{label:"任务",value:N.value,sub:N.sub}),c.jsx(nu,{label:"Workers",value:b.value,sub:b.sub}),c.jsx(nu,{label:"项目",value:B.value,sub:B.sub}),c.jsx(nu,{label:"项目数据",value:k.value,sub:k.sub})]})}function Zt({id:i,className:r,title:m,children:o}){return c.jsxs("section",{id:i,className:"card"+(r?" "+r:""),children:[m?c.jsx("h2",{children:m}):null,o]})}function Dt({children:i}){return c.jsx("div",{className:"bar",children:i})}function Ml({items:i,empty:r}){return i.length?c.jsx("ul",{className:"data-list",children:i.map((m,o)=>c.jsx("li",{children:m},o))}):c.jsx("div",{className:"muted",children:r||"(暂无)"})}function cu({children:i}){return c.jsx("ul",{className:"data-list",children:i})}function ng(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(!1),[b,B]=v.useState(!1),[U,k]=v.useState(!1),[j,q]=v.useState("docker"),[tt,X]=v.useState(""),[W,G]=v.useState(""),[dt,Mt]=v.useState(""),[Ft,nt]=v.useState(""),[Xt,ee]=v.useState(""),[ct,yt]=v.useState(""),[oe,ve]=v.useState(""),Vt=v.useRef(null),Wt=v.useRef(null),ae=v.useRef(null),[Ie,vt]=v.useState("");async function Y(){var He,Ee,y;if(vt(""),!i.projectId){vt("先选项目");return}if(!r.trim()){vt("prompt 必填");return}const A={project_id:i.projectId,prompt:r.trim()};i.envSelect&&(A.environment_id=i.envSelect),j&&(A.executor=j);const at=W.trim()||tt;at&&(A.model=at),dt&&(A.effort=dt);const gt=ct.trim()||Xt;if(gt&&(A.child_model=gt),oe&&(A.child_effort=oe),Ft&&(A.approval=Ft),U){if(Ft==="full"){vt("计划模式不能与完全访问同用");return}if(C||b){vt("计划模式不能与 goal 模式同用");return}A.plan=1}b?(A.goal_mode=1,A.no_time_limit=1):C&&(A.goal_mode=1);const St=o.trim();if(St){try{A.coordinator_parts=JSON.parse(St)}catch{vt("协调员子任务 JSON 解析失败");return}if(!Array.isArray(A.coordinator_parts)){vt("协调员子任务必须是数组");return}if(C||b||U){vt("协调员任务不能与 goal/计划模式同用:协调员任务本身不跑模型回合,请取消 goal/计划勾选,或清空协调员 JSON");return}}const ye=Jy(((He=Vt.current)==null?void 0:He.files)||null,((Ee=Wt.current)==null?void 0:Ee.files)||null,((y=ae.current)==null?void 0:y.files)||null);try{const R=await i.dispatch(A,ye);vt(R),m(""),_(""),Vt.current&&(Vt.current.value=""),Wt.current&&(Wt.current.value=""),ae.current&&(ae.current.value="")}catch(R){vt("提交失败:"+((R==null?void 0:R.message)||String(R)))}}return c.jsxs(Zt,{id:"nav-newtask",className:"composer",title:"新建任务",children:[c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"环境",value:i.envSelect,onChange:A=>i.setEnvSelect(A.target.value),children:[c.jsx("option",{value:"",children:"环境:不指定(走项目仓库)"}),i.envs.map(A=>c.jsxs("option",{value:A.id,disabled:A.status!=="ready",children:[A.name,"(",A.status,")"]},A.id))]}),c.jsxs("select",{"aria-label":"执行器",value:j,onChange:A=>q(A.target.value),children:[c.jsx("option",{value:"docker",children:"docker(默认,多用户下隔离最强)"}),c.jsx("option",{value:"local",children:"local"}),c.jsx("option",{value:"cloud",children:"cloud"})]}),c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:C,onChange:A=>N(A.target.checked)})," goal 模式"]}),c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:b,onChange:A=>B(A.target.checked)})," goal 模式无敌版"]}),c.jsxs("label",{children:[c.jsx("input",{type:"checkbox",checked:U,onChange:A=>k(A.target.checked)})," 计划模式(只读)"]})]}),c.jsx("textarea",{className:"prompt stacked",placeholder:"任务 prompt(必填)",value:r,onChange:A=>m(A.target.value)}),c.jsx("textarea",{className:"coord stacked",placeholder:"协调员子任务 JSON(可选),留空为普通任务",value:o,onChange:A=>_(A.target.value)}),c.jsxs("div",{className:"muted",children:["协调员格式:[","{",'"name":"后端","prompt":"做后端"',"}",",","{",'"name":"前端","prompt":"做前端"',"}","];提交后 worker 并行建子任务、等齐、合流汇总。不能与 goal/计划模式同用。协调员与 goal/计划互斥:勾了 goal 或计划模式时不要填协调员 JSON,提交前会校验并拦截。子任务费用记父任务创建人账;父任务创建时按分工数预留配额,余额不足时整个父任务被挡下。"]}),c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"模型",value:tt,onChange:A=>X(A.target.value),children:[c.jsx("option",{value:"",children:"模型:默认(跟随配置)"}),i.models.map(A=>c.jsx("option",{value:A,children:A},A))]}),i.modelCustomVisible?c.jsx("input",{type:"text",placeholder:"手动输入模型(中转列表取不到时用)",value:W,onChange:A=>G(A.target.value)}):null,c.jsxs("select",{"aria-label":"推理强度",value:dt,onChange:A=>Mt(A.target.value),children:[c.jsx("option",{value:"",children:"推理强度:默认(跟随配置)"}),wh.map(A=>c.jsx("option",{value:A,children:A},A))]}),c.jsxs("select",{"aria-label":"权限",value:Ft,onChange:A=>nt(A.target.value),children:[c.jsx("option",{value:"",children:"权限:默认(跟随配置)"}),c.jsx("option",{value:"ask",children:"请求批准"}),c.jsx("option",{value:"auto",children:"帮我批准"}),c.jsx("option",{value:"full",children:"完全访问"})]})]}),c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"子任务模型",value:Xt,onChange:A=>ee(A.target.value),children:[c.jsx("option",{value:"",children:"子任务模型:跟随本任务模型"}),i.models.map(A=>c.jsx("option",{value:A,children:A},A))]}),c.jsx("input",{type:"text",placeholder:"子任务模型手动输入(中转列表里没有时填,如 gpt-6-luna;留空=跟随本任务模型)",value:ct,onChange:A=>yt(A.target.value)}),c.jsxs("select",{"aria-label":"子任务强度",value:oe,onChange:A=>ve(A.target.value),children:[c.jsx("option",{value:"",children:"子任务强度:跟随本任务强度"}),wh.map(A=>c.jsx("option",{value:A,children:A},A))]})]}),c.jsx("div",{className:"muted",children:"子任务模型/强度是派生默认:本任务用 marker task-create 或协调员分工派生的子任务,未显式写模型/强度时用它;块/分工里显式写了则覆盖它。也可以不在这里填、直接在 prompt 里写“子任务用 gpt-6-luna max”,建任务时服务端会解析成同一对字段(任务详情里可核对)。"}),C?c.jsx("div",{className:"muted",children:"goal 模式:输入框内容即目标,不需要专用 prompt 与验收命令;不限轮次,模型确认达成后在回复末尾输出“目标已达成”即结束,未达成会一直运行,可用取消停止。"}):null,b?c.jsx("div",{className:"muted",children:"goal 模式无敌版:goal 模式 + 任务不限时(去掉 worker/docker 总超时;单轮 600 秒护栏还在,不限的是任务总时长与总轮次)。服务端默认的自动续跑与断点镜像同时生效。"}):null,c.jsxs(Dt,{children:[c.jsx("span",{className:"muted",children:"附件(放进任务工作区,图片与普通文件不区分):"}),c.jsx("input",{ref:Vt,type:"file",multiple:!0,title:"文件"}),c.jsx("input",{ref:Wt,type:"file",multiple:!0,title:"文件夹",webkitdirectory:""}),c.jsx("input",{ref:ae,type:"file",accept:"image/*",multiple:!0,title:"图片"})]}),c.jsxs(Dt,{children:[c.jsx("button",{className:"seal",onClick:Y,children:"提交任务"}),c.jsx("span",{className:"muted",children:Ie||i.dispatchMsg})]})]})}function Xh(i){const r=(i.prompt||"").trim();return r?[...r][0]:i.id?[...i.id][0]:"?"}function zc(i){const r=Math.max(0,Math.floor(i));if(r<60)return r+"秒";if(r<3600){const _=Math.floor(r/60),C=r%60;return C?_+"分"+C+"秒":_+"分"}if(r<86400){const _=Math.floor(r/3600),C=Math.floor(r%3600/60);return C?_+"小时"+C+"分":_+"小时"}const m=Math.floor(r/86400),o=Math.floor(r%86400/3600);return o?m+"天"+o+"小时":m+"天"}function iu(i){if(i==null)return null;const r=Number(i);return Number.isFinite(r)?r:null}function Vh(i){const r=Date.now()/1e3,m=iu(i.started_at),o=iu(i.finished_at),_=iu(i.created_at);return m!==null&&o!==null&&o>=m?[zc(o-m),"总耗时:开始→结束(末次认领的执行时长)"]:m!==null&&i.status==="running"?["进行中 "+zc(r-m),"总耗时:进行中,已用时长从开始算起,随刷新更新"]:_!==null&&o!==null&&o>=_?[zc(o-_),"总耗时:创建→完成(含排队等待;无开始时间时的兜底口径)"]:_!==null&&(i.status==="queued"||i.status==="running")?[(i.status==="queued"?"排队中 ":"进行中 ")+zc(r-_),"总耗时:从创建算起的已用时长(无开始时间时的兜底口径)"]:["—","总耗时:无可用时间戳"]}function ug(i){if(i==null||!Number.isFinite(Number(i)))return"—";const r=Number(i)/1e6;return"$"+(r>0&&r<.01?r.toFixed(4):r.toFixed(2))}function Lh(i){const r=iu(i.total_tokens);if(r!==null)return[r.toLocaleString()+" token","token:服务端 total_tokens"];const m=iu(i.actual_tokens),o=iu(i.estimated_tokens);return m!==null||o!==null?[((m||0)+(o||0)).toLocaleString()+" token","token:actual + estimated 分项加总"]:["token —","token:本任务对象未带 token 字段;单任务真数在详情的成本里可查,不逐个调成本接口、不编造"]}function ig({onNew:i}){const r=Ut();return c.jsxs("div",{children:[c.jsxs("div",{className:"search-box",children:[c.jsxs("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round","aria-hidden":"true",children:[c.jsx("circle",{cx:"11",cy:"11",r:"7"}),c.jsx("path",{d:"M21 21l-4.3-4.3"})]}),c.jsx("input",{type:"text",placeholder:"搜索","aria-label":"搜索任务",value:r.searchText,onChange:m=>r.setSearchText(m.target.value)})]}),c.jsx("div",{className:"bar",children:c.jsxs("select",{"aria-label":"项目",value:r.projectId,onChange:m=>r.selectProject(m.target.value),children:[r.projects.length===0?c.jsx("option",{value:"",children:"(先加载项目)"}):null,r.projects.map(m=>c.jsxs("option",{value:m.id,children:[m.name," (",Ue(m.id),")"]},m.id))]})}),c.jsxs("div",{className:"list-section-head",children:[c.jsx("span",{children:"主要聊天"}),c.jsx("button",{type:"button","aria-label":"派发新任务",title:"派发新任务",onClick:i,children:"+"})]}),c.jsxs("div",{className:"bar",children:[c.jsxs("select",{"aria-label":"状态筛选",value:r.statusFilter,onChange:m=>r.setStatusFilter(m.target.value),children:[c.jsx("option",{value:"",children:"状态:全部"}),["queued","running","completed","failed","interrupted","merged","merge-failed"].map(m=>c.jsx("option",{value:m,children:m},m))]}),c.jsxs("select",{"aria-label":"执行器筛选",value:r.executorFilter,onChange:m=>r.setExecutorFilter(m.target.value),children:[c.jsx("option",{value:"",children:"执行器:全部"}),c.jsx("option",{value:"local",children:"local"}),c.jsx("option",{value:"docker",children:"docker"}),c.jsx("option",{value:"cloud",children:"cloud"})]})]}),c.jsxs("div",{className:"bar",children:[c.jsx("button",{onClick:r.refreshTasks,children:"刷新"}),c.jsx("span",{className:"muted",children:r.taskCountText})]}),r.taskError?c.jsx("div",{className:"err",children:r.taskError}):r.projectId?r.filteredTasks.length===0?c.jsx("div",{className:"muted",children:r.tasks.length?"没有符合筛选条件的任务":"该项目暂无任务"}):c.jsx("ul",{className:"issue-list",children:r.filteredTasks.slice().reverse().map(m=>{var B;const[o,_]=Vh(m),[C,N]=Lh(m),b=Xh(m);return c.jsxs("li",{className:"issue-item"+(((B=r.currentTask)==null?void 0:B.id)===m.id?" selected":""),onClick:()=>r.showDetail(m.id),children:[c.jsx("span",{className:"issue-state st-"+m.status,"aria-hidden":"true"}),c.jsx("span",{className:"issue-first",title:"任务首字:"+b,"aria-hidden":"true",children:b}),c.jsxs("span",{style:{flex:1,minWidth:0},children:[c.jsxs("div",{className:"issue-title",children:[m.plan?"[计划] ":"",m.forked_from?"[分支] ":"",m.coordinator_parts?"[协调] ":"",m.parent_task_id?"[协调子任务] ":"",String(m.prompt||Ue(m.id)).slice(0,60)]}),c.jsxs("div",{className:"issue-meta",children:[Ue(m.id)," · ",c.jsx("span",{className:"st-"+m.status,children:m.status})," · ",m.executor||"",m.updated_at?" · "+new Date(m.updated_at*1e3).toLocaleString():""," · ",c.jsxs("span",{title:_,children:["耗时 ",o]})," · ",c.jsx("span",{title:N,children:C})]})]})]},m.id)})}):c.jsx("div",{className:"muted",children:"先选项目"})]})}function cg(i){const r=v.useRef(null),[m,o]=v.useState(!0),_=v.useRef(!0),C=()=>{const N=r.current;if(!N)return;const b=N.scrollHeight-N.scrollTop-N.clientHeight<80;_.current=b,o(b)};return v.useEffect(()=>{_.current&&r.current&&(r.current.scrollTop=r.current.scrollHeight)},[i]),{ref:r,following:m,onScroll:C}}function sg({msg:i}){if(i.role==="status")return c.jsx("div",{className:"chat-status",children:i.text});const r=i.label||(i.role==="user"?"用户":i.role==="assistant"?"助手":"工具");return c.jsxs("div",{className:"gh-comment "+i.role,children:[c.jsx("div",{className:"gh-comment-header",children:c.jsx("span",{className:"gh-comment-author",children:r})}),c.jsx("div",{className:"gh-comment-body",children:i.text})]})}function fg({messages:i,empty:r}){const{ref:m,following:o,onScroll:_}=cg(i.length);return c.jsxs("div",{className:"chat-list",ref:m,onScroll:_,children:[i.length===0?c.jsx("div",{className:"muted",children:r||"(暂无消息)"}):i.map(C=>c.jsx(sg,{msg:C},C.id)),!o&&i.length>0?c.jsx("button",{className:"chat-follow",onClick:()=>{m.current&&(m.current.scrollTop=m.current.scrollHeight)},children:"回到最新 ↓"}):null]})}function rg({onSend:i,disabled:r,placeholder:m}){const[o,_]=v.useState(""),C=()=>{const N=o.trim();!N||r||(i(N),_(""))};return c.jsxs("div",{className:"gh-comment-box",children:[c.jsx("textarea",{"aria-label":"会话输入",rows:3,placeholder:m||"消息",value:o,disabled:r,onChange:N=>_(N.target.value),onKeyDown:N=>{N.key==="Enter"&&!N.shiftKey&&(N.preventDefault(),C())}}),c.jsx("div",{className:"gh-comment-footer",children:c.jsx("button",{type:"button",className:"primary","aria-label":"发送",disabled:r||!o.trim(),onClick:C,children:"发送"})})]})}function Yh(i,r){const m=i.id||"trace-"+r;if(i.kind==="message"){const o=(i.phase?"["+i.phase+"] ":"")+(i.text||"");return{id:m,role:"assistant",kind:i.kind,text:i.truncated?o+`
-(链路摘要已截断至 300 字,完整回复见右侧任务结果)`:o,label:"助手"}}if(i.kind==="exec"||i.kind==="file"||i.kind==="tool"||i.kind==="call"){const o=i.kind==="exec"?"命令":i.kind==="file"?"文件":i.kind==="tool"?"工具":"调用";return{id:m,role:"tool",kind:i.kind,text:dr(i),label:o}}return i.kind==="plan"?{id:m,role:"status",kind:i.kind,text:i.text||""}:i.kind==="reasoning"?{id:m,role:"status",kind:i.kind,text:"思考:"+(i.summary||"")}:i.kind==="agent-start"?{id:m,role:"status",kind:i.kind,text:"子代理开始:"+(i.name||"")+(i.prompt?"("+i.prompt+")":"")}:i.kind==="agent-done"?{id:m,role:"status",kind:i.kind,text:"子代理结束:"+(i.name||"")+" "+(i.status||"")}:{id:m,role:"status",kind:i.kind,text:dr(i)}}function og(){const i=Ut(),r=i.currentTask,m=v.useMemo(()=>{if(!r)return[];let B;if(i.chatHistory){B=i.chatHistory.messages.map(X=>({id:X.id,role:X.role,text:X.text,label:X.label,kind:X.kind}));const q=new Set(B.map(X=>X.id)),tt=i.traceEntries.filter(X=>X.id&&!q.has(X.id)&&!String(X.id).startsWith("fu-")).map((X,W)=>Yh(X,W));B=[...B,...tt]}else{const q=r.prompt?[{id:"task-prompt",role:"user",text:r.prompt}]:[],tt=i.traceEntries.filter(W=>!String(W.id||"").startsWith("fu-")).map((W,G)=>Yh(W,G)),X=i.followups.map((W,G)=>({id:"followup-"+G,role:"user",text:String(W.body||""),label:"后续消息"}));B=[...q,...tt,...X]}const U=i.traceKind,k=U?B.filter(q=>q.role==="user"||!q.kind||q.kind===U):B,j=i.traceDone?[{id:"trace-done",role:"status",text:"链路已结束("+i.traceDone+")"}]:[];return[...k,...j]},[r,i.chatHistory,i.traceEntries,i.followups,i.traceKind,i.traceDone]);if(!r)return c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示继续会话"});const o=uu.includes(r.status),_=["queued","running"].includes(r.status),C=o||_,N=o?"终态任务:发送走继续接口(同一会话再跑一轮)":_?"运行中/排队中:发送走后续消息直接发送(跑完当前轮后优先执行)":"merged/merge-failed 任务不可继续,也不可发后续消息",b=i.chatHistory?i.chatHistory.legacy_continue_count??null:null;return c.jsxs("div",{className:"chat-column",children:[c.jsx("div",{className:"muted",children:"实时对话"}),c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"链路类型",value:i.traceKind,onChange:B=>i.setTraceKind(B.target.value),children:[c.jsx("option",{value:"",children:"链路类型:全部"}),["exec","file","call","tool","message","reasoning","plan","agent-start","agent-done"].map(B=>c.jsx("option",{value:B,children:B==="exec"?"命令":B==="file"?"文件":B==="call"?"调用":B==="tool"?"工具":B==="message"?"消息":B==="reasoning"?"思考":B==="plan"?"计划":"子代理"},B))]}),c.jsx("button",{onClick:i.downloadTrace,children:"下载完整链路"}),c.jsx("span",{className:"muted",children:i.traceMsg})]}),i.traceNote?c.jsx("div",{children:c.jsx("span",{className:"err",children:i.traceNote})}):null,b!==null&&b>0?c.jsxs("div",{className:"muted",children:["此前有 ",b," 条继续消息发生在持久化之前,未入库,上面历史不完整;部署后新发的继续消息会正常显示。"]}):null,i.chatHistory&&i.chatHistory.trace_note?c.jsx("div",{className:"muted",children:i.chatHistory.trace_note}):null,c.jsx(fg,{messages:m,empty:"(暂无会话消息)"}),c.jsx(rg,{disabled:!C,placeholder:"消息",onSend:B=>void i.sendChatMessage(B)}),c.jsxs("div",{className:"muted",children:[N,"。",i.chatMsg]}),c.jsx("div",{className:"muted",children:"对话时间线:首条是本任务 prompt(用户);助手回复、命令/文件/工具/调用、计划/思考/子代理开始结束都在同一列里,不再另起一份链路名单。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。"})]})}function dg(){return Ut().currentTask?c.jsx("div",{className:"conversation",children:c.jsx(og,{})}):c.jsx("div",{className:"conversation",children:c.jsx("div",{className:"muted",children:"在任务列表里点一条任务,对话和详情就切到该任务;也可以在上面派发一个新任务。"})})}function mg(){const i=Ut(),r=i.currentTask,[m,o]=v.useState("");if(!r)return null;const _=uu.includes(r.status),C=["failed","interrupted","merge-failed"].includes(r.status);return c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("button",{disabled:!C,title:C?"":"仅 failed/interrupted/merge-failed 可重试",onClick:()=>i.doAction("retry"),children:"重试"}),c.jsx("button",{className:"danger",disabled:_,title:_?"终态任务不可取消":"",onClick:()=>i.doAction("cancel"),children:"取消"}),c.jsx("button",{disabled:r.status!=="completed",title:r.status!=="completed"?"仅 completed 可合并":"",onClick:()=>i.doAction("merge"),children:"合并(completed → merged)"}),c.jsx("button",{disabled:r.status!=="merged",title:r.status!=="merged"?"仅 merged 可提 PR":"",onClick:()=>i.doAction("pr"),children:"提 PR(须 merged)"}),_?c.jsx("button",{onClick:()=>i.setForkVisible(!0),children:"分支"}):null,c.jsx("button",{onClick:i.taskCost,children:"查成本"}),c.jsxs("span",{className:"muted",children:[i.actionMsg," ",i.actionReasons]})]}),i.forkVisible?c.jsxs("div",{children:[c.jsx("input",{type:"text",placeholder:"分支首轮消息(必填,带历史的新会话)",style:{width:"100%",boxSizing:"border-box",margin:"6px 0"},value:m,onChange:N=>o(N.target.value)}),c.jsxs(Dt,{children:[c.jsx("button",{className:"seal",onClick:async()=>{await i.forkTask(m),o("")},children:"创建分支任务"}),c.jsx("span",{className:"muted",children:i.forkMsg})]})]}):null]})}function hg(){const i=Ut(),[r,m]=v.useState("uncommittedChanges"),[o,_]=v.useState(""),[C,N]=v.useState(""),[b,B]=v.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("h3",{children:"评审队列"}),c.jsxs("select",{"aria-label":"评审目标",value:r,onChange:U=>m(U.target.value),children:[c.jsx("option",{value:"uncommittedChanges",children:"未提交改动(工作区)"}),c.jsx("option",{value:"baseBranch",children:"与分支的差异"}),c.jsx("option",{value:"commit",children:"指定提交"}),c.jsx("option",{value:"custom",children:"自定义评审指令"})]}),c.jsx("input",{className:"stacked",placeholder:"与分支的差异用:分支名(如 main)",style:{width:"100%"},value:o,onChange:U=>_(U.target.value)}),c.jsx("input",{className:"stacked",placeholder:"指定提交用:提交 sha",style:{width:"100%"},value:C,onChange:U=>N(U.target.value)}),c.jsx("textarea",{placeholder:"自定义评审指令用:评审指令正文",value:b,onChange:U=>B(U.target.value)}),c.jsxs(Dt,{children:[c.jsx("button",{className:"primary",onClick:()=>void i.postReview({target_type:r,branch:o.trim()||void 0,sha:C.trim()||void 0,instructions:b.trim()||void 0}),children:"登记评审需求"}),c.jsx("button",{onClick:i.refreshReviews,children:"刷新队列"}),c.jsx("span",{className:"muted",children:i.reviewMsg})]}),c.jsx("div",{className:"muted",children:"本基线只登记评审需求(requested),不自动跑评审;评审是否执行、结果如何,以评审队列里的记录为准。"}),i.reviewError?c.jsx("div",{className:"muted",children:i.reviewError}):i.reviews.length===0?c.jsx("div",{className:"muted",children:"点任务行查看详情后,点“刷新队列”查看评审记录"}):c.jsx(cu,{children:i.reviews.map(U=>{let k=U.target_type||"";return U.branch&&(k+=":"+U.branch),U.sha&&(k+=":"+String(U.sha).slice(0,12)),U.instructions&&(k+=":"+String(U.instructions).slice(0,80)),c.jsxs("li",{children:[c.jsxs("span",{className:"row-main",children:[c.jsx("b",{children:"评审"})," ",Ue(U.id)," | ",k," | ",c.jsx("span",{className:"st-"+(U.status||""),children:U.status}),U.created_at?" | "+ka(U.created_at):"",c.jsx("br",{}),U.findings?String(U.findings).slice(0,1e3):c.jsx("span",{className:"muted",children:"(暂无 findings:评审尚未执行或尚未写回)"})]}),c.jsx("button",{onClick:()=>i.submitFindings(U.id),children:"写 findings"})]},U.id)})})]})}function vg(){const i=Ut();return i.currentTask?i.currentTask.coordinator_parts?i.coordChildren.length===0?c.jsx("div",{className:"muted",children:"(子任务尚未创建)"}):c.jsx(cu,{children:i.coordChildren.map(r=>c.jsx("li",{children:c.jsxs("span",{className:"row-main",children:["分工 ",c.jsx("b",{children:r.coordinator_part||""})," | 状态 ",c.jsx("span",{className:"st-"+r.status,children:r.status})," | ",Ue(r.id)," | ",String(r.prompt||"").slice(0,60)]})},r.id))}):c.jsx("div",{className:"muted",children:"(非协调员任务)"}):c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示协调员的子任务"})}function yg(){const i=Ut();if(!i.currentTask)return c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示子代理链路"});if(i.agents.length===0)return c.jsxs("div",{className:"muted",children:["(暂无子代理)",i.agentsNote?c.jsx("span",{className:"err",children:i.agentsNote}):null]});const r={main:"主任务",delegate:"委派子任务",model:"模型子代理"},m={running:"进行中",completed:"已完成",failed:"失败",interrupted:"已中断",unknown:"未知"};return c.jsx(cu,{children:i.agents.map((o,_)=>c.jsx("li",{children:c.jsxs("span",{className:"row-main",children:[c.jsxs("b",{children:[r[o.kind||""]||o.kind||"",":"]}),o.name||""," ",c.jsx("span",{className:"st-"+(o.status||""),children:m[o.status||""]||o.status||"?"})," | 过程调用 "+(o.calls?o.calls.length:0)+" 条",o.updated_ts?" | 最近活动 "+ka(o.updated_ts/1e3):"",o.prompt?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsxs("span",{className:"muted",children:["任务:",o.prompt]})]}):null,o.calls&&o.calls.length?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),o.calls.slice(-50).map((C,N)=>c.jsx("div",{children:dr(C)},N))]}):c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsx("span",{className:"muted",children:"(暂无过程调用)"})]})]})},_))})}function gg(){const i=Ut();return c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.refreshApprovals,children:"刷新审批队列"}),c.jsx("span",{className:"muted",children:i.approvalMsg})]}),c.jsx("div",{className:"muted",children:"待审批项需人工点记录允许或记录拒绝;超时默认拒绝。当前版本只留回执,不拦截实时行为(实时请求的事前拦截待 host 接入后生效,在此之前实时行为不变)。"}),c.jsx(Ml,{empty:"(暂无审批项)",items:i.approvals.map(r=>c.jsxs("span",{className:"row-main",children:["[",r.kind,"|",r.status,"] ",r.summary,["approved","denied","expired"].includes(r.status||"")?"|回执:"+(r.decision||r.status)+" by "+String(r.decided_by||"").slice(0,8)+" "+ka(r.decided_at):"",r.status==="pending"?c.jsxs(c.Fragment,{children:[" ",c.jsx("button",{onClick:()=>i.decideApproval(r.id,"approved"),children:"记录允许"})," ",c.jsx("button",{onClick:()=>i.decideApproval(r.id,"denied"),children:"记录拒绝"})]}):null]},r.id))})]})}function Sg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("input",{placeholder:"目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)",style:{width:"100%"},value:r,onChange:C=>m(C.target.value)}),c.jsx("textarea",{placeholder:"消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)",value:o,onChange:C=>_(C.target.value)}),c.jsxs(Dt,{children:[c.jsx("button",{onClick:async()=>{await i.postPeer("queued",r,o),_("")},children:"排队发给对方"}),c.jsx("button",{className:"primary",onClick:async()=>{await i.postPeer("direct",r,o),_("")},children:"直接发送"}),c.jsx("span",{className:"muted",children:i.peerMsg})]}),c.jsx(Ml,{empty:"(本任务尚未发出任务间消息)",items:i.peerMessages.map((C,N)=>c.jsxs("span",{className:"row-main",children:["[发给 ",String(C.task_id).slice(0,8),"|",C.mode,"|",C.status,"] ",String(C.body||"").slice(0,120)]},N))})]})}function pg(){const i=Ut(),[r,m]=v.useState(""),o=i.currentTask?["completed","failed","interrupted"].includes(i.currentTask.status):!1;return c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"muted",children:i.threadText||"点任务行查看详情后,这里显示线程元数据"}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"新线程名",value:r,onChange:_=>m(_.target.value)}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("rename",r),children:"重命名"}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("archive",""),children:"归档"}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("unarchive",""),children:"取消归档"}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("compact",""),children:"压缩"}),c.jsx("span",{className:"muted",children:i.threadGateNote}),c.jsx("span",{className:"muted",children:i.threadMsg})]}),c.jsx(Ml,{empty:"暂无其他线程",items:i.threadList.map((_,C)=>c.jsxs("span",{className:"row-main",children:[_.name||_.thread_name||_.id||""," [",_.id||"","]",_.archived?" [已归档]":"",_.cwd?" "+_.cwd:""]},C))}),c.jsx("div",{className:"muted",children:"限制:Docker/异机任务线程操作一律 409;merged/merge-failed 不可改;turn/steer 与 review/start 不在本批。"})]})}function bg(){const i=Ut(),r=i.currentTask;if(!r)return c.jsx(Zt,{id:"nav-detail",title:"任务详情",children:c.jsx("div",{className:"muted",children:"点任务行查看详情"})});const[m,o]=Vh(r),[_,C]=Lh(r),N=Xh(r),b=i.costSummary,B=r.plan?"计划模式(只读)":r.goal_mode?r.no_time_limit?"goal 模式无敌版(不限时)":"goal 模式(不限轮次,模型宣告完成)":r.verify_command?"goal 模式(旧语义,验收命令)":null;return c.jsxs("div",{className:"detail-stack",id:"nav-detail",children:[c.jsxs(Zt,{title:"任务详情",children:[c.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[c.jsx("span",{className:"issue-first",title:"任务首字:"+N,"aria-hidden":"true",children:N}),c.jsxs("span",{children:["状态 ",c.jsx("b",{className:"st-"+r.status,children:r.status}),"(",Xy[r.status]||"未知状态",")"]}),c.jsxs("span",{className:"muted",children:["更新 ",ka(r.updated_at)]})]}),c.jsxs("div",{className:"detail-cards",children:[c.jsxs("div",{className:"detail-card",title:o,children:[c.jsx("div",{className:"detail-card-label",children:"耗时"}),c.jsx("div",{className:"detail-card-value",children:m})]}),c.jsxs("div",{className:"detail-card",title:C,children:[c.jsx("div",{className:"detail-card-label",children:"token"}),c.jsx("div",{className:"detail-card-value",children:_})]}),c.jsxs("div",{className:"detail-card",title:"成本明细:GET /tasks/{id}/cost 聚合;美元只计有价行,无价 token 单列;缓存是输入 token 的子集,不另计",children:[c.jsx("div",{className:"detail-card-label",children:"成本"}),c.jsx("div",{className:"detail-card-value",children:b===void 0?"加载中…":b===null?"—":ug(b.usd_micros)}),b===void 0?c.jsx("div",{className:"muted",children:"成本加载中…"}):b===null?c.jsx("div",{className:"muted",children:"成本明细加载失败(“查成本”按钮仍可手动拉取原始 JSON)"}):c.jsxs("div",{className:"muted",children:["token ",(b.total_tokens??0).toLocaleString(),"(实际 ",(b.actual_tokens??0).toLocaleString()," / 估算 ",(b.estimated_tokens??0).toLocaleString(),",缓存 ",(b.cached_input_tokens??0).toLocaleString(),",无价 ",(b.unpriced_actual_tokens??0).toLocaleString(),")| 轮数 ",b.turns??0," | fallback ",b.fallback_count??0]})]})]})]}),c.jsx(Zt,{title:"基本信息",children:c.jsxs("dl",{className:"detail-kv",children:[c.jsxs("div",{children:[c.jsx("dt",{children:"任务"}),c.jsx("dd",{children:r.id})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"turn"}),c.jsx("dd",{children:Ue(r.turn_id)})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"root turn"}),c.jsx("dd",{children:Ue(r.root_turn_id)})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"executor"}),c.jsx("dd",{children:r.executor||""})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"主机"}),c.jsx("dd",{children:r.worktree_host||""})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"模型"}),c.jsx("dd",{children:r.model||"默认"})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"强度"}),c.jsx("dd",{children:r.effort||"默认"})]}),r.child_model||r.child_effort?c.jsxs("div",{children:[c.jsx("dt",{children:"子任务默认"}),c.jsx("dd",{children:(r.child_model||"跟随本任务")+" / "+(r.child_effort||"跟随本任务")})]}):null,c.jsxs("div",{children:[c.jsx("dt",{children:"权限"}),c.jsx("dd",{children:r.approval||"默认"})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"项目"}),c.jsx("dd",{children:Ue(r.project_id)})]}),B?c.jsxs("div",{children:[c.jsx("dt",{children:"模式"}),c.jsx("dd",{children:B})]}):null,r.forked_from?c.jsxs("div",{children:[c.jsx("dt",{children:"分支自"}),c.jsx("dd",{children:Ue(r.forked_from)})]}):null,r.coordinator_parts?c.jsxs("div",{children:[c.jsx("dt",{children:"协调员"}),c.jsxs("dd",{children:[r.coordinator_parts.length," 个子任务(",r.coordinator_parts.map(U=>U.name).join("、"),")"]})]}):null,r.parent_task_id?c.jsxs("div",{children:[c.jsx("dt",{children:"协调子任务"}),c.jsxs("dd",{children:["父任务 ",Ue(r.parent_task_id),r.coordinator_part?"("+r.coordinator_part+")":""]})]}):null,r.attachments&&r.attachments.length?c.jsxs("div",{children:[c.jsx("dt",{children:"附件"}),c.jsx("dd",{children:r.attachments.join("、")})]}):null,r.pr_url?c.jsxs("div",{children:[c.jsx("dt",{children:"PR"}),c.jsx("dd",{children:c.jsxs("a",{href:r.pr_url,target:"_blank",rel:"noopener noreferrer",children:["PR #",r.pr_number]})})]}):null]})}),c.jsx(Zt,{title:"prompt",children:c.jsx("div",{style:{whiteSpace:"pre-wrap",overflowWrap:"anywhere"},children:r.prompt||"(无 prompt)"})}),c.jsxs(Zt,{title:"操作与结果",children:[c.jsx(mg,{}),c.jsx("pre",{children:i.detailBody||"(暂无 result/error 输出)"}),i.costBox?c.jsx("pre",{children:i.costBox}):null]}),c.jsx(Zt,{title:"协调子任务",children:c.jsx(vg,{})}),c.jsx(Zt,{title:"子代理链路",children:c.jsx(yg,{})}),c.jsx(Zt,{title:"评审队列",children:c.jsx(hg,{})}),c.jsx(Zt,{title:"运行时审批队列",children:c.jsx(gg,{})}),c.jsx(Zt,{title:"给其他任务发消息",children:c.jsx(Sg,{})}),c.jsx(Zt,{title:"线程",children:c.jsx(pg,{})})]})}function xg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState([]),[b,B]=v.useState(null),[U,k]=v.useState(!1),[j,q]=v.useState(""),[tt,X]=v.useState(""),W=v.useCallback(async()=>{if(!i.keySaved){N([]);return}try{const nt=await lt(P.userKeys);N(nt.keys||[]),X("")}catch(nt){X(nt instanceof Error?nt.message:"加载 key 列表失败")}},[i.keySaved]);v.useEffect(()=>{W()},[W]);const G=async()=>{q(""),X(""),k(!1);try{const nt=await lt(P.userKeys,"POST",{label:o.trim()||"api-key"});B(nt),_(""),q("新 key 已生成,只显示一次:复制后请妥善保存。"),await W()}catch(nt){X(nt instanceof Error?nt.message:"生成 key 失败")}},dt=async()=>{if(b)try{await navigator.clipboard.writeText(b.api_key),k(!0)}catch{X("复制失败:请手动选中上方 key 文本复制")}},Mt=()=>{b&&(i.saveKeyInput(b.api_key),B(null),q("已存为当前浏览器 key(原有 key 未被撤销,需要时可单独撤销)。"))},Ft=async nt=>{const Xt=(()=>{try{return bl().slice(-4)}catch{return""}})(),ee=nt.id==="legacy"?"(主 key:撤销后当前浏览器保存的 key 也可能随之失效,需重新登录拿新 key)":nt.hint&&nt.hint===Xt?"(这就是本浏览器当前在用的 key,撤销后本页会立刻未连接)":"";if(window.confirm(`撤销 key「${nt.label}」(后 4 位 ${nt.hint||"无"})吗?${ee}撤销不可恢复。`)){q(""),X("");try{await lt(P.userKey(nt.id),"DELETE"),q(`已撤销 key「${nt.label}」。`),await W()}catch(ct){X(ct instanceof Error?ct.message:"撤销失败")}}};return c.jsxs(Zt,{id:"nav-key",title:"API Key",children:[c.jsxs(Dt,{children:[c.jsx("input",{type:"password",placeholder:"粘贴你的 X-API-Key(与调 API 用的同一个)",autoComplete:"off",value:r,onChange:nt=>m(nt.target.value)}),c.jsx("button",{className:"primary",onClick:()=>{i.saveKeyInput(r),m("")},children:"保存到本浏览器"}),c.jsx("button",{onClick:i.clearKeyInput,children:"清除"}),c.jsx("span",{className:"muted",children:i.keyState})]}),c.jsx("div",{children:c.jsx("span",{className:"muted",children:i.quotaText})}),!i.keySaved&&c.jsx("div",{children:c.jsx("span",{className:"muted",children:"先粘贴并保存已有 key,再生成或管理 key(生成接口本身也要用已有 key 鉴权)。"})}),i.keySaved&&c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("input",{placeholder:"新 key 备注(可选,默认 api-key,如 harness2-temp)",autoComplete:"off",value:o,onChange:nt=>_(nt.target.value)}),c.jsx("button",{className:"primary",onClick:()=>void G(),children:"生成新 key"}),c.jsx("button",{onClick:()=>void W(),children:"刷新列表"})]}),b&&c.jsxs("div",{children:[c.jsx("div",{children:c.jsxs("span",{className:"muted",children:["新 key(",b.label,",后 4 位 ",b.hint,"):只显示一次,关闭后无法再查看。"]})}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",readOnly:!0,value:b.api_key,onFocus:nt=>nt.target.select()}),c.jsx("button",{className:"primary",onClick:()=>void dt(),children:U?"已复制":"复制"}),c.jsx("button",{onClick:Mt,children:"存为当前浏览器 key"}),c.jsx("button",{onClick:()=>B(null),children:"关闭(不再显示)"})]})]}),j&&c.jsx("div",{children:c.jsx("span",{className:"muted",children:j})}),tt&&c.jsx("div",{children:c.jsx("span",{children:tt})}),c.jsxs("div",{children:[C.length===0&&c.jsx("span",{className:"muted",children:"暂无 key(或列表加载失败,见上方报错)。"}),C.map(nt=>c.jsxs("div",{children:[c.jsx("span",{children:nt.label})," ",c.jsxs("span",{className:"muted",children:["后 4 位 ",nt.hint||"无"," · 创建 ",ka(nt.created_at)," · 最近使用 ",nt.last_used_at?ka(nt.last_used_at):"未使用过"]})," ",nt.revoked_at?c.jsxs("span",{className:"muted",children:["已撤销(",ka(nt.revoked_at),")"]}):c.jsx("button",{onClick:()=>void Ft(nt),children:"撤销"})]},nt.id))]})]})]})}function jg(){const i=Ut();return c.jsxs(Zt,{id:"adminCard",title:c.jsxs(c.Fragment,{children:["管理区 ",c.jsx("span",{className:"muted",children:"(仅全局管理员)"})]}),children:[c.jsx("div",{className:"muted",children:i.adminGate}),i.adminBody?c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"要查配额的用户 id",value:i.adminUserId,onChange:r=>i.setAdminUserId(r.target.value)}),c.jsx("button",{onClick:i.adminQuota,children:"查该用户配额"})]}),c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.adminSweep,children:"手动触发 sweep(清理陈旧 running 任务)"}),c.jsx("button",{onClick:i.adminBackup,children:"手动触发备份"})]}),c.jsx("div",{className:"muted",children:i.adminResult})]}):null]})}function Tg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return c.jsxs(Zt,{id:"nav-projects",title:"项目",children:[c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"项目",value:i.projectId,onChange:b=>i.selectProject(b.target.value),children:[i.projects.length===0?c.jsx("option",{value:"",children:"(先加载项目)"}):null,i.projects.map(b=>c.jsxs("option",{value:b.id,children:[b.name," (",Ue(b.id),")"]},b.id))]}),c.jsx("button",{onClick:i.refreshProjects,children:"刷新"})]}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"新项目名",value:r,onChange:b=>m(b.target.value)}),c.jsxs("select",{"aria-label":"从 GitHub 仓库选",value:o,onChange:b=>{_(b.target.value),b.target.value&&N(b.target.value)},children:[c.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选,或手动输入)"}),i.githubRepos.map(b=>c.jsx("option",{value:b.clone_url,children:b.repo_full_name},b.clone_url))]}),c.jsx("input",{type:"text",placeholder:"repo_url(可选)",value:C,onChange:b=>N(b.target.value)}),c.jsx("button",{onClick:async()=>{await i.createProject(r,C),m(""),N(""),_("")},children:"新建项目"})]}),c.jsx("span",{className:"muted",children:i.projectMsg})]})}function _g(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState("contributor"),C=i.projects.find(N=>N.id===i.projectId);return c.jsxs(Zt,{title:"项目成员",children:[C?c.jsxs("div",{className:"muted",children:[C.name," | ",C.id," | 仓库 ",C.repo_url||"未绑定"," | 我的角色 ",C.my_role||"未知"]}):c.jsx("div",{className:"muted",children:"先选项目"}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"成员 user_id 或用户名",value:r,onChange:N=>m(N.target.value)}),c.jsxs("select",{"aria-label":"邀请角色",value:o,onChange:N=>_(N.target.value),children:[c.jsx("option",{value:"viewer",children:"viewer(只读)"}),c.jsx("option",{value:"contributor",children:"contributor(可建任务)"}),c.jsx("option",{value:"maintainer",children:"maintainer(可批合并)"}),c.jsx("option",{value:"owner",children:"owner(可管项目)"})]}),c.jsx("button",{onClick:async()=>{await i.inviteMember(r,o),m("")},children:"邀请成员"}),c.jsx("button",{onClick:i.refreshMembers,children:"刷新成员"})]}),i.memberError?c.jsx("div",{className:"muted",children:i.memberError}):i.members.length===0?c.jsx("div",{className:"muted",children:"先选项目"}):c.jsx(cu,{children:i.members.map(N=>{const b=(N.username||"")+(N.username?"("+String(N.user_id).slice(0,8)+")":String(N.user_id).slice(0,8));return c.jsxs("li",{children:[c.jsx("span",{className:"row-main",children:b}),c.jsx("select",{"aria-label":"成员角色",value:N.role||"viewer",onChange:B=>void i.changeMemberRole(N.user_id,B.target.value),children:Vy.map(B=>c.jsx("option",{value:B,children:B},B))})]},N.user_id)})}),c.jsx("span",{className:"muted",children:i.memberMsg})]})}function Eg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return c.jsxs(Zt,{id:"nav-env",title:c.jsxs(c.Fragment,{children:["环境 ",c.jsx("span",{className:"muted",children:"(选、建、管:当前项目的基准检出)"})]}),children:[c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.refreshEnvs,children:"刷新"}),c.jsx("span",{className:"muted",children:i.envCount})]}),i.envs.length===0?c.jsx("div",{className:"muted",children:"先选项目"}):c.jsx(cu,{children:i.envs.map(b=>c.jsxs("li",{children:[c.jsxs("span",{className:"row-main",children:[b.name,"(",Ue(b.id),") / 分支 ",b.branch||"默认分支"," / 执行器 ",b.executor||"不限"," / 状态 ",b.status,b.status==="failed"&&b.error_text?" / 失败原因:"+b.error_text:""]}),b.status==="archived"?null:c.jsx("button",{onClick:()=>void i.archiveEnv(b.id),children:"归档"})]},b.id))}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"新环境名",value:r,onChange:b=>m(b.target.value)}),c.jsx("input",{type:"text",placeholder:"分支(可选,空=默认分支)",value:o,onChange:b=>_(b.target.value)}),c.jsxs("select",{"aria-label":"新环境执行器",value:C,onChange:b=>N(b.target.value),children:[c.jsx("option",{value:"",children:"执行器:不限"}),c.jsx("option",{value:"local",children:"local"}),c.jsx("option",{value:"docker",children:"docker"})]}),c.jsx("button",{onClick:async()=>{await i.createEnv(r,o,C),m(""),_("")},children:"新建环境"})]}),c.jsx("span",{className:"muted",children:i.envMsg})]})}function Ng(){const i=Ut(),[r,m]=v.useState("");return c.jsxs(Zt,{title:"仓库与环境上下文",children:[c.jsx("div",{className:"muted",children:i.envRepoLine||"先选项目"}),c.jsx("div",{className:"muted",children:i.envCount}),i.envRepoBar?c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"补仓库",value:r,onChange:o=>m(o.target.value),children:[c.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选)"}),i.githubRepos.map(o=>c.jsx("option",{value:o.clone_url,children:o.repo_full_name},o.clone_url))]}),c.jsx("button",{onClick:()=>void i.saveEnvRepo(r),children:"保存仓库"})]}):null,c.jsx("span",{className:"muted",children:i.envRepoMsg})]})}function Cg(){const i=Ut();return c.jsxs(Zt,{id:"nav-workers",title:"Workers",children:[c.jsx(Dt,{children:c.jsx("button",{onClick:i.refreshWorkers,children:"刷新"})}),i.workersError?c.jsx("div",{className:"muted",children:i.workersError}):i.workers===null?c.jsx("div",{className:"muted",children:i.workersSummary||"未加载"}):i.workers.length===0?c.jsx("div",{className:"muted",children:"无 worker 注册"}):c.jsx(cu,{children:i.workers.map((r,m)=>{const o=r.running===void 0||r.running===null?"?":r.running,_=r.capacity===void 0||r.capacity===null?"?":r.capacity,C=Qh(r),N=r.alive!==void 0&&r.alive!==null?!!r.alive:C.age!==null&&C.age<=120,b=N?" / 在线":" / 离线(占用为上次上报值)";return c.jsx("li",{className:N?"is-online":"is-offline",children:c.jsxs("span",{className:"row-main",children:[r.worker_id||r.id||"?"," / ",r.executor||""," / 占用 ",o,"/",_,b," / 最后心跳 ",C.text]})},m)})})]})}function Ag(){const i=Ut();return c.jsxs(Zt,{title:"健康与配额",children:[c.jsxs(Dt,{children:[c.jsx("span",{className:"muted",children:i.healthText}),c.jsx("button",{onClick:i.refreshHealth,children:"刷新"})]}),c.jsx("div",{children:c.jsx("span",{className:"muted",children:i.quotaText})}),c.jsx("div",{className:"muted",children:i.workersSummary})]})}function Og(){const i=Ut();return c.jsxs(Zt,{id:"nav-skills",title:"技能与 MCP",children:[c.jsx("div",{className:"muted",children:"反映宿主租户 home,容器内 home 可能不同;重载只在 schema 枚举里,当前 pin 的二进制拒绝时原样 502;OAuth 只发起登录,不代表登录完成。"}),c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.refreshSkills,children:"刷新"}),c.jsx("span",{className:"muted",children:i.skillMsg})]}),c.jsx("h3",{children:"技能"}),i.skillError?c.jsx("div",{className:"muted",children:i.skillError}):c.jsx(Ml,{empty:"暂无技能",items:i.skills.map((r,m)=>c.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:"",r.detail?" - "+r.detail:""]},m))}),c.jsx("h3",{children:"应用"}),c.jsx(Ml,{empty:"暂无应用",items:i.apps.map((r,m)=>c.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:""]},m))}),c.jsx("h3",{children:"MCP 服务"}),c.jsx(Ml,{empty:"暂无 MCP 服务",items:i.mcpServers.map((r,m)=>{const o=r.detail||r.details||r.state||"";return c.jsxs("span",{className:"row-main",children:[r.name||r.id||""," | 状态 ",r.status||"",o?" | "+o:""]},m)})})]})}function Mg(){const i=Ut(),[r,m]=v.useState("");return c.jsxs(Zt,{title:"MCP 操作",children:[c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.reloadMcp,children:"重载配置"}),c.jsx("span",{className:"muted",children:i.mcpMsg})]}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"MCP 服务名",value:r,onChange:o=>m(o.target.value)}),c.jsx("button",{onClick:()=>void i.mcpOauth(r),children:"发起 OAuth 登录"}),c.jsx("span",{className:"muted",children:i.mcpOauthMsg})]}),i.mcpOauthBox?c.jsx("pre",{children:i.mcpOauthBox}):null]})}function zg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(""),[b,B]=v.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("input",{placeholder:"自动化名称(同项目内启用中的名称唯一)",style:{width:"100%"},value:r,onChange:U=>m(U.target.value)}),c.jsx("textarea",{placeholder:"定时任务内容(创建只登记定义与到期状态;执行由后续执行器经 claim 抢单后建任务,不另起调度器)",value:o,onChange:U=>_(U.target.value)}),c.jsxs(Dt,{children:[c.jsx("input",{placeholder:"间隔秒数(默认 86400,最小 60)",style:{width:"40%"},value:C,onChange:U=>N(U.target.value)}),c.jsx("input",{placeholder:"仓库(可选)",style:{width:"40%"},value:b,onChange:U=>B(U.target.value)}),c.jsx("button",{className:"primary",onClick:async()=>{await i.createAutomation(r,o,C,b),m(""),_(""),N(""),B("")},children:"创建自动化"}),c.jsx("button",{onClick:i.refreshAutomations,children:"刷新自动化"}),c.jsx("span",{className:"muted",children:i.autoMsg})]}),c.jsx(Ml,{empty:"(暂无自动化)",items:i.automations.map(U=>c.jsxs("span",{className:"row-main",children:["[",U.status,U.due?"|到期":"","] ",U.name,"|每 ",U.interval_seconds," 秒|下次 ",ka(U.next_run_at),U.status==="active"?c.jsxs(c.Fragment,{children:[" ",c.jsx("button",{onClick:()=>i.cancelAutomation(U.id),children:"取消"})]}):null]},U.id))})]})}function Rg(){var m,o,_,C;const i=Ut(),r=i.triage;return i.triageError?c.jsx("div",{className:"muted",children:i.triageError}):r?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["到期自动化(",((m=r.counts)==null?void 0:m.automations_due)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.automations_due||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:[N.name,"|每 ",N.interval_seconds," 秒"]},b))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["失败/中断任务(",((o=r.counts)==null?void 0:o.failed_tasks)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.failed_tasks||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:[Ue(N.id),"|",N.status,"|",String(N.prompt||"").slice(0,80)]},b))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["待处理后续消息(",((_=r.counts)==null?void 0:_.pending_followups)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.pending_followups||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:["任务 ",Ue(N.task_id),"|",String(N.body||"").slice(0,80)]},b))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["最近自动化产出(",((C=r.counts)==null?void 0:C.recent_runs)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.recent_runs||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:[Ue(N.automation_id),"|",N.status,N.task_id?"|任务 "+Ue(N.task_id):"",N.task_status?"|"+N.task_status:""]},b))})]})]}):c.jsx("div",{className:"muted",children:"(先选项目)"})}function Dg(){return c.jsx(Zt,{id:"nav-automations",title:"自动化",children:c.jsx(zg,{})})}function Ug(){const i=Ut();return c.jsxs(Zt,{id:"nav-triage",title:"分诊收件箱",children:[c.jsx(Dt,{children:c.jsx("button",{onClick:i.refreshTriage,children:"刷新分诊"})}),c.jsx(Rg,{})]})}const Hg=[["#sec-dispatch","派发"],["#sec-tasks","任务"],["#sec-conv","对话"],["#sec-projects","项目"],["#sec-env","环境"],["#sec-workers","Workers"],["#sec-skills","技能"],["#sec-automations","自动化"],["#sec-triage","分诊"],["#sec-admin","管理区"],["#sec-key","API Key"]];function Bg(){return c.jsxs("header",{className:"dash-topbar",children:[c.jsxs("div",{className:"dash-topbar-row",children:[c.jsx("span",{className:"dash-brand",children:"Codex 命令台"}),c.jsx(qg,{}),c.jsx("span",{className:"muted dash-hide-sm",children:c.jsx(wg,{})}),c.jsx("span",{className:"muted dash-hide-sm",children:c.jsx(Yg,{})}),c.jsx("span",{className:"muted dash-stamp",children:c.jsx(kg,{})})]}),c.jsx("nav",{className:"dash-nav","aria-label":"页面导航",children:Hg.map(([i,r])=>c.jsx("a",{href:i,children:r},i))})]})}function qg(){const i=Ut();return c.jsx("span",{className:i.keySaved?"dash-status ok":"dash-status off",children:i.keySaved?"● 已连接":"○ 未连接"})}function wg(){return c.jsx(c.Fragment,{children:Ut().healthText})}function Yg(){return c.jsx(c.Fragment,{children:Ut().quotaText})}function kg(){return c.jsxs(c.Fragment,{children:["自动刷新 · 每 10 秒 · 已刷新 ",Ut().refreshStamp]})}function Gg(){const i=lg();Py(m=>i.refreshAll(m),1e4),tg(()=>i.refreshSlow(),6e4);const r=()=>{var m;(m=document.getElementById("sec-dispatch"))==null||m.scrollIntoView({behavior:"smooth"})};return c.jsxs(Gh.Provider,{value:i,children:[c.jsx(Bg,{}),c.jsxs("main",{className:"dash-page",children:[c.jsx(ag,{}),c.jsxs("div",{className:"dash-col dash-col-left",children:[c.jsxs("section",{id:"sec-tasks",className:"dash-section card",children:[c.jsx("h2",{children:"任务列表"}),c.jsx(ig,{onNew:r})]}),c.jsxs("section",{id:"sec-projects",className:"dash-section",children:[c.jsx(Tg,{}),c.jsx(_g,{})]})]}),c.jsxs("div",{className:"dash-col dash-col-mid",children:[c.jsx("section",{id:"sec-dispatch",className:"dash-section",children:c.jsx(ng,{})}),c.jsxs("section",{id:"sec-conv",className:"dash-section",children:[c.jsxs("div",{className:"card",children:[c.jsx("h2",{children:"对话"}),c.jsx(dg,{})]}),c.jsx(bg,{})]})]}),c.jsxs("div",{className:"dash-col dash-col-right",children:[c.jsxs("section",{id:"sec-env",className:"dash-section",children:[c.jsx(Eg,{}),c.jsx(Ng,{})]}),c.jsxs("section",{id:"sec-workers",className:"dash-section",children:[c.jsx(Cg,{}),c.jsx(Ag,{})]}),c.jsxs("section",{id:"sec-skills",className:"dash-section",children:[c.jsx(Og,{}),c.jsx(Mg,{})]}),c.jsx("section",{id:"sec-automations",className:"dash-section",children:c.jsx(Dg,{})}),c.jsx("section",{id:"sec-triage",className:"dash-section",children:c.jsx(Ug,{})}),c.jsx("section",{id:"sec-admin",className:"dash-section",children:c.jsx(jg,{})}),c.jsx("section",{id:"sec-key",className:"dash-section",children:c.jsx(xg,{})})]})]})]})}Gy.createRoot(document.getElementById("root")).render(c.jsx(Dy.StrictMode,{children:c.jsx(Gg,{})}));
-
+(链路摘要已截断至 300 字,完整回复见右侧任务结果)`:o,label:"助手"}}if(i.kind==="exec"||i.kind==="file"||i.kind==="tool"||i.kind==="call"){const o=i.kind==="exec"?"命令":i.kind==="file"?"文件":i.kind==="tool"?"工具":"调用";return{id:m,role:"tool",kind:i.kind,text:dr(i),label:o}}return i.kind==="plan"?{id:m,role:"status",kind:i.kind,text:i.text||""}:i.kind==="reasoning"?{id:m,role:"status",kind:i.kind,text:"思考:"+(i.summary||"")}:i.kind==="agent-start"?{id:m,role:"status",kind:i.kind,text:"子代理开始:"+(i.name||"")+(i.prompt?"("+i.prompt+")":"")}:i.kind==="agent-done"?{id:m,role:"status",kind:i.kind,text:"子代理结束:"+(i.name||"")+" "+(i.status||"")}:{id:m,role:"status",kind:i.kind,text:dr(i)}}function og(){const i=Ut(),r=i.currentTask,m=v.useMemo(()=>{if(!r)return[];let B;if(i.chatHistory){B=i.chatHistory.messages.map(X=>({id:X.id,role:X.role,text:X.text,label:X.label,kind:X.kind}));const q=new Set(B.map(X=>X.id)),tt=i.traceEntries.filter(X=>X.id&&!q.has(X.id)&&!String(X.id).startsWith("fu-")).map((X,W)=>Yh(X,W));B=[...B,...tt]}else{const q=r.prompt?[{id:"task-prompt",role:"user",text:r.prompt}]:[],tt=i.traceEntries.filter(W=>!String(W.id||"").startsWith("fu-")).map((W,G)=>Yh(W,G)),X=i.followups.map((W,G)=>({id:"followup-"+G,role:"user",text:String(W.body||""),label:"后续消息"}));B=[...q,...tt,...X]}const U=i.traceKind,k=U?B.filter(q=>q.role==="user"||!q.kind||q.kind===U):B,j=i.traceDone?[{id:"trace-done",role:"status",text:"链路已结束("+i.traceDone+")"}]:[];return[...k,...j]},[r,i.chatHistory,i.traceEntries,i.followups,i.traceKind,i.traceDone]);if(!r)return c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示继续会话"});const o=uu.includes(r.status),_=["queued","running"].includes(r.status),C=o||_,N=o?"终态任务:发送走继续接口(同一会话再跑一轮)":_?"运行中/排队中:发送走后续消息直接发送(跑完当前轮后优先执行)":"merged/merge-failed 任务不可继续,也不可发后续消息",b=i.chatHistory?i.chatHistory.legacy_continue_count??null:null;return c.jsxs("div",{className:"chat-column",children:[c.jsx("div",{className:"muted",children:"实时对话"}),c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"链路类型",value:i.traceKind,onChange:B=>i.setTraceKind(B.target.value),children:[c.jsx("option",{value:"",children:"链路类型:全部"}),["exec","file","call","tool","message","reasoning","plan","agent-start","agent-done"].map(B=>c.jsx("option",{value:B,children:B==="exec"?"命令":B==="file"?"文件":B==="call"?"调用":B==="tool"?"工具":B==="message"?"消息":B==="reasoning"?"思考":B==="plan"?"计划":"子代理"},B))]}),c.jsx("button",{onClick:i.downloadTrace,children:"下载完整链路"}),c.jsx("span",{className:"muted",children:i.traceMsg})]}),i.traceNote?c.jsx("div",{children:c.jsx("span",{className:"err",children:i.traceNote})}):null,b!==null&&b>0?c.jsxs("div",{className:"muted",children:["此前有 ",b," 条继续消息发生在持久化之前,未入库,上面历史不完整;部署后新发的继续消息会正常显示。"]}):null,i.chatHistory&&i.chatHistory.trace_note?c.jsx("div",{className:"muted",children:i.chatHistory.trace_note}):null,c.jsx(fg,{messages:m,empty:"(暂无会话消息)"}),c.jsx(rg,{disabled:!C,placeholder:"消息",onSend:B=>void i.sendChatMessage(B)}),c.jsxs("div",{className:"muted",children:[N,"。",i.chatMsg]}),c.jsx("div",{className:"muted",children:"对话时间线:首条是本任务 prompt(用户);助手回复、命令/文件/工具/调用、计划/思考/子代理开始结束都在同一列里,不再另起一份链路名单。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。"})]})}function dg(){return Ut().currentTask?c.jsx("div",{className:"conversation",children:c.jsx(og,{})}):c.jsx("div",{className:"conversation",children:c.jsx("div",{className:"muted",children:"在任务列表里点一条任务,对话和详情就切到该任务;也可以在上面派发一个新任务。"})})}function mg(){const i=Ut(),r=i.currentTask,[m,o]=v.useState("");if(!r)return null;const _=uu.includes(r.status),C=["failed","interrupted","merge-failed"].includes(r.status);return c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("button",{disabled:!C,title:C?"":"仅 failed/interrupted/merge-failed 可重试",onClick:()=>i.doAction("retry"),children:"重试"}),c.jsx("button",{className:"danger",disabled:_,title:_?"终态任务不可取消":"",onClick:()=>i.doAction("cancel"),children:"取消"}),c.jsx("button",{disabled:r.status!=="completed",title:r.status!=="completed"?"仅 completed 可合并":"",onClick:()=>i.doAction("merge"),children:"合并(completed → merged)"}),c.jsx("button",{disabled:r.status!=="merged",title:r.status!=="merged"?"仅 merged 可提 PR":"",onClick:()=>i.doAction("pr"),children:"提 PR(须 merged)"}),_?c.jsx("button",{onClick:()=>i.setForkVisible(!0),children:"分支"}):null,c.jsx("button",{onClick:i.taskCost,children:"查成本"}),c.jsxs("span",{className:"muted",children:[i.actionMsg," ",i.actionReasons]})]}),i.forkVisible?c.jsxs("div",{children:[c.jsx("input",{type:"text",placeholder:"分支首轮消息(必填,带历史的新会话)",style:{width:"100%",boxSizing:"border-box",margin:"6px 0"},value:m,onChange:N=>o(N.target.value)}),c.jsxs(Dt,{children:[c.jsx("button",{className:"seal",onClick:async()=>{await i.forkTask(m),o("")},children:"创建分支任务"}),c.jsx("span",{className:"muted",children:i.forkMsg})]})]}):null]})}function hg(){const i=Ut(),[r,m]=v.useState("uncommittedChanges"),[o,_]=v.useState(""),[C,N]=v.useState(""),[b,B]=v.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("h3",{children:"评审队列"}),c.jsxs("select",{"aria-label":"评审目标",value:r,onChange:U=>m(U.target.value),children:[c.jsx("option",{value:"uncommittedChanges",children:"未提交改动(工作区)"}),c.jsx("option",{value:"baseBranch",children:"与分支的差异"}),c.jsx("option",{value:"commit",children:"指定提交"}),c.jsx("option",{value:"custom",children:"自定义评审指令"})]}),c.jsx("input",{className:"stacked",placeholder:"与分支的差异用:分支名(如 main)",style:{width:"100%"},value:o,onChange:U=>_(U.target.value)}),c.jsx("input",{className:"stacked",placeholder:"指定提交用:提交 sha",style:{width:"100%"},value:C,onChange:U=>N(U.target.value)}),c.jsx("textarea",{placeholder:"自定义评审指令用:评审指令正文",value:b,onChange:U=>B(U.target.value)}),c.jsxs(Dt,{children:[c.jsx("button",{className:"primary",onClick:()=>void i.postReview({target_type:r,branch:o.trim()||void 0,sha:C.trim()||void 0,instructions:b.trim()||void 0}),children:"登记评审需求"}),c.jsx("button",{onClick:i.refreshReviews,children:"刷新队列"}),c.jsx("span",{className:"muted",children:i.reviewMsg})]}),c.jsx("div",{className:"muted",children:"本基线只登记评审需求(requested),不自动跑评审;评审是否执行、结果如何,以评审队列里的记录为准。"}),i.reviewError?c.jsx("div",{className:"muted",children:i.reviewError}):i.reviews.length===0?c.jsx("div",{className:"muted",children:"点任务行查看详情后,点“刷新队列”查看评审记录"}):c.jsx(cu,{children:i.reviews.map(U=>{let k=U.target_type||"";return U.branch&&(k+=":"+U.branch),U.sha&&(k+=":"+String(U.sha).slice(0,12)),U.instructions&&(k+=":"+String(U.instructions).slice(0,80)),c.jsxs("li",{children:[c.jsxs("span",{className:"row-main",children:[c.jsx("b",{children:"评审"})," ",Ue(U.id)," | ",k," | ",c.jsx("span",{className:"st-"+(U.status||""),children:U.status}),U.created_at?" | "+ka(U.created_at):"",c.jsx("br",{}),U.findings?String(U.findings).slice(0,1e3):c.jsx("span",{className:"muted",children:"(暂无 findings:评审尚未执行或尚未写回)"})]}),c.jsx("button",{onClick:()=>i.submitFindings(U.id),children:"写 findings"})]},U.id)})})]})}function vg(){const i=Ut();return i.currentTask?i.currentTask.coordinator_parts?i.coordChildren.length===0?c.jsx("div",{className:"muted",children:"(子任务尚未创建)"}):c.jsx(cu,{children:i.coordChildren.map(r=>c.jsx("li",{children:c.jsxs("span",{className:"row-main",children:["分工 ",c.jsx("b",{children:r.coordinator_part||""})," | 状态 ",c.jsx("span",{className:"st-"+r.status,children:r.status})," | ",Ue(r.id)," | ",String(r.prompt||"").slice(0,60)]})},r.id))}):c.jsx("div",{className:"muted",children:"(非协调员任务)"}):c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示协调员的子任务"})}function yg(){const i=Ut();if(!i.currentTask)return c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示子代理链路"});if(i.agents.length===0)return c.jsxs("div",{className:"muted",children:["(暂无子代理)",i.agentsNote?c.jsx("span",{className:"err",children:i.agentsNote}):null]});const r={main:"主任务",delegate:"委派子任务",model:"模型子代理"},m={running:"进行中",completed:"已完成",failed:"失败",interrupted:"已中断",unknown:"未知"};return c.jsx(cu,{children:i.agents.map((o,_)=>c.jsx("li",{children:c.jsxs("span",{className:"row-main",children:[c.jsxs("b",{children:[r[o.kind||""]||o.kind||"",":"]}),o.name||""," ",c.jsx("span",{className:"st-"+(o.status||""),children:m[o.status||""]||o.status||"?"})," | 过程调用 "+(o.calls?o.calls.length:0)+" 条",o.updated_ts?" | 最近活动 "+ka(o.updated_ts/1e3):"",o.prompt?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsxs("span",{className:"muted",children:["任务:",o.prompt]})]}):null,o.calls&&o.calls.length?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),o.calls.slice(-50).map((C,N)=>c.jsx("div",{children:dr(C)},N))]}):c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsx("span",{className:"muted",children:"(暂无过程调用)"})]})]})},_))})}function gg(){const i=Ut();return c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.refreshApprovals,children:"刷新审批队列"}),c.jsx("span",{className:"muted",children:i.approvalMsg})]}),c.jsx("div",{className:"muted",children:"待审批项需人工点记录允许或记录拒绝;超时默认拒绝。当前版本只留回执,不拦截实时行为(实时请求的事前拦截待 host 接入后生效,在此之前实时行为不变)。"}),c.jsx(Ml,{empty:"(暂无审批项)",items:i.approvals.map(r=>c.jsxs("span",{className:"row-main",children:["[",r.kind,"|",r.status,"] ",r.summary,["approved","denied","expired"].includes(r.status||"")?"|回执:"+(r.decision||r.status)+" by "+String(r.decided_by||"").slice(0,8)+" "+ka(r.decided_at):"",r.status==="pending"?c.jsxs(c.Fragment,{children:[" ",c.jsx("button",{onClick:()=>i.decideApproval(r.id,"approved"),children:"记录允许"})," ",c.jsx("button",{onClick:()=>i.decideApproval(r.id,"denied"),children:"记录拒绝"})]}):null]},r.id))})]})}function Sg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("input",{placeholder:"目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)",style:{width:"100%"},value:r,onChange:C=>m(C.target.value)}),c.jsx("textarea",{placeholder:"消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)",value:o,onChange:C=>_(C.target.value)}),c.jsxs(Dt,{children:[c.jsx("button",{onClick:async()=>{await i.postPeer("queued",r,o),_("")},children:"排队发给对方"}),c.jsx("button",{className:"primary",onClick:async()=>{await i.postPeer("direct",r,o),_("")},children:"直接发送"}),c.jsx("span",{className:"muted",children:i.peerMsg})]}),c.jsx(Ml,{empty:"(本任务尚未发出任务间消息)",items:i.peerMessages.map((C,N)=>c.jsxs("span",{className:"row-main",children:["[发给 ",String(C.task_id).slice(0,8),"|",C.mode,"|",C.status,"] ",String(C.body||"").slice(0,120)]},N))})]})}function pg(){const i=Ut(),[r,m]=v.useState(""),o=i.currentTask?["completed","failed","interrupted"].includes(i.currentTask.status):!1;return c.jsxs(c.Fragment,{children:[c.jsx("div",{className:"muted",children:i.threadText||"点任务行查看详情后,这里显示线程元数据"}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"新线程名",value:r,onChange:_=>m(_.target.value)}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("rename",r),children:"重命名"}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("archive",""),children:"归档"}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("unarchive",""),children:"取消归档"}),c.jsx("button",{disabled:!o,onClick:()=>i.threadAction("compact",""),children:"压缩"}),c.jsx("span",{className:"muted",children:i.threadGateNote}),c.jsx("span",{className:"muted",children:i.threadMsg})]}),c.jsx(Ml,{empty:"暂无其他线程",items:i.threadList.map((_,C)=>c.jsxs("span",{className:"row-main",children:[_.name||_.thread_name||_.id||""," [",_.id||"","]",_.archived?" [已归档]":"",_.cwd?" "+_.cwd:""]},C))}),c.jsx("div",{className:"muted",children:"限制:Docker/异机任务线程操作一律 409;merged/merge-failed 不可改;turn/steer 与 review/start 不在本批。"})]})}function bg(){const i=Ut(),r=i.currentTask;if(!r)return c.jsx(Zt,{id:"nav-detail",title:"任务详情",children:c.jsx("div",{className:"muted",children:"点任务行查看详情"})});const[m,o]=Vh(r),[_,C]=Lh(r),N=Xh(r),b=i.costSummary,B=r.plan?"计划模式(只读)":r.goal_mode?r.no_time_limit?"goal 模式无敌版(不限时)":"goal 模式(不限轮次,模型宣告完成)":r.verify_command?"goal 模式(旧语义,验收命令)":null;return c.jsxs("div",{className:"detail-stack",id:"nav-detail",children:[c.jsxs(Zt,{title:"任务详情",children:[c.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[c.jsx("span",{className:"issue-first",title:"任务首字:"+N,"aria-hidden":"true",children:N}),c.jsxs("span",{children:["状态 ",c.jsx("b",{className:"st-"+r.status,children:r.status}),"(",Xy[r.status]||"未知状态",")"]}),c.jsxs("span",{className:"muted",children:["更新 ",ka(r.updated_at)]})]}),c.jsxs("div",{className:"detail-cards",children:[c.jsxs("div",{className:"detail-card",title:o,children:[c.jsx("div",{className:"detail-card-label",children:"耗时"}),c.jsx("div",{className:"detail-card-value",children:m})]}),c.jsxs("div",{className:"detail-card",title:C,children:[c.jsx("div",{className:"detail-card-label",children:"token"}),c.jsx("div",{className:"detail-card-value",children:_})]}),c.jsxs("div",{className:"detail-card",title:"成本明细:GET /tasks/{id}/cost 聚合;美元只计有价行,无价 token 单列;缓存是输入 token 的子集,不另计",children:[c.jsx("div",{className:"detail-card-label",children:"成本"}),c.jsx("div",{className:"detail-card-value",children:b===void 0?"加载中…":b===null?"—":ug(b.usd_micros)}),b===void 0?c.jsx("div",{className:"muted",children:"成本加载中…"}):b===null?c.jsx("div",{className:"muted",children:"成本明细加载失败(“查成本”按钮仍可手动拉取原始 JSON)"}):c.jsxs("div",{className:"muted",children:["token ",(b.total_tokens??0).toLocaleString(),"(实际 ",(b.actual_tokens??0).toLocaleString()," / 估算 ",(b.estimated_tokens??0).toLocaleString(),",缓存 ",(b.cached_input_tokens??0).toLocaleString(),",无价 ",(b.unpriced_actual_tokens??0).toLocaleString(),")| 轮数 ",b.turns??0," | fallback ",b.fallback_count??0]})]})]})]}),c.jsx(Zt,{title:"基本信息",children:c.jsxs("dl",{className:"detail-kv",children:[c.jsxs("div",{children:[c.jsx("dt",{children:"任务"}),c.jsx("dd",{children:r.id})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"turn"}),c.jsx("dd",{children:Ue(r.turn_id)})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"root turn"}),c.jsx("dd",{children:Ue(r.root_turn_id)})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"executor"}),c.jsx("dd",{children:r.executor||""})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"主机"}),c.jsx("dd",{children:r.worktree_host||""})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"模型"}),c.jsx("dd",{children:r.model||"默认"})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"强度"}),c.jsx("dd",{children:r.effort||"默认"})]}),r.child_model||r.child_effort?c.jsxs("div",{children:[c.jsx("dt",{children:"子任务默认"}),c.jsx("dd",{children:(r.child_model||"跟随本任务")+" / "+(r.child_effort||"跟随本任务")})]}):null,c.jsxs("div",{children:[c.jsx("dt",{children:"权限"}),c.jsx("dd",{children:r.approval||"默认"})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"项目"}),c.jsx("dd",{children:Ue(r.project_id)})]}),B?c.jsxs("div",{children:[c.jsx("dt",{children:"模式"}),c.jsx("dd",{children:B})]}):null,r.forked_from?c.jsxs("div",{children:[c.jsx("dt",{children:"分支自"}),c.jsx("dd",{children:Ue(r.forked_from)})]}):null,r.coordinator_parts?c.jsxs("div",{children:[c.jsx("dt",{children:"协调员"}),c.jsxs("dd",{children:[r.coordinator_parts.length," 个子任务(",r.coordinator_parts.map(U=>U.name).join("、"),")"]})]}):null,r.parent_task_id?c.jsxs("div",{children:[c.jsx("dt",{children:"协调子任务"}),c.jsxs("dd",{children:["父任务 ",Ue(r.parent_task_id),r.coordinator_part?"("+r.coordinator_part+")":""]})]}):null,r.attachments&&r.attachments.length?c.jsxs("div",{children:[c.jsx("dt",{children:"附件"}),c.jsx("dd",{children:r.attachments.join("、")})]}):null,r.pr_url?c.jsxs("div",{children:[c.jsx("dt",{children:"PR"}),c.jsx("dd",{children:c.jsxs("a",{href:r.pr_url,target:"_blank",rel:"noopener noreferrer",children:["PR #",r.pr_number]})})]}):null]})}),c.jsx(Zt,{title:"prompt",children:c.jsx("div",{style:{whiteSpace:"pre-wrap",overflowWrap:"anywhere"},children:r.prompt||"(无 prompt)"})}),c.jsxs(Zt,{title:"操作与结果",children:[c.jsx(mg,{}),c.jsx("pre",{children:i.detailBody||"(暂无 result/error 输出)"}),i.costBox?c.jsx("pre",{children:i.costBox}):null]}),c.jsx(Zt,{title:"协调子任务",children:c.jsx(vg,{})}),c.jsx(Zt,{title:"子代理链路",children:c.jsx(yg,{})}),c.jsx(Zt,{title:"评审队列",children:c.jsx(hg,{})}),c.jsx(Zt,{title:"运行时审批队列",children:c.jsx(gg,{})}),c.jsx(Zt,{title:"给其他任务发消息",children:c.jsx(Sg,{})}),c.jsx(Zt,{title:"线程",children:c.jsx(pg,{})})]})}function xg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState([]),[b,B]=v.useState(null),[U,k]=v.useState(!1),[j,q]=v.useState(""),[tt,X]=v.useState(""),W=v.useCallback(async()=>{if(!i.keySaved){N([]);return}try{const nt=await lt(P.userKeys);N(nt.keys||[]),X("")}catch(nt){X(nt instanceof Error?nt.message:"加载 key 列表失败")}},[i.keySaved]);v.useEffect(()=>{W()},[W]);const G=async()=>{q(""),X(""),k(!1);try{const nt=await lt(P.userKeys,"POST",{label:o.trim()||"api-key"});B(nt),_(""),q("新 key 已生成,只显示一次:复制后请妥善保存。"),await W()}catch(nt){X(nt instanceof Error?nt.message:"生成 key 失败")}},dt=async()=>{if(b)try{await navigator.clipboard.writeText(b.api_key),k(!0)}catch{X("复制失败:请手动选中上方 key 文本复制")}},Mt=()=>{b&&(i.saveKeyInput(b.api_key),B(null),q("已存为当前浏览器 key(原有 key 未被撤销,需要时可单独撤销)。"))},Ft=async nt=>{const Xt=(()=>{try{return bl().slice(-4)}catch{return""}})(),ee=nt.id==="legacy"?"(主 key:撤销后当前浏览器保存的 key 也可能随之失效,需重新登录拿新 key)":nt.hint&&nt.hint===Xt?"(这就是本浏览器当前在用的 key,撤销后本页会立刻未连接)":"";if(window.confirm(`撤销 key「${nt.label}」(后 4 位 ${nt.hint||"无"})吗?${ee}撤销不可恢复。`)){q(""),X("");try{await lt(P.userKey(nt.id),"DELETE"),q(`已撤销 key「${nt.label}」。`),await W()}catch(ct){X(ct instanceof Error?ct.message:"撤销失败")}}};return c.jsxs(Zt,{id:"nav-key",title:"API Key",children:[c.jsxs(Dt,{children:[c.jsx("input",{type:"password",placeholder:"粘贴你的 X-API-Key(与调 API 用的同一个)",autoComplete:"off",value:r,onChange:nt=>m(nt.target.value)}),c.jsx("button",{className:"primary",onClick:()=>{i.saveKeyInput(r),m("")},children:"保存到本浏览器"}),c.jsx("button",{onClick:i.clearKeyInput,children:"清除"}),c.jsx("span",{className:"muted",children:i.keyState})]}),c.jsx("div",{children:c.jsx("span",{className:"muted",children:i.quotaText})}),!i.keySaved&&c.jsx("div",{children:c.jsx("span",{className:"muted",children:"先粘贴并保存已有 key,再生成或管理 key(生成接口本身也要用已有 key 鉴权)。"})}),i.keySaved&&c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("input",{placeholder:"新 key 备注(可选,默认 api-key,如 harness2-temp)",autoComplete:"off",value:o,onChange:nt=>_(nt.target.value)}),c.jsx("button",{className:"primary",onClick:()=>void G(),children:"生成新 key"}),c.jsx("button",{onClick:()=>void W(),children:"刷新列表"})]}),b&&c.jsxs("div",{children:[c.jsx("div",{children:c.jsxs("span",{className:"muted",children:["新 key(",b.label,",后 4 位 ",b.hint,"):只显示一次,关闭后无法再查看。"]})}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",readOnly:!0,value:b.api_key,onFocus:nt=>nt.target.select()}),c.jsx("button",{className:"primary",onClick:()=>void dt(),children:U?"已复制":"复制"}),c.jsx("button",{onClick:Mt,children:"存为当前浏览器 key"}),c.jsx("button",{onClick:()=>B(null),children:"关闭(不再显示)"})]})]}),j&&c.jsx("div",{children:c.jsx("span",{className:"muted",children:j})}),tt&&c.jsx("div",{children:c.jsx("span",{children:tt})}),c.jsxs("div",{className:"api-key-list",children:[C.length===0&&c.jsx("span",{className:"muted",children:"暂无 key(或列表加载失败,见上方报错)。"}),C.map(nt=>c.jsxs("div",{children:[c.jsx("span",{children:nt.label})," ",c.jsxs("span",{className:"muted",children:["后 4 位 ",nt.hint||"无"," · 创建 ",ka(nt.created_at)," · 最近使用 ",nt.last_used_at?ka(nt.last_used_at):"未使用过"]})," ",nt.revoked_at?c.jsxs("span",{className:"muted",children:["已撤销(",ka(nt.revoked_at),")"]}):c.jsx("button",{onClick:()=>void Ft(nt),children:"撤销"})]},nt.id))]})]})]})}function jg(){const i=Ut();return c.jsxs(Zt,{id:"adminCard",title:c.jsxs(c.Fragment,{children:["管理区 ",c.jsx("span",{className:"muted",children:"(仅全局管理员)"})]}),children:[c.jsx("div",{className:"muted",children:i.adminGate}),i.adminBody?c.jsxs(c.Fragment,{children:[c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"要查配额的用户 id",value:i.adminUserId,onChange:r=>i.setAdminUserId(r.target.value)}),c.jsx("button",{onClick:i.adminQuota,children:"查该用户配额"})]}),c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.adminSweep,children:"手动触发 sweep(清理陈旧 running 任务)"}),c.jsx("button",{onClick:i.adminBackup,children:"手动触发备份"})]}),c.jsx("div",{className:"muted",children:i.adminResult})]}):null]})}function Tg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return c.jsxs(Zt,{id:"nav-projects",title:"项目",children:[c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"项目",value:i.projectId,onChange:b=>i.selectProject(b.target.value),children:[i.projects.length===0?c.jsx("option",{value:"",children:"(先加载项目)"}):null,i.projects.map(b=>c.jsxs("option",{value:b.id,children:[b.name," (",Ue(b.id),")"]},b.id))]}),c.jsx("button",{onClick:i.refreshProjects,children:"刷新"})]}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"新项目名",value:r,onChange:b=>m(b.target.value)}),c.jsxs("select",{"aria-label":"从 GitHub 仓库选",value:o,onChange:b=>{_(b.target.value),b.target.value&&N(b.target.value)},children:[c.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选,或手动输入)"}),i.githubRepos.map(b=>c.jsx("option",{value:b.clone_url,children:b.repo_full_name},b.clone_url))]}),c.jsx("input",{type:"text",placeholder:"repo_url(可选)",value:C,onChange:b=>N(b.target.value)}),c.jsx("button",{onClick:async()=>{await i.createProject(r,C),m(""),N(""),_("")},children:"新建项目"})]}),c.jsx("span",{className:"muted",children:i.projectMsg})]})}function _g(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState("contributor"),C=i.projects.find(N=>N.id===i.projectId);return c.jsxs(Zt,{title:"项目成员",children:[C?c.jsxs("div",{className:"muted",children:[C.name," | ",C.id," | 仓库 ",C.repo_url||"未绑定"," | 我的角色 ",C.my_role||"未知"]}):c.jsx("div",{className:"muted",children:"先选项目"}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"成员 user_id 或用户名",value:r,onChange:N=>m(N.target.value)}),c.jsxs("select",{"aria-label":"邀请角色",value:o,onChange:N=>_(N.target.value),children:[c.jsx("option",{value:"viewer",children:"viewer(只读)"}),c.jsx("option",{value:"contributor",children:"contributor(可建任务)"}),c.jsx("option",{value:"maintainer",children:"maintainer(可批合并)"}),c.jsx("option",{value:"owner",children:"owner(可管项目)"})]}),c.jsx("button",{onClick:async()=>{await i.inviteMember(r,o),m("")},children:"邀请成员"}),c.jsx("button",{onClick:i.refreshMembers,children:"刷新成员"})]}),i.memberError?c.jsx("div",{className:"muted",children:i.memberError}):i.members.length===0?c.jsx("div",{className:"muted",children:"先选项目"}):c.jsx(cu,{children:i.members.map(N=>{const b=(N.username||"")+(N.username?"("+String(N.user_id).slice(0,8)+")":String(N.user_id).slice(0,8));return c.jsxs("li",{children:[c.jsx("span",{className:"row-main",children:b}),c.jsx("select",{"aria-label":"成员角色",value:N.role||"viewer",onChange:B=>void i.changeMemberRole(N.user_id,B.target.value),children:Vy.map(B=>c.jsx("option",{value:B,children:B},B))})]},N.user_id)})}),c.jsx("span",{className:"muted",children:i.memberMsg})]})}function Eg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return c.jsxs(Zt,{id:"nav-env",title:c.jsxs(c.Fragment,{children:["环境 ",c.jsx("span",{className:"muted",children:"(选、建、管:当前项目的基准检出)"})]}),children:[c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.refreshEnvs,children:"刷新"}),c.jsx("span",{className:"muted",children:i.envCount})]}),i.envs.length===0?c.jsx("div",{className:"muted",children:"先选项目"}):c.jsx(cu,{children:i.envs.map(b=>c.jsxs("li",{children:[c.jsxs("span",{className:"row-main",children:[b.name,"(",Ue(b.id),") / 分支 ",b.branch||"默认分支"," / 执行器 ",b.executor||"不限"," / 状态 ",b.status,b.status==="failed"&&b.error_text?" / 失败原因:"+b.error_text:""]}),b.status==="archived"?null:c.jsx("button",{onClick:()=>void i.archiveEnv(b.id),children:"归档"})]},b.id))}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"新环境名",value:r,onChange:b=>m(b.target.value)}),c.jsx("input",{type:"text",placeholder:"分支(可选,空=默认分支)",value:o,onChange:b=>_(b.target.value)}),c.jsxs("select",{"aria-label":"新环境执行器",value:C,onChange:b=>N(b.target.value),children:[c.jsx("option",{value:"",children:"执行器:不限"}),c.jsx("option",{value:"local",children:"local"}),c.jsx("option",{value:"docker",children:"docker"})]}),c.jsx("button",{onClick:async()=>{await i.createEnv(r,o,C),m(""),_("")},children:"新建环境"})]}),c.jsx("span",{className:"muted",children:i.envMsg})]})}function Ng(){const i=Ut(),[r,m]=v.useState("");return c.jsxs(Zt,{title:"仓库与环境上下文",children:[c.jsx("div",{className:"muted",children:i.envRepoLine||"先选项目"}),c.jsx("div",{className:"muted",children:i.envCount}),i.envRepoBar?c.jsxs(Dt,{children:[c.jsxs("select",{"aria-label":"补仓库",value:r,onChange:o=>m(o.target.value),children:[c.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选)"}),i.githubRepos.map(o=>c.jsx("option",{value:o.clone_url,children:o.repo_full_name},o.clone_url))]}),c.jsx("button",{onClick:()=>void i.saveEnvRepo(r),children:"保存仓库"})]}):null,c.jsx("span",{className:"muted",children:i.envRepoMsg})]})}function Cg(){const i=Ut();return c.jsxs(Zt,{id:"nav-workers",title:"Workers",children:[c.jsx(Dt,{children:c.jsx("button",{onClick:i.refreshWorkers,children:"刷新"})}),i.workersError?c.jsx("div",{className:"muted",children:i.workersError}):i.workers===null?c.jsx("div",{className:"muted",children:i.workersSummary||"未加载"}):i.workers.length===0?c.jsx("div",{className:"muted",children:"无 worker 注册"}):c.jsx(cu,{children:i.workers.map((r,m)=>{const o=r.running===void 0||r.running===null?"?":r.running,_=r.capacity===void 0||r.capacity===null?"?":r.capacity,C=Qh(r),N=r.alive!==void 0&&r.alive!==null?!!r.alive:C.age!==null&&C.age<=120,b=N?" / 在线":" / 离线(占用为上次上报值)";return c.jsx("li",{className:N?"is-online":"is-offline",children:c.jsxs("span",{className:"row-main",children:[r.worker_id||r.id||"?"," / ",r.executor||""," / 占用 ",o,"/",_,b," / 最后心跳 ",C.text]})},m)})})]})}function Ag(){const i=Ut();return c.jsxs(Zt,{title:"健康与配额",children:[c.jsxs(Dt,{children:[c.jsx("span",{className:"muted",children:i.healthText}),c.jsx("button",{onClick:i.refreshHealth,children:"刷新"})]}),c.jsx("div",{children:c.jsx("span",{className:"muted",children:i.quotaText})}),c.jsx("div",{className:"muted",children:i.workersSummary})]})}function Og(){const i=Ut();return c.jsxs(Zt,{id:"nav-skills",title:"技能与 MCP",children:[c.jsx("div",{className:"muted",children:"反映宿主租户 home,容器内 home 可能不同;重载只在 schema 枚举里,当前 pin 的二进制拒绝时原样 502;OAuth 只发起登录,不代表登录完成。"}),c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.refreshSkills,children:"刷新"}),c.jsx("span",{className:"muted",children:i.skillMsg})]}),c.jsx("h3",{children:"技能"}),i.skillError?c.jsx("div",{className:"muted",children:i.skillError}):c.jsx(Ml,{empty:"暂无技能",items:i.skills.map((r,m)=>c.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:"",r.detail?" - "+r.detail:""]},m))}),c.jsx("h3",{children:"应用"}),c.jsx(Ml,{empty:"暂无应用",items:i.apps.map((r,m)=>c.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:""]},m))}),c.jsx("h3",{children:"MCP 服务"}),c.jsx(Ml,{empty:"暂无 MCP 服务",items:i.mcpServers.map((r,m)=>{const o=r.detail||r.details||r.state||"";return c.jsxs("span",{className:"row-main",children:[r.name||r.id||""," | 状态 ",r.status||"",o?" | "+o:""]},m)})})]})}function Mg(){const i=Ut(),[r,m]=v.useState("");return c.jsxs(Zt,{title:"MCP 操作",children:[c.jsxs(Dt,{children:[c.jsx("button",{onClick:i.reloadMcp,children:"重载配置"}),c.jsx("span",{className:"muted",children:i.mcpMsg})]}),c.jsxs(Dt,{children:[c.jsx("input",{type:"text",placeholder:"MCP 服务名",value:r,onChange:o=>m(o.target.value)}),c.jsx("button",{onClick:()=>void i.mcpOauth(r),children:"发起 OAuth 登录"}),c.jsx("span",{className:"muted",children:i.mcpOauthMsg})]}),i.mcpOauthBox?c.jsx("pre",{children:i.mcpOauthBox}):null]})}function zg(){const i=Ut(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(""),[b,B]=v.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("input",{placeholder:"自动化名称(同项目内启用中的名称唯一)",style:{width:"100%"},value:r,onChange:U=>m(U.target.value)}),c.jsx("textarea",{placeholder:"定时任务内容(创建只登记定义与到期状态;执行由后续执行器经 claim 抢单后建任务,不另起调度器)",value:o,onChange:U=>_(U.target.value)}),c.jsxs(Dt,{children:[c.jsx("input",{placeholder:"间隔秒数(默认 86400,最小 60)",style:{width:"40%"},value:C,onChange:U=>N(U.target.value)}),c.jsx("input",{placeholder:"仓库(可选)",style:{width:"40%"},value:b,onChange:U=>B(U.target.value)}),c.jsx("button",{className:"primary",onClick:async()=>{await i.createAutomation(r,o,C,b),m(""),_(""),N(""),B("")},children:"创建自动化"}),c.jsx("button",{onClick:i.refreshAutomations,children:"刷新自动化"}),c.jsx("span",{className:"muted",children:i.autoMsg})]}),c.jsx(Ml,{empty:"(暂无自动化)",items:i.automations.map(U=>c.jsxs("span",{className:"row-main",children:["[",U.status,U.due?"|到期":"","] ",U.name,"|每 ",U.interval_seconds," 秒|下次 ",ka(U.next_run_at),U.status==="active"?c.jsxs(c.Fragment,{children:[" ",c.jsx("button",{onClick:()=>i.cancelAutomation(U.id),children:"取消"})]}):null]},U.id))})]})}function Rg(){var m,o,_,C;const i=Ut(),r=i.triage;return i.triageError?c.jsx("div",{className:"muted",children:i.triageError}):r?c.jsxs(c.Fragment,{children:[c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["到期自动化(",((m=r.counts)==null?void 0:m.automations_due)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.automations_due||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:[N.name,"|每 ",N.interval_seconds," 秒"]},b))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["失败/中断任务(",((o=r.counts)==null?void 0:o.failed_tasks)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.failed_tasks||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:[Ue(N.id),"|",N.status,"|",String(N.prompt||"").slice(0,80)]},b))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["待处理后续消息(",((_=r.counts)==null?void 0:_.pending_followups)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.pending_followups||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:["任务 ",Ue(N.task_id),"|",String(N.body||"").slice(0,80)]},b))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["最近自动化产出(",((C=r.counts)==null?void 0:C.recent_runs)||0,")"]}),c.jsx(Ml,{empty:"(无)",items:(r.recent_runs||[]).map((N,b)=>c.jsxs("span",{className:"row-main",children:[Ue(N.automation_id),"|",N.status,N.task_id?"|任务 "+Ue(N.task_id):"",N.task_status?"|"+N.task_status:""]},b))})]})]}):c.jsx("div",{className:"muted",children:"(先选项目)"})}function Dg(){return c.jsx(Zt,{id:"nav-automations",title:"自动化",children:c.jsx(zg,{})})}function Ug(){const i=Ut();return c.jsxs(Zt,{id:"nav-triage",title:"分诊收件箱",children:[c.jsx(Dt,{children:c.jsx("button",{onClick:i.refreshTriage,children:"刷新分诊"})}),c.jsx(Rg,{})]})}const Hg=[["#sec-dispatch","派发"],["#sec-tasks","任务"],["#sec-conv","对话"],["#sec-projects","项目"],["#sec-env","环境"],["#sec-workers","Workers"],["#sec-skills","技能"],["#sec-automations","自动化"],["#sec-triage","分诊"],["#sec-admin","管理区"],["#sec-key","API Key"]];function Bg(){return c.jsxs("header",{className:"dash-topbar",children:[c.jsxs("div",{className:"dash-topbar-row",children:[c.jsx("span",{className:"dash-brand",children:"Codex 命令台"}),c.jsx(qg,{}),c.jsx("span",{className:"muted dash-hide-sm",children:c.jsx(wg,{})}),c.jsx("span",{className:"muted dash-hide-sm",children:c.jsx(Yg,{})}),c.jsx("span",{className:"muted dash-stamp",children:c.jsx(kg,{})})]}),c.jsx("nav",{className:"dash-nav","aria-label":"页面导航",children:Hg.map(([i,r])=>c.jsx("a",{href:i,children:r},i))})]})}function qg(){const i=Ut();return c.jsx("span",{className:i.keySaved?"dash-status ok":"dash-status off",children:i.keySaved?"● 已连接":"○ 未连接"})}function wg(){return c.jsx(c.Fragment,{children:Ut().healthText})}function Yg(){return c.jsx(c.Fragment,{children:Ut().quotaText})}function kg(){return c.jsxs(c.Fragment,{children:["自动刷新 · 每 10 秒 · 已刷新 ",Ut().refreshStamp]})}function Gg(){const i=lg();Py(m=>i.refreshAll(m),1e4),tg(()=>i.refreshSlow(),6e4);const r=()=>{var m;(m=document.getElementById("sec-dispatch"))==null||m.scrollIntoView({behavior:"smooth"})};return c.jsxs(Gh.Provider,{value:i,children:[c.jsx(Bg,{}),c.jsxs("main",{className:"dash-page",children:[c.jsx(ag,{}),c.jsxs("div",{className:"dash-col dash-col-left",children:[c.jsxs("section",{id:"sec-tasks",className:"dash-section card",children:[c.jsx("h2",{children:"任务列表"}),c.jsx(ig,{onNew:r})]}),c.jsxs("section",{id:"sec-projects",className:"dash-section",children:[c.jsx(Tg,{}),c.jsx(_g,{})]})]}),c.jsxs("div",{className:"dash-col dash-col-mid",children:[c.jsx("section",{id:"sec-dispatch",className:"dash-section",children:c.jsx(ng,{})}),c.jsxs("section",{id:"sec-conv",className:"dash-section",children:[c.jsxs("div",{className:"card",children:[c.jsx("h2",{children:"对话"}),c.jsx(dg,{})]}),c.jsx(bg,{})]})]}),c.jsxs("div",{className:"dash-col dash-col-right",children:[c.jsxs("section",{id:"sec-env",className:"dash-section",children:[c.jsx(Eg,{}),c.jsx(Ng,{})]}),c.jsxs("section",{id:"sec-workers",className:"dash-section",children:[c.jsx(Cg,{}),c.jsx(Ag,{})]}),c.jsxs("section",{id:"sec-skills",className:"dash-section",children:[c.jsx(Og,{}),c.jsx(Mg,{})]}),c.jsx("section",{id:"sec-automations",className:"dash-section",children:c.jsx(Dg,{})}),c.jsx("section",{id:"sec-triage",className:"dash-section",children:c.jsx(Ug,{})}),c.jsx("section",{id:"sec-admin",className:"dash-section",children:c.jsx(jg,{})}),c.jsx("section",{id:"sec-key",className:"dash-section",children:c.jsx(xg,{})})]})]})]})}Gy.createRoot(document.getElementById("root")).render(c.jsx(Dy.StrictMode,{children:c.jsx(Gg,{})}));
+