diff --git a/cloud/console-react/src/App.tsx b/cloud/console-react/src/App.tsx
index 3a81d2c..d44afec 100644
--- a/cloud/console-react/src/App.tsx
+++ b/cloud/console-react/src/App.tsx
@@ -22,10 +22,19 @@ import TriageSection from "./sections/TriageSection";
// Layout only: ONE scrollable console page in GitHub Primer style —
// a dark header bar (name + real connection status + health + quota
// + refresh stamp + anchor nav as header links), a data-cards row,
-// then every module as a bordered section in order. No icon-rail
-// column, no left list column, no right panel column, no view
-// switching. Detail/context panels sit under their own sections
-// below (detail under 对话, members under 项目, and so on).
+// then every module as a bordered section. At medium/wide widths the
+// sections live in three independent column wrappers (left: tasks +
+// projects; middle: dispatch + conversation; right: environments +
+// Workers + skills + automations + triage + admin + API key) so each
+// column's modules stack tightly on their own, instead of sharing
+// grid rows with the other columns — shared rows were the blank-gap
+// bug (a tall task list in row 2 held the whole row tall, so the
+// conversation in row 3 started far below a short dispatch box).
+// At narrow width the wrappers use display:contents plus an explicit
+// order per section, so the single column stacks in the original
+// DOM order (dispatch, tasks, conversation, projects, …), not in
+// column-group order. Detail/context panels sit under their own
+// sections below (detail under 对话, members under 项目, and so on).
const NAV: Array<[string, string]> = [
["#sec-dispatch", "派发"], ["#sec-tasks", "任务"], ["#sec-conv", "对话"],
["#sec-projects", "项目"], ["#sec-env", "环境"], ["#sec-workers", "Workers"],
@@ -78,48 +87,54 @@ export default function App() {
-
-
-
-
-
-
-
-
-
-
-
+
+
+
);
diff --git a/cloud/console-react/src/tokens.css b/cloud/console-react/src/tokens.css
index d6843d9..0647d5a 100644
--- a/cloud/console-react/src/tokens.css
+++ b/cloud/console-react/src/tokens.css
@@ -4,9 +4,11 @@
no pill shapes, no coloured page backgrounds, no shadows beyond
GitHub's hairline button shadow. Layout is width-adaptive (see the
"Width-adaptive columns" block below): 1 column under 900px,
- 2 columns at 900-1399px, 3 columns at 1400px and up — CSS grid
- placement per section id only, DOM order untouched, so the narrow
- single-column order is the original stacked order. */
+ 2 columns at 900-1399px, 3 columns at 1400px and up — each column
+ is an independent wrapper (.dash-col) whose sections stack tightly
+ on their own; the narrow single column is restored to the original
+ stacked order with display:contents plus an explicit order per
+ section (see the narrow block). */
:root{
--text:#1f2328; --muted:#656d76; --subtle:#6e7781;
--line:#d0d7de; --line-muted:#d8dee4;
@@ -151,45 +153,53 @@ pre{background:var(--inset-bg);color:var(--text);border:1px solid var(--line);bo
.gh-comment-box textarea:focus{box-shadow:none}
.gh-comment-footer{display:flex;justify-content:flex-end;gap:8px;padding:8px;border-top:1px solid var(--line);background:var(--subtle-bg)}
.conv-divider{border-top:1px solid var(--line);margin:4px 0}
-/* Width-adaptive columns — CSS grid placement only, no DOM change,
- no duplicated sections, nothing hidden at any width.
- Narrow (<900px): .dash-page stays the base flex column, so sections
- stack in DOM order (dispatch, tasks, conversation, projects,
- environments, Workers, skills, automations, triage, admin, API key).
- Medium (900-1399px): left = tasks + projects; right = everything
- else, in DOM order down the right column. Wide (>=1400px): left =
- tasks + projects; middle (flexible) = dispatch + conversation;
- right = environments + Workers + skills + automations + triage +
- admin + API Key. Each section gets an explicit grid-column AND
- grid-row per breakpoint (not auto-placement), so the stacking is
- deterministic and each column's sections stay in DOM order;
- align-items:start keeps every box only as tall as its content
- instead of stretching to its row. .dash-cards spans all columns
- at every grid width. */
+/* Width-adaptive columns — independent column wrappers, NOT shared
+ grid rows. Why: the previous layout gave every section an explicit
+ grid-column AND grid-row, so one grid row's height was the tallest
+ section in that row. A tall task list in row 2 held the whole row
+ tall, and the conversation (row 3) started far below a short
+ dispatch box — align-items:start only kept each box at its own
+ content height, it never pulled the next row up. That is the
+ blank gap between modules. Now each .dash-col is one grid item
+ whose sections stack in a flex column with a 20px gap, so a module
+ always follows the previous module in its own column, whatever
+ the other columns' heights are. The only blank left is at the
+ bottom of a shorter column, which is normal for column layouts,
+ not a gap between two modules.
+ Medium (900-1399px): left = tasks + projects; right column =
+ middle wrapper (dispatch + conversation) followed by the right
+ wrapper (environments + Workers + skills + automations + triage +
+ admin + API Key), in that order. Wide (>=1400px): left / middle /
+ right wrappers side by side. .dash-cards spans all columns at
+ 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}
@media (min-width:900px) and (max-width:1399px){
.dash-page{display:grid;grid-template-columns:320px minmax(0,1fr);align-items:start}
.dash-page > .dash-cards{grid-column:1 / -1;grid-row:1}
- .dash-section{min-width:0}
- #sec-tasks{grid-column:1;grid-row:2} #sec-projects{grid-column:1;grid-row:3}
- #sec-dispatch{grid-column:2;grid-row:2} #sec-conv{grid-column:2;grid-row:3}
- #sec-env{grid-column:2;grid-row:4} #sec-workers{grid-column:2;grid-row:5}
- #sec-skills{grid-column:2;grid-row:6} #sec-automations{grid-column:2;grid-row:7}
- #sec-triage{grid-column:2;grid-row:8} #sec-admin{grid-column:2;grid-row:9}
- #sec-key{grid-column:2;grid-row:10}
+ .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 > .dash-cards{grid-column:1 / -1;grid-row:1}
.dash-cards{grid-template-columns:repeat(6,1fr)}
- .dash-section{min-width:0}
- #sec-tasks{grid-column:1;grid-row:2} #sec-projects{grid-column:1;grid-row:3}
- #sec-dispatch{grid-column:2;grid-row:2} #sec-conv{grid-column:2;grid-row:3}
- #sec-env{grid-column:3;grid-row:2} #sec-workers{grid-column:3;grid-row:3}
- #sec-skills{grid-column:3;grid-row:4} #sec-automations{grid-column:3;grid-row:5}
- #sec-triage{grid-column:3;grid-row:6} #sec-admin{grid-column:3;grid-row:7}
- #sec-key{grid-column:3;grid-row:8}
+ .dash-col-left{grid-column:1;grid-row:2}
+ .dash-col-mid{grid-column:2;grid-row:2}
+ .dash-col-right{grid-column:3;grid-row:2}
}
@media (max-width:899px){ /* 899, not 900: narrow is strictly <900px, so 900px exactly already gets the 2-column grid + 3-per-row cards */
+ /* Narrow single column: unwrap the column wrappers so sections
+ stack as direct flex items of .dash-page, in the ORIGINAL order
+ (dispatch first), not in column-group order (tasks first).
+ Browsers without display:contents degrade to grouped stacking,
+ which is still tight — just in a different order. */
+ .dash-col{display:contents}
+ #sec-dispatch{order:1} #sec-tasks{order:2} #sec-conv{order:3}
+ #sec-projects{order:4} #sec-env{order:5} #sec-workers{order:6}
+ #sec-skills{order:7} #sec-automations{order:8} #sec-triage{order:9}
+ #sec-admin{order:10} #sec-key{order:11}
.dash-cards{grid-template-columns:repeat(2,1fr)}
.dash-hide-sm{display:none}
.dash-page{padding:14px}
diff --git a/cloud/console.html b/cloud/console.html
index 890b80f..9fd32e7 100644
--- a/cloud/console.html
+++ b/cloud/console.html
@@ -4,7 +4,7 @@
Codex 命令台
-
-
+`),O(Z||"(暂无 result/error 输出)")}catch{}dl(H.id),Bl(H.id),Ye(H.id),Vt(H.id),Hl(H),ol(H.id),ll(H.id),ml(H.id),ql(H.id)}},[dl,Bl,Ye,Vt,Hl,ol,ll,ml,ql]),yn=y.useCallback(async H=>{const R=le.current;if(!R)return;const Z={cancel:"确定取消该任务吗?",merge:"确定把 completed 任务标为 merged 吗?",pr:"确定为该任务提 PR 吗?(会在仓库真实建 PR)"};if(!(Z[H]&&!window.confirm(Z[H])))try{const F=await lt(P.taskAction(R.id,H),"POST",{});E(H+" 已提交:"+JSON.stringify(F).slice(0,300)),r(),await Wl(R.id)}catch(F){E(H+" 失败:"+F.message)}},[Wl,r]),Ke=y.useCallback(async()=>{const H=le.current;if(H)try{const R=await lt(P.taskCost(H.id));b(JSON.stringify(R,null,2).slice(0,4e3))}catch(R){b("查成本失败:"+R.message)}},[]),La=y.useCallback(async H=>{const R=le.current;if(R){if(!H.trim()){et("分支消息必填");return}if(!iu.includes(R.status)){et("仅终态任务可分支");return}try{const Z=await lt(P.taskFork(R.id),"POST",{message:H.trim()});et("分支任务已建:"+Z.id.slice(0,8)),r()}catch(Z){et("分支失败:"+Z.message)}}},[r]),va=y.useCallback(async H=>{const R=le.current;if(R)try{await lt(P.taskReviews(R.id),"POST",H),Ft("评审已登记(requested)"),await Ye(R.id)}catch(Z){Ft("登记评审需求失败:"+Z.message)}},[Ye]),fu=y.useCallback(H=>{const R=le.current;if(!R)return;const Z=window.prompt("输入该条评审的 findings(将写回记录并标为 completed):");Z!==null&<(P.taskReviewFindings(R.id,H),"POST",{findings:Z}).then(()=>void Ye(R.id)).catch(F=>Ft("写 findings 失败:"+F.message))},[Ye]),ru=y.useCallback((H,R)=>{const Z=le.current;if(!Z)return;const F=R==="approved"?"approve":"deny";lt(P.taskApprovalDecision(Z.id,H,F),"POST",{}).then(()=>{J("已记录"+(R==="approved"?"允许":"拒绝")+"(当前版本只留回执,不拦截实时行为)"),Vt(Z.id)}).catch(Nt=>J("决定失败:"+Nt.message))},[Vt]),$l=y.useCallback(async(H,R,Z)=>{const F=le.current;if(F){if(!R.trim()){Q("目标任务 id 不能为空");return}if(!Z.trim()){Q("消息正文不能为空");return}try{const Nt=await lt(P.taskMessagesTo(R.trim()),"POST",{from_task_id:F.id,body:Z.trim(),mode:H});Q("已发送("+Nt.delivery+")"),await ll(F.id)}catch(Nt){Q("发送失败:"+Nt.message)}}},[ll]),pe=y.useCallback((H,R)=>{const Z=le.current;if(!Z)return;if(!["completed","failed","interrupted"].includes(Z.status)){Gt("仅 completed/failed/interrupted 任务可操作线程(merged/merge-failed 不可改,服务端同样 409)");return}const F={};if(H==="rename"){if(!R.trim()){Gt("新线程名不能为空");return}F.name=R.trim()}lt(P.taskThreadAction(Z.id,H),"POST",F).then(Nt=>{Gt(H+" 已提交:"+JSON.stringify(Nt).slice(0,300)),ml(Z.id),ql(Z.id)}).catch(Nt=>Gt(H+" 失败:"+Nt.message))},[ml,ql]),hl=y.useCallback(async H=>{const R=le.current;if(!R)return;const Z=H.trim();if(!Z){ee("消息不能为空");return}try{iu.includes(R.status)&&R.status!=="merged"?(await lt(P.taskContinue(R.id),"POST",{message:Z}),ee("已重新排队,同一会话继续"),r(),await Wl(R.id)):["queued","running"].includes(R.status)?(await lt(P.taskFollowups(R.id),"POST",{body:Z,mode:"direct"}),ee("已直接发送"),await dl(R.id),await Bl(R.id)):ee("merged/merge-failed 任务不可继续,也不可发后续消息")}catch(F){ee("发送失败:"+F.message)}},[Wl,r,dl,Bl]),be=y.useCallback(async()=>{const H=le.current;if(!H){te("先选一个任务");return}try{const R=await lt(P.taskTrace(H.id)),Z=new Blob([JSON.stringify({task_id:H.id,status:R.status,note:R.note||"",count:(R.entries||[]).length,entries:R.entries||[]},null,2)],{type:"application/json"}),F=document.createElement("a");F.href=URL.createObjectURL(Z),F.download="trace-"+H.id.slice(0,8)+".json",document.body.appendChild(F),F.click(),F.remove(),setTimeout(()=>URL.revokeObjectURL(F.href),1e3),te("已下载完整链路 "+(R.entries||[]).length+" 条")}catch(R){te("下载失败:"+R.message)}},[]);return y.useEffect(()=>()=>qe(),[qe]),{currentTask:m,detailBody:_,actionMsg:N,actionReasons:X,costBox:G,forkVisible:w,setForkVisible:at,forkMsg:st,coordChildren:k,agents:Ut,agentsNote:Me,reviews:fe,reviewMsg:vt,reviewError:Pt,traceEntries:re,traceNote:tl,traceDone:q,traceKind:tt,setTraceKind:xt,traceMsg:yt,followups:ze,approvals:v,approvalMsg:W,peerMessages:gt,peerMsg:jt,threadText:nt,threadGateNote:Va,threadMsg:Le,threadList:Ot,chatMsg:Fl,chatHistory:ha,showDetail:Wl,refreshDetailLists:vn,doAction:yn,taskCost:Ke,forkTask:La,postReview:va,submitFindings:fu,decideApproval:ru,postPeer:$l,threadAction:pe,sendChatMessage:hl,downloadTrace:be,refreshReviews:()=>void Ye(),refreshApprovals:()=>void Vt()}}function Jy(c){const[r,m]=y.useState([]),[o,_]=y.useState(""),[O,N]=y.useState(null),[E,X]=y.useState(""),D=y.useCallback(async at=>{const st=at!==void 0?at:c();if(!st){m([]);return}try{const et=await lt(P.projectAutomations(st));m(et.automations||[])}catch(et){_("自动化加载失败:"+et.message)}},[c]),G=y.useCallback(async(at,st,et,k)=>{const dt=c();if(!dt){_("先选项目");return}if(!at.trim()){_("自动化名称必填");return}if(!st.trim()){_("定时任务内容必填");return}const Ut={name:at.trim(),prompt:st.trim()};et.trim()&&(Ut.interval_seconds=parseInt(et.trim(),10)),k.trim()&&(Ut.repo_url=k.trim());try{await lt(P.projectAutomations(dt),"POST",Ut),_("自动化已创建(登记定义,到期后由执行器认领)"),await D(dt)}catch(ye){_("创建失败:"+ye.message)}},[c,D]),b=y.useCallback(at=>{const st=c();st&<(P.projectAutomationCancel(st,at),"POST",{}).then(()=>{_("自动化已取消"),D(st)}).catch(et=>_("取消失败:"+et.message))},[c,D]),w=y.useCallback(async at=>{const st=at!==void 0?at:c();if(!st){N(null);return}try{const et=await lt(P.projectTriage(st));N(et),X("")}catch(et){X("分诊加载失败:"+et.message)}},[c]);return{automations:r,autoMsg:o,triage:O,triageError:E,refreshAutomations:D,createAutomation:G,cancelAutomation:b,refreshTriage:w}}function Fy(c,r){const m=y.useRef(c);m.current=c,y.useEffect(()=>{const o=setInterval(()=>{const _=document.activeElement;m.current(_?_.tagName==="SELECT":!1)},r);return()=>clearInterval(o)},[r])}function Wy(c,r){const m=y.useRef(c);m.current=c,y.useEffect(()=>{const o=setInterval(()=>m.current(),r);return()=>clearInterval(o)},[r])}function $y(c){const r=m=>String(m).padStart(2,"0");return r(c.getHours())+":"+r(c.getMinutes())+":"+r(c.getSeconds())}function Iy(){var et;const c=Ly(),r=ky(),m=y.useRef("");m.current=c.projectId;const o=y.useCallback(()=>m.current,[]),_=Jy(o),O=y.useCallback(k=>{const dt=c.projects.find(Ut=>Ut.id===k);return dt&&dt.my_role||null},[c.projects]),N=y.useCallback(()=>{r.refreshTasks(void 0,m.current)},[r]),E=Ky(O,N),[X,D]=y.useState("--:--:--"),G=y.useCallback(k=>{c.setProjectId(k),m.current=k,r.refreshTasks(k),c.refreshEnvs(k),c.refreshMembers(k),c.refreshSkills(k),_.refreshAutomations(k),_.refreshTriage(k)},[c,r,_]),b=(et=c.projects[0])==null?void 0:et.id;y.useEffect(()=>{!c.projectId&&b&&G(b)},[c.projectId,b,G]);const w=y.useCallback(k=>{c.saveKeyInput(k),k.trim()&&(c.refreshHealth(),c.refreshProjects(),c.refreshWorkers(),m.current&&(r.refreshTasks(m.current),c.refreshEnvs(m.current),c.refreshMembers(m.current)),c.loadRelayModels(),c.loadQuota(),c.loadGithubRepos(),c.probeAdmin())},[c,r]),at=y.useCallback(k=>{if(D($y(new Date)),!Rl()){c.refreshHealth();return}r.refreshTasks(void 0,m.current),c.refreshHealth(),c.loadQuota(),c.refreshWorkers(),c.refreshMembers(),c.refreshSkills(),_.refreshAutomations(),_.refreshTriage(),E.refreshDetailLists(),k||(c.refreshProjects(),c.refreshEnvs())},[c,r,_,E]),st=y.useCallback(()=>{Rl()&&(c.loadRelayModels(),c.loadGithubRepos())},[c]);return y.useEffect(()=>{c.refreshHealth(),c.refreshProjects(),c.refreshWorkers(),c.loadQuota(),c.loadGithubRepos(),Rl()&&c.loadRelayModels(),c.probeAdmin()},[]),{keySaved:c.keySaved,keyState:c.keyState,saveKeyInput:w,clearKeyInput:c.clearKeyInput,quotaText:c.quotaText,healthText:c.healthText,refreshHealth:c.refreshHealth,adminGate:c.adminGate,adminBody:c.adminBody,adminResult:c.adminResult,adminUserId:c.adminUserId,setAdminUserId:c.setAdminUserId,adminQuota:c.adminQuota,adminSweep:c.adminSweep,adminBackup:c.adminBackup,projects:c.projects,projectId:c.projectId,projectMsg:c.projectMsg,selectProject:G,refreshProjects:c.refreshProjects,createProject:c.createProject,githubRepos:c.githubRepos,workers:c.workers,workersSummary:c.workersSummary,workersError:c.workersError,refreshWorkers:c.refreshWorkers,members:c.members,memberMsg:c.memberMsg,memberError:c.memberError,refreshMembers:()=>void c.refreshMembers(),inviteMember:c.inviteMember,changeMemberRole:c.changeMemberRole,skills:c.skills,apps:c.apps,mcpServers:c.mcpServers,skillMsg:c.skillMsg,skillError:c.skillError,mcpMsg:c.mcpMsg,mcpOauthMsg:c.mcpOauthMsg,mcpOauthBox:c.mcpOauthBox,refreshSkills:()=>void c.refreshSkills(),reloadMcp:c.reloadMcp,mcpOauth:c.mcpOauth,envs:c.envs,envCount:c.envCount,envMsg:c.envMsg,envRepoLine:c.envRepoLine,envRepoBar:c.envRepoBar,envRepoMsg:c.envRepoMsg,envSelect:c.envSelect,setEnvSelect:c.setEnvSelect,refreshEnvs:()=>void c.refreshEnvs(),createEnv:c.createEnv,archiveEnv:c.archiveEnv,saveEnvRepo:c.saveEnvRepo,models:c.models,modelCustomVisible:c.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:E.currentTask,detailBody:E.detailBody,actionMsg:E.actionMsg,actionReasons:E.actionReasons,showDetail:k=>void E.showDetail(k),doAction:E.doAction,taskCost:E.taskCost,costBox:E.costBox,forkVisible:E.forkVisible,setForkVisible:E.setForkVisible,forkTask:E.forkTask,forkMsg:E.forkMsg,coordChildren:E.coordChildren,coordText:"",agents:E.agents,agentsNote:E.agentsNote,reviews:E.reviews,reviewMsg:E.reviewMsg,reviewError:E.reviewError,refreshReviews:E.refreshReviews,postReview:E.postReview,submitFindings:E.submitFindings,traceEntries:E.traceEntries,traceNote:E.traceNote,traceDone:E.traceDone,traceKind:E.traceKind,setTraceKind:E.setTraceKind,downloadTrace:E.downloadTrace,traceMsg:E.traceMsg,sendChatMessage:E.sendChatMessage,chatMsg:E.chatMsg,chatHistory:E.chatHistory,followups:E.followups,approvals:E.approvals,approvalMsg:E.approvalMsg,refreshApprovals:E.refreshApprovals,decideApproval:E.decideApproval,peerMessages:E.peerMessages,peerMsg:E.peerMsg,postPeer:E.postPeer,automations:_.automations,autoMsg:_.autoMsg,refreshAutomations:()=>void _.refreshAutomations(),createAutomation:_.createAutomation,cancelAutomation:_.cancelAutomation,triage:_.triage,triageError:_.triageError,refreshTriage:()=>void _.refreshTriage(),threadText:E.threadText,threadGateNote:E.threadGateNote,threadMsg:E.threadMsg,threadList:E.threadList,threadAction:E.threadAction,dispatch:async(k,dt)=>{const Ut=await r.dispatch(k,dt);return r.refreshTasks(m.current),Ut},dispatchMsg:"",refreshAll:at,refreshSlow:st,refreshStamp:X}}function cu({label:c,value:r,sub:m}){return s.jsxs("div",{className:"dash-card data-card",children:[s.jsx("div",{className:"dash-card-label",children:c}),s.jsx("div",{className:"dash-card-value",children:r}),s.jsx("div",{className:"muted",children:m})]})}function Py(){const c=At(),r=c.healthText==="未加载"?"未加载":c.healthText.includes("worker_ok=true")?"正常":c.healthText.includes("worker_ok=false")?"异常":c.healthText.includes("加载失败")?"加载失败":"未知",m=c.quotaText.match(/剩余 \$([0-9.]+)/),o=c.quotaText.includes("加载失败")?"加载失败":c.quotaText.includes("未填 key")||c.quotaText==="未加载"?"未加载":m?"$"+m[1]:"配额",_=["running","completed","failed","queued","merged","interrupted"].map(b=>c.tasks.filter(w=>w.status===b).length).map((b,w)=>["running","completed","failed","queued","merged","interrupted"][w]+" "+b).join(" | "),O=c.projects.find(b=>b.id===c.projectId),N=c.taskError?{value:"加载失败",sub:c.taskError}:c.projectId?{value:String(c.tasks.length),sub:c.taskCountText+" | "+_+(O?" | "+O.name:"")}:{value:"先选项目",sub:c.projectMsg||"项目加载后自动选第一个"};let E;if(c.workersError)E={value:"加载失败",sub:c.workersError};else if(c.workers===null)E={value:c.workersSummary||"未加载",sub:"完整 worker 清单仅全局管理员可见"};else{const b=c.workers.filter(w=>{if(w.alive!==void 0&&w.alive!==null)return!!w.alive;const at=wh(w).age;return at!==null&&at<=120}).length;E={value:b+" 在线 / "+c.workers.length,sub:c.workers.length-b+" 离线"}}const X=c.projectMsg.includes("加载失败")?{value:"加载失败",sub:c.projectMsg}:{value:c.projects.length+" 个",sub:O?"当前项目:"+O.name:"未选项目(加载后自动选第一个)"},D=[c.envMsg,c.memberError,c.skillError].filter(b=>b&&b.includes("失败")),G=c.projectId?D.length?{value:"部分加载失败",sub:D.join(" | ")}:{value:c.envs.length+" 个环境",sub:c.members.length+" 成员 | "+c.skills.length+" 技能 | "+c.apps.length+" 应用 | "+c.mcpServers.length+" MCP"}:{value:"先选项目",sub:"选项目后显示环境 / 成员 / 技能计数"};return s.jsxs("section",{className:"dash-cards","aria-label":"数据卡片",children:[s.jsx(cu,{label:"健康",value:r,sub:c.healthText}),s.jsx(cu,{label:"配额",value:o,sub:c.quotaText}),s.jsx(cu,{label:"任务",value:N.value,sub:N.sub}),s.jsx(cu,{label:"Workers",value:E.value,sub:E.sub}),s.jsx(cu,{label:"项目",value:X.value,sub:X.sub}),s.jsx(cu,{label:"项目数据",value:G.value,sub:G.sub})]})}function Ze({id:c,className:r,title:m,children:o}){return s.jsxs("section",{id:c,className:"card"+(r?" "+r:""),children:[m?s.jsx("h2",{children:m}):null,o]})}function Yt({children:c}){return s.jsx("div",{className:"bar",children:c})}function Dl({items:c,empty:r}){return c.length?s.jsx("ul",{className:"data-list",children:c.map((m,o)=>s.jsx("li",{children:m},o))}):s.jsx("div",{className:"muted",children:r||"(暂无)"})}function su({children:c}){return s.jsx("ul",{className:"data-list",children:c})}function tg(){const c=At(),[r,m]=y.useState(""),[o,_]=y.useState(""),[O,N]=y.useState(!1),[E,X]=y.useState(!1),[D,G]=y.useState("docker"),[b,w]=y.useState(""),[at,st]=y.useState(""),[et,k]=y.useState(""),[dt,Ut]=y.useState(""),[ye,Me]=y.useState(""),[Jt,fe]=y.useState(""),[it,vt]=y.useState(""),Ft=y.useRef(null),Pt=y.useRef(null),kt=y.useRef(null),[re,Ht]=y.useState("");async function tl(){var yt,te,ze;if(Ht(""),!c.projectId){Ht("先选项目");return}if(!r.trim()){Ht("prompt 必填");return}const U={project_id:c.projectId,prompt:r.trim()};c.envSelect&&(U.environment_id=c.envSelect),D&&(U.executor=D);const q=at.trim()||b;q&&(U.model=q),et&&(U.effort=et);const K=Jt.trim()||ye;if(K&&(U.child_model=K),it&&(U.child_effort=it),dt){if(dt==="full"&&!window.confirm("完全访问 = 自动批准 + 不受工作区限制,agent 可读写工作区外路径。确认提交吗?"))return;U.approval=dt}if(E){if(dt==="full"){Ht("计划模式不能与完全访问同用");return}if(O){Ht("计划模式不能与 goal 模式同用");return}U.plan=1}O&&(U.goal_mode=1);const tt=o.trim();if(tt){try{U.coordinator_parts=JSON.parse(tt)}catch{Ht("协调员子任务 JSON 解析失败");return}if(!Array.isArray(U.coordinator_parts)){Ht("协调员子任务必须是数组");return}if(O||E){Ht("协调员任务不能与 goal/计划模式同用:协调员任务本身不跑模型回合,请取消 goal/计划勾选,或清空协调员 JSON");return}}const xt=Zy(((yt=Ft.current)==null?void 0:yt.files)||null,((te=Pt.current)==null?void 0:te.files)||null,((ze=kt.current)==null?void 0:ze.files)||null);try{const ne=await c.dispatch(U,xt);Ht(ne),m(""),_(""),Ft.current&&(Ft.current.value=""),Pt.current&&(Pt.current.value=""),kt.current&&(kt.current.value="")}catch(ne){Ht("提交失败:"+((ne==null?void 0:ne.message)||String(ne)))}}return s.jsxs(Ze,{id:"nav-newtask",className:"composer",title:"新建任务",children:[s.jsxs(Yt,{children:[s.jsxs("select",{"aria-label":"环境",value:c.envSelect,onChange:U=>c.setEnvSelect(U.target.value),children:[s.jsx("option",{value:"",children:"环境:不指定(走项目仓库)"}),c.envs.map(U=>s.jsxs("option",{value:U.id,disabled:U.status!=="ready",children:[U.name,"(",U.status,")"]},U.id))]}),s.jsxs("select",{"aria-label":"执行器",value:D,onChange:U=>G(U.target.value),children:[s.jsx("option",{value:"docker",children:"docker(默认,多用户下隔离最强)"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"cloud",children:"cloud"})]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:O,onChange:U=>N(U.target.checked)})," goal 模式"]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:E,onChange:U=>X(U.target.checked)})," 计划模式(只读)"]})]}),s.jsx("textarea",{className:"prompt stacked",placeholder:"任务 prompt(必填)",value:r,onChange:U=>m(U.target.value)}),s.jsx("textarea",{className:"coord stacked",placeholder:"协调员子任务 JSON(可选),留空为普通任务",value:o,onChange:U=>_(U.target.value)}),s.jsxs("div",{className:"muted",children:["协调员格式:[","{",'"name":"后端","prompt":"做后端"',"}",",","{",'"name":"前端","prompt":"做前端"',"}","];提交后 worker 并行建子任务、等齐、合流汇总。不能与 goal/计划模式同用。协调员与 goal/计划互斥:勾了 goal 或计划模式时不要填协调员 JSON,提交前会校验并拦截。子任务费用记父任务创建人账;父任务创建时按分工数预留配额,余额不足时整个父任务被挡下。"]}),s.jsxs(Yt,{children:[s.jsxs("select",{"aria-label":"模型",value:b,onChange:U=>w(U.target.value),children:[s.jsx("option",{value:"",children:"模型:默认(跟随配置)"}),c.models.map(U=>s.jsx("option",{value:U,children:U},U))]}),c.modelCustomVisible?s.jsx("input",{type:"text",placeholder:"手动输入模型(中转列表取不到时用)",value:at,onChange:U=>st(U.target.value)}):null,s.jsxs("select",{"aria-label":"推理强度",value:et,onChange:U=>k(U.target.value),children:[s.jsx("option",{value:"",children:"推理强度:默认(跟随配置)"}),Bh.map(U=>s.jsx("option",{value:U,children:U},U))]}),s.jsxs("select",{"aria-label":"权限",value:dt,onChange:U=>Ut(U.target.value),children:[s.jsx("option",{value:"",children:"权限:默认(跟随配置)"}),s.jsx("option",{value:"ask",children:"请求批准"}),s.jsx("option",{value:"auto",children:"帮我批准"}),s.jsx("option",{value:"full",children:"完全访问"})]})]}),s.jsxs(Yt,{children:[s.jsxs("select",{"aria-label":"子任务模型",value:ye,onChange:U=>Me(U.target.value),children:[s.jsx("option",{value:"",children:"子任务模型:跟随本任务模型"}),c.models.map(U=>s.jsx("option",{value:U,children:U},U))]}),s.jsx("input",{type:"text",placeholder:"子任务模型手动输入(中转列表里没有时填,如 gpt-6-luna;留空=跟随本任务模型)",value:Jt,onChange:U=>fe(U.target.value)}),s.jsxs("select",{"aria-label":"子任务强度",value:it,onChange:U=>vt(U.target.value),children:[s.jsx("option",{value:"",children:"子任务强度:跟随本任务强度"}),Bh.map(U=>s.jsx("option",{value:U,children:U},U))]})]}),s.jsx("div",{className:"muted",children:"子任务模型/强度是派生默认:本任务用 marker task-create 或协调员分工派生的子任务,未显式写模型/强度时用它;块/分工里显式写了则覆盖它。也可以不在这里填、直接在 prompt 里写“子任务用 gpt-6-luna max”,建任务时服务端会解析成同一对字段(任务详情里可核对)。"}),O?s.jsx("div",{className:"muted",children:"goal 模式:输入框内容即目标,不需要专用 prompt 与验收命令;不限轮次,模型确认达成后在回复末尾输出“目标已达成”即结束,未达成会一直运行,可用取消停止。"}):null,s.jsxs(Yt,{children:[s.jsx("span",{className:"muted",children:"附件(放进任务工作区,图片与普通文件不区分):"}),s.jsx("input",{ref:Ft,type:"file",multiple:!0,title:"文件"}),s.jsx("input",{ref:Pt,type:"file",multiple:!0,title:"文件夹",webkitdirectory:""}),s.jsx("input",{ref:kt,type:"file",accept:"image/*",multiple:!0,title:"图片"})]}),s.jsxs(Yt,{children:[s.jsx("button",{className:"seal",onClick:tl,children:"提交任务"}),s.jsx("span",{className:"muted",children:re||c.dispatchMsg})]})]})}function eg({onNew:c}){const r=At();return s.jsxs("div",{children:[s.jsxs("div",{className:"search-box",children:[s.jsxs("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round","aria-hidden":"true",children:[s.jsx("circle",{cx:"11",cy:"11",r:"7"}),s.jsx("path",{d:"M21 21l-4.3-4.3"})]}),s.jsx("input",{type:"text",placeholder:"搜索","aria-label":"搜索任务",value:r.searchText,onChange:m=>r.setSearchText(m.target.value)})]}),s.jsx("div",{className:"bar",children:s.jsxs("select",{"aria-label":"项目",value:r.projectId,onChange:m=>r.selectProject(m.target.value),children:[r.projects.length===0?s.jsx("option",{value:"",children:"(先加载项目)"}):null,r.projects.map(m=>s.jsxs("option",{value:m.id,children:[m.name," (",Oe(m.id),")"]},m.id))]})}),s.jsxs("div",{className:"list-section-head",children:[s.jsx("span",{children:"主要聊天"}),s.jsx("button",{type:"button","aria-label":"派发新任务",title:"派发新任务",onClick:c,children:"+"})]}),s.jsxs("div",{className:"bar",children:[s.jsxs("select",{"aria-label":"状态筛选",value:r.statusFilter,onChange:m=>r.setStatusFilter(m.target.value),children:[s.jsx("option",{value:"",children:"状态:全部"}),["queued","running","completed","failed","interrupted","merged","merge-failed"].map(m=>s.jsx("option",{value:m,children:m},m))]}),s.jsxs("select",{"aria-label":"执行器筛选",value:r.executorFilter,onChange:m=>r.setExecutorFilter(m.target.value),children:[s.jsx("option",{value:"",children:"执行器:全部"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"docker",children:"docker"}),s.jsx("option",{value:"cloud",children:"cloud"})]})]}),s.jsxs("div",{className:"bar",children:[s.jsx("button",{onClick:r.refreshTasks,children:"刷新"}),s.jsx("span",{className:"muted",children:r.taskCountText})]}),r.taskError?s.jsx("div",{className:"err",children:r.taskError}):r.projectId?r.filteredTasks.length===0?s.jsx("div",{className:"muted",children:r.tasks.length?"没有符合筛选条件的任务":"该项目暂无任务"}):s.jsx("ul",{className:"issue-list",children:r.filteredTasks.slice().reverse().map(m=>{var o;return s.jsxs("li",{className:"issue-item"+(((o=r.currentTask)==null?void 0:o.id)===m.id?" selected":""),onClick:()=>r.showDetail(m.id),children:[s.jsx("span",{className:"issue-state st-"+m.status,"aria-hidden":"true"}),s.jsxs("span",{children:[s.jsxs("div",{className:"issue-title",children:[m.plan?"[计划] ":"",m.forked_from?"[分支] ":"",m.coordinator_parts?"[协调] ":"",m.parent_task_id?"[协调子任务] ":"",String(m.prompt||Oe(m.id)).slice(0,60)]}),s.jsxs("div",{className:"issue-meta",children:[Oe(m.id)," · ",s.jsx("span",{className:"st-"+m.status,children:m.status})," · ",m.executor||"",m.updated_at?" · "+new Date(m.updated_at*1e3).toLocaleString():""]})]})]},m.id)})}):s.jsx("div",{className:"muted",children:"先选项目"})]})}function lg(c){const r=y.useRef(null),[m,o]=y.useState(!0),_=y.useRef(!0),O=()=>{const N=r.current;if(!N)return;const E=N.scrollHeight-N.scrollTop-N.clientHeight<80;_.current=E,o(E)};return y.useEffect(()=>{_.current&&r.current&&(r.current.scrollTop=r.current.scrollHeight)},[c]),{ref:r,following:m,onScroll:O}}function ag({msg:c}){if(c.role==="status")return s.jsx("div",{className:"chat-status",children:c.text});const r=c.label||(c.role==="user"?"用户":c.role==="assistant"?"助手":"工具");return s.jsxs("div",{className:"gh-comment "+c.role,children:[s.jsx("div",{className:"gh-comment-header",children:s.jsx("span",{className:"gh-comment-author",children:r})}),s.jsx("div",{className:"gh-comment-body",children:c.text})]})}function Gh({messages:c,empty:r}){const{ref:m,following:o,onScroll:_}=lg(c.length);return s.jsxs("div",{className:"chat-list",ref:m,onScroll:_,children:[c.length===0?s.jsx("div",{className:"muted",children:r||"(暂无消息)"}):c.map(O=>s.jsx(ag,{msg:O},O.id)),!o&&c.length>0?s.jsx("button",{className:"chat-follow",onClick:()=>{m.current&&(m.current.scrollTop=m.current.scrollHeight)},children:"回到最新 ↓"}):null]})}function ng({onSend:c,disabled:r,placeholder:m}){const[o,_]=y.useState(""),O=()=>{const N=o.trim();!N||r||(c(N),_(""))};return s.jsxs("div",{className:"gh-comment-box",children:[s.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(),O())}}),s.jsx("div",{className:"gh-comment-footer",children:s.jsx("button",{type:"button",className:"primary","aria-label":"发送",disabled:r||!o.trim(),onClick:O,children:"发送"})})]})}function Qh(c,r){const m=c.id||"trace-"+r;if(c.kind==="message")return{id:m,role:"assistant",text:(c.phase?"["+c.phase+"] ":"")+(c.text||""),label:"助手"};if(c.kind==="exec"||c.kind==="file"||c.kind==="tool"||c.kind==="call"){const o=c.kind==="exec"?"命令":c.kind==="file"?"文件":c.kind==="tool"?"工具":"调用";return{id:m,role:"tool",text:fr(c),label:o}}return c.kind==="plan"?{id:m,role:"status",text:c.text||""}:c.kind==="reasoning"?{id:m,role:"status",text:"思考:"+(c.summary||"")}:c.kind==="agent-start"?{id:m,role:"status",text:"子代理开始:"+(c.name||"")+(c.prompt?"("+c.prompt+")":"")}:c.kind==="agent-done"?{id:m,role:"status",text:"子代理结束:"+(c.name||"")+" "+(c.status||"")}:{id:m,role:"status",text:fr(c)}}function ug(){const c=At(),r=y.useMemo(()=>{const m=c.currentTask,o=m&&m.prompt?[{id:"task-prompt",role:"user",text:m.prompt}]:[],O=(c.traceKind?c.traceEntries.filter(E=>E.kind===c.traceKind):c.traceEntries).map((E,X)=>Qh(E,X)),N=c.traceDone?[{id:"trace-done",role:"status",text:"链路已结束("+c.traceDone+")"}]:[];return[...o,...O,...N]},[c.currentTask,c.traceEntries,c.traceKind,c.traceDone]);return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"muted",children:"实时链路"}),s.jsxs(Yt,{children:[s.jsxs("select",{"aria-label":"链路类型",value:c.traceKind,onChange:m=>c.setTraceKind(m.target.value),children:[s.jsx("option",{value:"",children:"链路类型:全部"}),["exec","file","call","tool","message","reasoning","plan","agent-start","agent-done"].map(m=>s.jsx("option",{value:m,children:m==="exec"?"命令":m==="file"?"文件":m==="call"?"调用":m==="tool"?"工具":m==="message"?"消息":m==="reasoning"?"思考":m==="plan"?"计划":"子代理"},m))]}),s.jsx("button",{onClick:c.downloadTrace,children:"下载完整链路"}),s.jsx("span",{className:"muted",children:c.traceMsg})]}),c.traceNote?s.jsx("div",{children:s.jsx("span",{className:"err",children:c.traceNote})}):null,s.jsx("div",{className:"chat-column",children:s.jsx(Gh,{messages:r,empty:"(暂无链路条目)"})}),s.jsx("div",{className:"muted",children:"对话时间线:首条是本任务 prompt(用户);助手回复来自 message 条目,命令/文件/工具/调用是工具评论框,计划/思考/子代理开始结束是时间线上的状态文字。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。"})]})}function cg(){const c=At(),r=c.currentTask,m=y.useMemo(()=>{if(!r)return[];if(c.chatHistory)return c.chatHistory.messages.map(b=>({id:b.id,role:b.role,text:b.text,label:b.label}));const X=r.prompt?[{id:"task-prompt",role:"user",text:r.prompt}]:[],D=c.traceEntries.filter(b=>b.kind==="message").map((b,w)=>Qh(b,w)),G=c.followups.map((b,w)=>({id:"followup-"+w,role:"user",text:String(b.body||""),label:"后续消息"}));return[...X,...D,...G]},[r,c.chatHistory,c.traceEntries,c.followups]);if(!r)return s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示继续会话"});const o=iu.includes(r.status),_=["queued","running"].includes(r.status),O=o||_,N=o?"终态任务:发送走继续接口(同一会话再跑一轮)":_?"运行中/排队中:发送走后续消息直接发送(跑完当前轮后优先执行)":"merged/merge-failed 任务不可继续,也不可发后续消息",E=c.chatHistory?c.chatHistory.legacy_continue_count??null:null;return s.jsxs("div",{className:"chat-column",children:[E!==null&&E>0?s.jsxs("div",{className:"muted",children:["此前有 ",E," 条继续消息发生在持久化之前,未入库,上面历史不完整;部署后新发的继续消息会正常显示。"]}):null,c.chatHistory&&c.chatHistory.trace_note?s.jsx("div",{className:"muted",children:c.chatHistory.trace_note}):null,s.jsx(Gh,{messages:m,empty:"(暂无会话消息)"}),s.jsx(ng,{disabled:!O,placeholder:"消息",onSend:X=>void c.sendChatMessage(X)}),s.jsxs("div",{className:"muted",children:[N,"。",c.chatMsg]})]})}function ig(){return At().currentTask?s.jsxs("div",{className:"conversation",children:[s.jsx(ug,{}),s.jsx("div",{className:"conv-divider"}),s.jsx(cg,{})]}):s.jsx("div",{className:"conversation",children:s.jsx("div",{className:"muted",children:"在任务列表里点一条任务,对话和详情就切到该任务;也可以在上面派发一个新任务。"})})}function sg(){const c=At(),r=c.currentTask,[m,o]=y.useState("");if(!r)return null;const _=iu.includes(r.status),O=["failed","interrupted","merge-failed"].includes(r.status);return s.jsxs(s.Fragment,{children:[s.jsxs(Yt,{children:[s.jsx("button",{disabled:!O,title:O?"":"仅 failed/interrupted/merge-failed 可重试",onClick:()=>c.doAction("retry"),children:"重试"}),s.jsx("button",{className:"danger",disabled:_,title:_?"终态任务不可取消":"",onClick:()=>c.doAction("cancel"),children:"取消"}),s.jsx("button",{disabled:r.status!=="completed",title:r.status!=="completed"?"仅 completed 可合并":"",onClick:()=>c.doAction("merge"),children:"合并(completed → merged)"}),s.jsx("button",{disabled:r.status!=="merged",title:r.status!=="merged"?"仅 merged 可提 PR":"",onClick:()=>c.doAction("pr"),children:"提 PR(须 merged)"}),_?s.jsx("button",{onClick:()=>c.setForkVisible(!0),children:"分支"}):null,s.jsx("button",{onClick:c.taskCost,children:"查成本"}),s.jsxs("span",{className:"muted",children:[c.actionMsg," ",c.actionReasons]})]}),c.forkVisible?s.jsxs("div",{children:[s.jsx("input",{type:"text",placeholder:"分支首轮消息(必填,带历史的新会话)",style:{width:"100%",boxSizing:"border-box",margin:"6px 0"},value:m,onChange:N=>o(N.target.value)}),s.jsxs(Yt,{children:[s.jsx("button",{className:"seal",onClick:async()=>{await c.forkTask(m),o("")},children:"创建分支任务"}),s.jsx("span",{className:"muted",children:c.forkMsg})]})]}):null]})}function fg(){const c=At(),[r,m]=y.useState("uncommittedChanges"),[o,_]=y.useState(""),[O,N]=y.useState(""),[E,X]=y.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("h3",{children:"评审队列"}),s.jsxs("select",{"aria-label":"评审目标",value:r,onChange:D=>m(D.target.value),children:[s.jsx("option",{value:"uncommittedChanges",children:"未提交改动(工作区)"}),s.jsx("option",{value:"baseBranch",children:"与分支的差异"}),s.jsx("option",{value:"commit",children:"指定提交"}),s.jsx("option",{value:"custom",children:"自定义评审指令"})]}),s.jsx("input",{className:"stacked",placeholder:"与分支的差异用:分支名(如 main)",style:{width:"100%"},value:o,onChange:D=>_(D.target.value)}),s.jsx("input",{className:"stacked",placeholder:"指定提交用:提交 sha",style:{width:"100%"},value:O,onChange:D=>N(D.target.value)}),s.jsx("textarea",{placeholder:"自定义评审指令用:评审指令正文",value:E,onChange:D=>X(D.target.value)}),s.jsxs(Yt,{children:[s.jsx("button",{className:"primary",onClick:()=>void c.postReview({target_type:r,branch:o.trim()||void 0,sha:O.trim()||void 0,instructions:E.trim()||void 0}),children:"登记评审需求"}),s.jsx("button",{onClick:c.refreshReviews,children:"刷新队列"}),s.jsx("span",{className:"muted",children:c.reviewMsg})]}),s.jsx("div",{className:"muted",children:"本基线只登记评审需求(requested),不自动跑评审;评审是否执行、结果如何,以评审队列里的记录为准。"}),c.reviewError?s.jsx("div",{className:"muted",children:c.reviewError}):c.reviews.length===0?s.jsx("div",{className:"muted",children:"点任务行查看详情后,点“刷新队列”查看评审记录"}):s.jsx(su,{children:c.reviews.map(D=>{let G=D.target_type||"";return D.branch&&(G+=":"+D.branch),D.sha&&(G+=":"+String(D.sha).slice(0,12)),D.instructions&&(G+=":"+String(D.instructions).slice(0,80)),s.jsxs("li",{children:[s.jsxs("span",{className:"row-main",children:[s.jsx("b",{children:"评审"})," ",Oe(D.id)," | ",G," | ",s.jsx("span",{className:"st-"+(D.status||""),children:D.status}),D.created_at?" | "+nc(D.created_at):"",s.jsx("br",{}),D.findings?String(D.findings).slice(0,1e3):s.jsx("span",{className:"muted",children:"(暂无 findings:评审尚未执行或尚未写回)"})]}),s.jsx("button",{onClick:()=>c.submitFindings(D.id),children:"写 findings"})]},D.id)})})]})}function rg(){const c=At();return c.currentTask?c.currentTask.coordinator_parts?c.coordChildren.length===0?s.jsx("div",{className:"muted",children:"(子任务尚未创建)"}):s.jsx(su,{children:c.coordChildren.map(r=>s.jsx("li",{children:s.jsxs("span",{className:"row-main",children:["分工 ",s.jsx("b",{children:r.coordinator_part||""})," | 状态 ",s.jsx("span",{className:"st-"+r.status,children:r.status})," | ",Oe(r.id)," | ",String(r.prompt||"").slice(0,60)]})},r.id))}):s.jsx("div",{className:"muted",children:"(非协调员任务)"}):s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示协调员的子任务"})}function og(){const c=At();if(!c.currentTask)return s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示子代理链路"});if(c.agents.length===0)return s.jsxs("div",{className:"muted",children:["(暂无子代理)",c.agentsNote?s.jsx("span",{className:"err",children:c.agentsNote}):null]});const r={main:"主任务",delegate:"委派子任务",model:"模型子代理"},m={running:"进行中",completed:"已完成",failed:"失败",interrupted:"已中断",unknown:"未知"};return s.jsx(su,{children:c.agents.map((o,_)=>s.jsx("li",{children:s.jsxs("span",{className:"row-main",children:[s.jsxs("b",{children:[r[o.kind||""]||o.kind||"",":"]}),o.name||""," ",s.jsx("span",{className:"st-"+(o.status||""),children:m[o.status||""]||o.status||"?"})," | 过程调用 "+(o.calls?o.calls.length:0)+" 条",o.updated_ts?" | 最近活动 "+nc(o.updated_ts/1e3):"",o.prompt?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsxs("span",{className:"muted",children:["任务:",o.prompt]})]}):null,o.calls&&o.calls.length?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),o.calls.slice(-50).map((O,N)=>s.jsx("div",{children:fr(O)},N))]}):s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsx("span",{className:"muted",children:"(暂无过程调用)"})]})]})},_))})}function dg(){const c=At();return s.jsxs(s.Fragment,{children:[s.jsxs(Yt,{children:[s.jsx("button",{onClick:c.refreshApprovals,children:"刷新审批队列"}),s.jsx("span",{className:"muted",children:c.approvalMsg})]}),s.jsx("div",{className:"muted",children:"待审批项需人工点记录允许或记录拒绝;超时默认拒绝。当前版本只留回执,不拦截实时行为(实时请求的事前拦截待 host 接入后生效,在此之前实时行为不变)。"}),s.jsx(Dl,{empty:"(暂无审批项)",items:c.approvals.map(r=>s.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)+" "+nc(r.decided_at):"",r.status==="pending"?s.jsxs(s.Fragment,{children:[" ",s.jsx("button",{onClick:()=>c.decideApproval(r.id,"approved"),children:"记录允许"})," ",s.jsx("button",{onClick:()=>c.decideApproval(r.id,"denied"),children:"记录拒绝"})]}):null]},r.id))})]})}function mg(){const c=At(),[r,m]=y.useState(""),[o,_]=y.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("input",{placeholder:"目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)",style:{width:"100%"},value:r,onChange:O=>m(O.target.value)}),s.jsx("textarea",{placeholder:"消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)",value:o,onChange:O=>_(O.target.value)}),s.jsxs(Yt,{children:[s.jsx("button",{onClick:async()=>{await c.postPeer("queued",r,o),_("")},children:"排队发给对方"}),s.jsx("button",{className:"primary",onClick:async()=>{await c.postPeer("direct",r,o),_("")},children:"直接发送"}),s.jsx("span",{className:"muted",children:c.peerMsg})]}),s.jsx(Dl,{empty:"(本任务尚未发出任务间消息)",items:c.peerMessages.map((O,N)=>s.jsxs("span",{className:"row-main",children:["[发给 ",String(O.task_id).slice(0,8),"|",O.mode,"|",O.status,"] ",String(O.body||"").slice(0,120)]},N))})]})}function hg(){const c=At(),[r,m]=y.useState(""),o=c.currentTask?["completed","failed","interrupted"].includes(c.currentTask.status):!1;return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"muted",children:c.threadText||"点任务行查看详情后,这里显示线程元数据"}),s.jsxs(Yt,{children:[s.jsx("input",{type:"text",placeholder:"新线程名",value:r,onChange:_=>m(_.target.value)}),s.jsx("button",{disabled:!o,onClick:()=>c.threadAction("rename",r),children:"重命名"}),s.jsx("button",{disabled:!o,onClick:()=>c.threadAction("archive",""),children:"归档"}),s.jsx("button",{disabled:!o,onClick:()=>c.threadAction("unarchive",""),children:"取消归档"}),s.jsx("button",{disabled:!o,onClick:()=>c.threadAction("compact",""),children:"压缩"}),s.jsx("span",{className:"muted",children:c.threadGateNote}),s.jsx("span",{className:"muted",children:c.threadMsg})]}),s.jsx(Dl,{empty:"暂无其他线程",items:c.threadList.map((_,O)=>s.jsxs("span",{className:"row-main",children:[_.name||_.thread_name||_.id||""," [",_.id||"","]",_.archived?" [已归档]":"",_.cwd?" "+_.cwd:""]},O))}),s.jsx("div",{className:"muted",children:"限制:Docker/异机任务线程操作一律 409;merged/merge-failed 不可改;turn/steer 与 review/start 不在本批。"})]})}function vg(){const c=At(),r=c.currentTask;return r?s.jsxs(Ze,{id:"nav-detail",title:"任务详情",children:[s.jsxs("div",{children:["状态 ",s.jsx("b",{className:"st-"+r.status,children:r.status}),"(",wy[r.status]||"未知状态",")",s.jsx("br",{}),"任务 ",r.id," | turn ",Oe(r.turn_id)," | root turn ",Oe(r.root_turn_id),s.jsx("br",{}),"executor ",r.executor||""," | 主机 ",r.worktree_host||"",s.jsx("br",{}),"模型 ",r.model||"默认"," | 强度 ",r.effort||"默认",r.child_model||r.child_effort?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"子任务默认 ",(r.child_model||"跟随本任务")+" / "+(r.child_effort||"跟随本任务")]}):null,s.jsx("br",{}),"权限 ",r.approval||"默认"," | 项目 ",Oe(r.project_id),s.jsx("br",{}),"更新 ",nc(r.updated_at),r.plan?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"计划模式(只读)"]}):null,r.forked_from?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"分支自 ",Oe(r.forked_from)]}):null,r.goal_mode?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"goal 模式(不限轮次,模型宣告完成)"]}):r.verify_command?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"goal 模式(旧语义,验收命令)"]}):null,r.coordinator_parts?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"协调员:",r.coordinator_parts.length," 个子任务(",r.coordinator_parts.map(m=>m.name).join("、"),")"]}):null,r.parent_task_id?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"协调子任务,父任务 ",Oe(r.parent_task_id),r.coordinator_part?"("+r.coordinator_part+")":""]}):null,r.attachments&&r.attachments.length?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"附件:",r.attachments.join("、")]}):null,r.pr_url?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsxs("a",{href:r.pr_url,target:"_blank",rel:"noopener noreferrer",children:["PR #",r.pr_number]})]}):null,s.jsx("br",{}),"prompt:",r.prompt||""]}),s.jsx(sg,{}),s.jsx("pre",{children:c.detailBody||"(暂无 result/error 输出)"}),c.costBox?s.jsx("pre",{children:c.costBox}):null,s.jsx("h3",{children:"协调子任务"}),s.jsx(rg,{}),s.jsx("h3",{children:"子代理链路"}),s.jsx(og,{}),s.jsx("h3",{children:"评审队列"}),s.jsx(fg,{}),s.jsx("h3",{children:"运行时审批队列"}),s.jsx(dg,{}),s.jsx("h3",{children:"给其他任务发消息"}),s.jsx(mg,{}),s.jsx("h3",{children:"线程"}),s.jsx(hg,{})]}):s.jsx(Ze,{id:"nav-detail",title:"任务详情",children:s.jsx("div",{className:"muted",children:"点任务行查看详情"})})}function yg(){const c=At(),[r,m]=y.useState("");return s.jsxs(Ze,{id:"nav-key",title:"API Key",children:[s.jsxs(Yt,{children:[s.jsx("input",{type:"password",placeholder:"粘贴你的 X-API-Key(与调 API 用的同一个)",autoComplete:"off",value:r,onChange:o=>m(o.target.value)}),s.jsx("button",{className:"primary",onClick:()=>{c.saveKeyInput(r),m("")},children:"保存到本浏览器"}),s.jsx("button",{onClick:c.clearKeyInput,children:"清除"}),s.jsx("span",{className:"muted",children:c.keyState})]}),s.jsx("div",{children:s.jsx("span",{className:"muted",children:c.quotaText})})]})}function gg(){const c=At();return s.jsxs(Ze,{id:"adminCard",title:s.jsxs(s.Fragment,{children:["管理区 ",s.jsx("span",{className:"muted",children:"(仅全局管理员)"})]}),children:[s.jsx("div",{className:"muted",children:c.adminGate}),c.adminBody?s.jsxs(s.Fragment,{children:[s.jsxs(Yt,{children:[s.jsx("input",{type:"text",placeholder:"要查配额的用户 id",value:c.adminUserId,onChange:r=>c.setAdminUserId(r.target.value)}),s.jsx("button",{onClick:c.adminQuota,children:"查该用户配额"})]}),s.jsxs(Yt,{children:[s.jsx("button",{onClick:c.adminSweep,children:"手动触发 sweep(清理陈旧 running 任务)"}),s.jsx("button",{onClick:c.adminBackup,children:"手动触发备份"})]}),s.jsx("div",{className:"muted",children:c.adminResult})]}):null]})}function Sg(){const c=At(),[r,m]=y.useState(""),[o,_]=y.useState(""),[O,N]=y.useState("");return s.jsxs(Ze,{id:"nav-projects",title:"项目",children:[s.jsxs(Yt,{children:[s.jsxs("select",{"aria-label":"项目",value:c.projectId,onChange:E=>c.selectProject(E.target.value),children:[c.projects.length===0?s.jsx("option",{value:"",children:"(先加载项目)"}):null,c.projects.map(E=>s.jsxs("option",{value:E.id,children:[E.name," (",Oe(E.id),")"]},E.id))]}),s.jsx("button",{onClick:c.refreshProjects,children:"刷新"})]}),s.jsxs(Yt,{children:[s.jsx("input",{type:"text",placeholder:"新项目名",value:r,onChange:E=>m(E.target.value)}),s.jsxs("select",{"aria-label":"从 GitHub 仓库选",value:o,onChange:E=>{_(E.target.value),E.target.value&&N(E.target.value)},children:[s.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选,或手动输入)"}),c.githubRepos.map(E=>s.jsx("option",{value:E.clone_url,children:E.repo_full_name},E.clone_url))]}),s.jsx("input",{type:"text",placeholder:"repo_url(可选)",value:O,onChange:E=>N(E.target.value)}),s.jsx("button",{onClick:async()=>{await c.createProject(r,O),m(""),N(""),_("")},children:"新建项目"})]}),s.jsx("span",{className:"muted",children:c.projectMsg})]})}function pg(){const c=At(),[r,m]=y.useState(""),[o,_]=y.useState("contributor"),O=c.projects.find(N=>N.id===c.projectId);return s.jsxs(Ze,{title:"项目成员",children:[O?s.jsxs("div",{className:"muted",children:[O.name," | ",O.id," | 仓库 ",O.repo_url||"未绑定"," | 我的角色 ",O.my_role||"未知"]}):s.jsx("div",{className:"muted",children:"先选项目"}),s.jsxs(Yt,{children:[s.jsx("input",{type:"text",placeholder:"成员 user_id 或用户名",value:r,onChange:N=>m(N.target.value)}),s.jsxs("select",{"aria-label":"邀请角色",value:o,onChange:N=>_(N.target.value),children:[s.jsx("option",{value:"viewer",children:"viewer(只读)"}),s.jsx("option",{value:"contributor",children:"contributor(可建任务)"}),s.jsx("option",{value:"maintainer",children:"maintainer(可批合并)"}),s.jsx("option",{value:"owner",children:"owner(可管项目)"})]}),s.jsx("button",{onClick:async()=>{await c.inviteMember(r,o),m("")},children:"邀请成员"}),s.jsx("button",{onClick:c.refreshMembers,children:"刷新成员"})]}),c.memberError?s.jsx("div",{className:"muted",children:c.memberError}):c.members.length===0?s.jsx("div",{className:"muted",children:"先选项目"}):s.jsx(su,{children:c.members.map(N=>{const E=(N.username||"")+(N.username?"("+String(N.user_id).slice(0,8)+")":String(N.user_id).slice(0,8));return s.jsxs("li",{children:[s.jsx("span",{className:"row-main",children:E}),s.jsx("select",{"aria-label":"成员角色",value:N.role||"viewer",onChange:X=>void c.changeMemberRole(N.user_id,X.target.value),children:Gy.map(X=>s.jsx("option",{value:X,children:X},X))})]},N.user_id)})}),s.jsx("span",{className:"muted",children:c.memberMsg})]})}function bg(){const c=At(),[r,m]=y.useState(""),[o,_]=y.useState(""),[O,N]=y.useState("");return s.jsxs(Ze,{id:"nav-env",title:s.jsxs(s.Fragment,{children:["环境 ",s.jsx("span",{className:"muted",children:"(选、建、管:当前项目的基准检出)"})]}),children:[s.jsxs(Yt,{children:[s.jsx("button",{onClick:c.refreshEnvs,children:"刷新"}),s.jsx("span",{className:"muted",children:c.envCount})]}),c.envs.length===0?s.jsx("div",{className:"muted",children:"先选项目"}):s.jsx(su,{children:c.envs.map(E=>s.jsxs("li",{children:[s.jsxs("span",{className:"row-main",children:[E.name,"(",Oe(E.id),") / 分支 ",E.branch||"默认分支"," / 执行器 ",E.executor||"不限"," / 状态 ",E.status,E.status==="failed"&&E.error_text?" / 失败原因:"+E.error_text:""]}),E.status==="archived"?null:s.jsx("button",{onClick:()=>void c.archiveEnv(E.id),children:"归档"})]},E.id))}),s.jsxs(Yt,{children:[s.jsx("input",{type:"text",placeholder:"新环境名",value:r,onChange:E=>m(E.target.value)}),s.jsx("input",{type:"text",placeholder:"分支(可选,空=默认分支)",value:o,onChange:E=>_(E.target.value)}),s.jsxs("select",{"aria-label":"新环境执行器",value:O,onChange:E=>N(E.target.value),children:[s.jsx("option",{value:"",children:"执行器:不限"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"docker",children:"docker"})]}),s.jsx("button",{onClick:async()=>{await c.createEnv(r,o,O),m(""),_("")},children:"新建环境"})]}),s.jsx("span",{className:"muted",children:c.envMsg})]})}function Tg(){const c=At(),[r,m]=y.useState("");return s.jsxs(Ze,{title:"仓库与环境上下文",children:[s.jsx("div",{className:"muted",children:c.envRepoLine||"先选项目"}),s.jsx("div",{className:"muted",children:c.envCount}),c.envRepoBar?s.jsxs(Yt,{children:[s.jsxs("select",{"aria-label":"补仓库",value:r,onChange:o=>m(o.target.value),children:[s.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选)"}),c.githubRepos.map(o=>s.jsx("option",{value:o.clone_url,children:o.repo_full_name},o.clone_url))]}),s.jsx("button",{onClick:()=>void c.saveEnvRepo(r),children:"保存仓库"})]}):null,s.jsx("span",{className:"muted",children:c.envRepoMsg})]})}function jg(){const c=At();return s.jsxs(Ze,{id:"nav-workers",title:"Workers",children:[s.jsx(Yt,{children:s.jsx("button",{onClick:c.refreshWorkers,children:"刷新"})}),c.workersError?s.jsx("div",{className:"muted",children:c.workersError}):c.workers===null?s.jsx("div",{className:"muted",children:c.workersSummary||"未加载"}):c.workers.length===0?s.jsx("div",{className:"muted",children:"无 worker 注册"}):s.jsx(su,{children:c.workers.map((r,m)=>{const o=r.running===void 0||r.running===null?"?":r.running,_=r.capacity===void 0||r.capacity===null?"?":r.capacity,O=wh(r),N=r.alive!==void 0&&r.alive!==null?!!r.alive:O.age!==null&&O.age<=120,E=N?" / 在线":" / 离线(占用为上次上报值)";return s.jsx("li",{className:N?"is-online":"is-offline",children:s.jsxs("span",{className:"row-main",children:[r.worker_id||r.id||"?"," / ",r.executor||""," / 占用 ",o,"/",_,E," / 最后心跳 ",O.text]})},m)})})]})}function xg(){const c=At();return s.jsxs(Ze,{title:"健康与配额",children:[s.jsxs(Yt,{children:[s.jsx("span",{className:"muted",children:c.healthText}),s.jsx("button",{onClick:c.refreshHealth,children:"刷新"})]}),s.jsx("div",{children:s.jsx("span",{className:"muted",children:c.quotaText})}),s.jsx("div",{className:"muted",children:c.workersSummary})]})}function Eg(){const c=At();return s.jsxs(Ze,{id:"nav-skills",title:"技能与 MCP",children:[s.jsx("div",{className:"muted",children:"反映宿主租户 home,容器内 home 可能不同;重载只在 schema 枚举里,当前 pin 的二进制拒绝时原样 502;OAuth 只发起登录,不代表登录完成。"}),s.jsxs(Yt,{children:[s.jsx("button",{onClick:c.refreshSkills,children:"刷新"}),s.jsx("span",{className:"muted",children:c.skillMsg})]}),s.jsx("h3",{children:"技能"}),c.skillError?s.jsx("div",{className:"muted",children:c.skillError}):s.jsx(Dl,{empty:"暂无技能",items:c.skills.map((r,m)=>s.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:"",r.detail?" - "+r.detail:""]},m))}),s.jsx("h3",{children:"应用"}),s.jsx(Dl,{empty:"暂无应用",items:c.apps.map((r,m)=>s.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:""]},m))}),s.jsx("h3",{children:"MCP 服务"}),s.jsx(Dl,{empty:"暂无 MCP 服务",items:c.mcpServers.map((r,m)=>{const o=r.detail||r.details||r.state||"";return s.jsxs("span",{className:"row-main",children:[r.name||r.id||""," | 状态 ",r.status||"",o?" | "+o:""]},m)})})]})}function _g(){const c=At(),[r,m]=y.useState("");return s.jsxs(Ze,{title:"MCP 操作",children:[s.jsxs(Yt,{children:[s.jsx("button",{onClick:c.reloadMcp,children:"重载配置"}),s.jsx("span",{className:"muted",children:c.mcpMsg})]}),s.jsxs(Yt,{children:[s.jsx("input",{type:"text",placeholder:"MCP 服务名",value:r,onChange:o=>m(o.target.value)}),s.jsx("button",{onClick:()=>void c.mcpOauth(r),children:"发起 OAuth 登录"}),s.jsx("span",{className:"muted",children:c.mcpOauthMsg})]}),c.mcpOauthBox?s.jsx("pre",{children:c.mcpOauthBox}):null]})}function Ng(){const c=At(),[r,m]=y.useState(""),[o,_]=y.useState(""),[O,N]=y.useState(""),[E,X]=y.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("input",{placeholder:"自动化名称(同项目内启用中的名称唯一)",style:{width:"100%"},value:r,onChange:D=>m(D.target.value)}),s.jsx("textarea",{placeholder:"定时任务内容(创建只登记定义与到期状态;执行由后续执行器经 claim 抢单后建任务,不另起调度器)",value:o,onChange:D=>_(D.target.value)}),s.jsxs(Yt,{children:[s.jsx("input",{placeholder:"间隔秒数(默认 86400,最小 60)",style:{width:"40%"},value:O,onChange:D=>N(D.target.value)}),s.jsx("input",{placeholder:"仓库(可选)",style:{width:"40%"},value:E,onChange:D=>X(D.target.value)}),s.jsx("button",{className:"primary",onClick:async()=>{await c.createAutomation(r,o,O,E),m(""),_(""),N(""),X("")},children:"创建自动化"}),s.jsx("button",{onClick:c.refreshAutomations,children:"刷新自动化"}),s.jsx("span",{className:"muted",children:c.autoMsg})]}),s.jsx(Dl,{empty:"(暂无自动化)",items:c.automations.map(D=>s.jsxs("span",{className:"row-main",children:["[",D.status,D.due?"|到期":"","] ",D.name,"|每 ",D.interval_seconds," 秒|下次 ",nc(D.next_run_at),D.status==="active"?s.jsxs(s.Fragment,{children:[" ",s.jsx("button",{onClick:()=>c.cancelAutomation(D.id),children:"取消"})]}):null]},D.id))})]})}function Cg(){var m,o,_,O;const c=At(),r=c.triage;return c.triageError?s.jsx("div",{className:"muted",children:c.triageError}):r?s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["到期自动化(",((m=r.counts)==null?void 0:m.automations_due)||0,")"]}),s.jsx(Dl,{empty:"(无)",items:(r.automations_due||[]).map((N,E)=>s.jsxs("span",{className:"row-main",children:[N.name,"|每 ",N.interval_seconds," 秒"]},E))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["失败/中断任务(",((o=r.counts)==null?void 0:o.failed_tasks)||0,")"]}),s.jsx(Dl,{empty:"(无)",items:(r.failed_tasks||[]).map((N,E)=>s.jsxs("span",{className:"row-main",children:[Oe(N.id),"|",N.status,"|",String(N.prompt||"").slice(0,80)]},E))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["待处理后续消息(",((_=r.counts)==null?void 0:_.pending_followups)||0,")"]}),s.jsx(Dl,{empty:"(无)",items:(r.pending_followups||[]).map((N,E)=>s.jsxs("span",{className:"row-main",children:["任务 ",Oe(N.task_id),"|",String(N.body||"").slice(0,80)]},E))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["最近自动化产出(",((O=r.counts)==null?void 0:O.recent_runs)||0,")"]}),s.jsx(Dl,{empty:"(无)",items:(r.recent_runs||[]).map((N,E)=>s.jsxs("span",{className:"row-main",children:[Oe(N.automation_id),"|",N.status,N.task_id?"|任务 "+Oe(N.task_id):"",N.task_status?"|"+N.task_status:""]},E))})]})]}):s.jsx("div",{className:"muted",children:"(先选项目)"})}function Ag(){return s.jsx(Ze,{id:"nav-automations",title:"自动化",children:s.jsx(Ng,{})})}function Og(){const c=At();return s.jsxs(Ze,{id:"nav-triage",title:"分诊收件箱",children:[s.jsx(Yt,{children:s.jsx("button",{onClick:c.refreshTriage,children:"刷新分诊"})}),s.jsx(Cg,{})]})}const Mg=[["#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 zg(){return s.jsxs("header",{className:"dash-topbar",children:[s.jsxs("div",{className:"dash-topbar-row",children:[s.jsx("span",{className:"dash-brand",children:"Codex 命令台"}),s.jsx(Rg,{}),s.jsx("span",{className:"muted dash-hide-sm",children:s.jsx(Dg,{})}),s.jsx("span",{className:"muted dash-hide-sm",children:s.jsx(Ug,{})}),s.jsx("span",{className:"muted dash-stamp",children:s.jsx(Hg,{})})]}),s.jsx("nav",{className:"dash-nav","aria-label":"页面导航",children:Mg.map(([c,r])=>s.jsx("a",{href:c,children:r},c))})]})}function Rg(){const c=At();return s.jsx("span",{className:c.keySaved?"dash-status ok":"dash-status off",children:c.keySaved?"● 已连接":"○ 未连接"})}function Dg(){return s.jsx(s.Fragment,{children:At().healthText})}function Ug(){return s.jsx(s.Fragment,{children:At().quotaText})}function Hg(){return s.jsxs(s.Fragment,{children:["自动刷新 · 每 10 秒 · 已刷新 ",At().refreshStamp]})}function Bg(){const c=Iy();Fy(m=>c.refreshAll(m),1e4),Wy(()=>c.refreshSlow(),6e4);const r=()=>{var m;(m=document.getElementById("sec-dispatch"))==null||m.scrollIntoView({behavior:"smooth"})};return s.jsxs(Yh.Provider,{value:c,children:[s.jsx(zg,{}),s.jsxs("main",{className:"dash-page",children:[s.jsx(Py,{}),s.jsxs("div",{className:"dash-col dash-col-left",children:[s.jsxs("section",{id:"sec-tasks",className:"dash-section card",children:[s.jsx("h2",{children:"任务列表"}),s.jsx(eg,{onNew:r})]}),s.jsxs("section",{id:"sec-projects",className:"dash-section",children:[s.jsx(Sg,{}),s.jsx(pg,{})]})]}),s.jsxs("div",{className:"dash-col dash-col-mid",children:[s.jsx("section",{id:"sec-dispatch",className:"dash-section",children:s.jsx(tg,{})}),s.jsxs("section",{id:"sec-conv",className:"dash-section",children:[s.jsxs("div",{className:"card",children:[s.jsx("h2",{children:"对话"}),s.jsx(ig,{})]}),s.jsx(vg,{})]})]}),s.jsxs("div",{className:"dash-col dash-col-right",children:[s.jsxs("section",{id:"sec-env",className:"dash-section",children:[s.jsx(bg,{}),s.jsx(Tg,{})]}),s.jsxs("section",{id:"sec-workers",className:"dash-section",children:[s.jsx(jg,{}),s.jsx(xg,{})]}),s.jsxs("section",{id:"sec-skills",className:"dash-section",children:[s.jsx(Eg,{}),s.jsx(_g,{})]}),s.jsx("section",{id:"sec-automations",className:"dash-section",children:s.jsx(Ag,{})}),s.jsx("section",{id:"sec-triage",className:"dash-section",children:s.jsx(Og,{})}),s.jsx("section",{id:"sec-admin",className:"dash-section",children:s.jsx(gg,{})}),s.jsx("section",{id:"sec-key",className:"dash-section",children:s.jsx(yg,{})})]})]})]})}qy.createRoot(document.getElementById("root")).render(s.jsx(Oy.StrictMode,{children:s.jsx(Bg,{})}));
+