子任务模型/强度是派生默认:本任务用 marker task-create 或协调员分工派生的子任务,未显式写模型/强度时用它;块/分工里显式写了则覆盖它。也可以不在这里填、直接在 prompt 里写“子任务用 gpt-6-luna max”,建任务时服务端会解析成同一对字段(任务详情里可核对)。
- {goalMode ? goal 模式:输入框内容即目标,不需要专用 prompt 与验收命令;不限轮次,模型确认达成后在回复末尾输出“目标已达成”即结束,未达成会一直运行,可用取消停止。
: null}
- {goalInvincible ? goal 模式无敌版:goal 模式 + 任务不限时(去掉 worker/docker 总超时;单轮 600 秒护栏还在,不限的是任务总时长与总轮次)。服务端默认的自动续跑与断点镜像同时生效。
: null}
+ {goalMode ? goal 模式:输入框内容即目标,不需要专用 prompt 与验收命令;不限轮次,模型确认达成后在回复末尾输出“目标已达成”即结束,未达成会一直运行,可用取消停止;任务不限时(去掉 worker/docker 总超时;单轮 600 秒护栏还在)。服务端默认的自动续跑与断点镜像同时生效。
: null}
附件(放进任务工作区,图片与普通文件不区分):
diff --git a/cloud/console-react/src/sections/TaskDetailPanel.tsx b/cloud/console-react/src/sections/TaskDetailPanel.tsx
index 487ccf3..5a38dd1 100644
--- a/cloud/console-react/src/sections/TaskDetailPanel.tsx
+++ b/cloud/console-react/src/sections/TaskDetailPanel.tsx
@@ -60,7 +60,7 @@ export default function TaskDetailPanel() {
const fc = firstChar(t);
const cost = ctx.costSummary;
const modeText = t.plan ? "计划模式(只读)"
- : t.goal_mode ? (t.no_time_limit ? "goal 模式无敌版(不限时)" : "goal 模式(不限轮次,模型宣告完成)")
+ : t.goal_mode ? (t.no_time_limit ? "goal 模式(不限轮次,模型宣告完成;任务不限时)" : "goal 模式(不限轮次,模型宣告完成)")
: t.verify_command ? "goal 模式(旧语义,验收命令)" : null;
return (
diff --git a/cloud/console.html b/cloud/console.html
index dcd1e42..a59cb58 100644
--- a/cloud/console.html
+++ b/cloud/console.html
@@ -4,7 +4,7 @@
Codex 命令台
-
+`)}}S("流已断开")}catch(lt){if(lt.name==="AbortError")return;M(lt instanceof Error?lt.message:String(lt)),S("未开始")}finally{x(!1)}},[r]),F=d.useCallback(()=>{var R;(R=B.current)==null||R.abort(),x(!1),S("已停止")},[]),yt=d.useCallback(async R=>{if(r)try{const X=await $(W.taskBrowserControl(r.id),"POST",{holder:R});C(X),M("")}catch(X){M(X instanceof Error?X.message:String(X))}},[r]),_t=d.useCallback(async R=>{if(!r||(y==null?void 0:y.holder)!=="user"||!V.current)return;const X=V.current.getBoundingClientRect(),lt=Math.round((R.clientX-X.left)/X.width*1280),pt=Math.round((R.clientY-X.top)/X.height*800);try{await $(W.taskBrowserInput(r.id),"POST",{type:"mouse_click",x:lt,y:pt})}catch(Et){M(Et instanceof Error?Et.message:String(Et))}},[r,y]),kt=d.useCallback(async R=>{if(!(!r||(y==null?void 0:y.holder)!=="user")){R.preventDefault();try{R.key.length===1?await $(W.taskBrowserInput(r.id),"POST",{type:"type",text:R.key}):await $(W.taskBrowserInput(r.id),"POST",{type:"key",key:R.key})}catch(X){M(X instanceof Error?X.message:String(X))}}},[r,y]);if(!r)return c.jsx("div",{className:"muted",children:"点任务行查看详情"});const Q=(y==null?void 0:y.holder)||"—",dt=y!==null;return c.jsxs("div",{children:[c.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",alignItems:"center"},children:[c.jsxs("span",{children:["状态 ",c.jsx("b",{children:A})]}),c.jsxs("span",{className:"muted",children:["会话 ",dt?"活跃":"未激活(轮次结束即消失)"]}),c.jsxs("span",{className:"muted",children:["控制权 ",Q]}),y!=null&&y.url?c.jsx("span",{className:"muted",title:y.url,children:y.url.slice(0,80)}):null]}),c.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginTop:8},children:[Y?c.jsx("button",{type:"button",onClick:F,children:"停止观看"}):c.jsx("button",{type:"button",onClick:()=>void ft(),children:"开始观看"}),c.jsx("button",{type:"button",onClick:()=>void et(),children:"刷新状态"}),Q!=="user"?c.jsx("button",{type:"button",onClick:()=>void yt("user"),disabled:!dt,children:"接管"}):c.jsx("button",{type:"button",onClick:()=>void yt("agent"),children:"交还给 Agent"})]}),_?c.jsx("div",{className:"muted",style:{marginTop:8},children:_}):null,Q==="user"?c.jsx("div",{className:"muted",style:{marginTop:8},children:"你已接管:点画面即点击,键盘输入直达页面。交还后 Agent 续跑前会先快照确认你的改动。"}):null,c.jsx("div",{style:{marginTop:8},children:h?c.jsx("img",{ref:V,src:h,alt:"浏览器实时画面",tabIndex:0,onClick:R=>void _t(R),onKeyDown:R=>void kt(R),style:{width:"100%",maxWidth:1280,cursor:Q==="user"?"crosshair":"default",border:"1px solid var(--border, #ccc)"}}):c.jsx("div",{className:"muted",children:dt?"点“开始观看”接入画面流(接管后点画面即点击)":"浏览器会话未激活:任务本轮未开浏览器,或轮次已结束。"})})]})}function bg(){const i=Lt(),[r,h]=d.useState("uncommittedChanges"),[f,y]=d.useState(""),[C,A]=d.useState(""),[S,_]=d.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("h3",{children:"评审队列"}),c.jsxs("select",{"aria-label":"评审目标",value:r,onChange:M=>h(M.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:f,onChange:M=>y(M.target.value)}),c.jsx("input",{className:"stacked",placeholder:"指定提交用:提交 sha",style:{width:"100%"},value:C,onChange:M=>A(M.target.value)}),c.jsx("textarea",{placeholder:"自定义评审指令用:评审指令正文",value:S,onChange:M=>_(M.target.value)}),c.jsxs(At,{children:[c.jsx("button",{className:"primary",onClick:()=>void i.postReview({target_type:r,branch:f.trim()||void 0,sha:C.trim()||void 0,instructions:S.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(ou,{children:i.reviews.map(M=>{let Y=M.target_type||"";return M.branch&&(Y+=":"+M.branch),M.sha&&(Y+=":"+String(M.sha).slice(0,12)),M.instructions&&(Y+=":"+String(M.instructions).slice(0,80)),c.jsxs("li",{children:[c.jsxs("span",{className:"row-main",children:[c.jsx("b",{children:"评审"})," ",xe(M.id)," | ",Y," | ",c.jsx("span",{className:"st-"+(M.status||""),children:M.status}),M.created_at?" | "+Le(M.created_at):"",c.jsx("br",{}),M.findings?String(M.findings).slice(0,1e3):c.jsx("span",{className:"muted",children:"(暂无 findings:评审尚未执行或尚未写回)"})]}),c.jsx("button",{onClick:()=>i.submitFindings(M.id),children:"写 findings"})]},M.id)})})]})}function Tg(){const i=Lt();return i.currentTask?i.currentTask.coordinator_parts?i.coordChildren.length===0?c.jsx("div",{className:"muted",children:"(子任务尚未创建)"}):c.jsx(ou,{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})," | ",xe(r.id)," | ",String(r.prompt||"").slice(0,60)]})},r.id))}):c.jsx("div",{className:"muted",children:"(非协调员任务)"}):c.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示协调员的子任务"})}function _g(){const i=Lt();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:"模型子代理"},h={running:"进行中",completed:"已完成",failed:"失败",interrupted:"已中断",unknown:"未知"};return c.jsx(ou,{children:i.agents.map((f,y)=>c.jsx("li",{children:c.jsxs("span",{className:"row-main",children:[c.jsxs("b",{children:[r[f.kind||""]||f.kind||"",":"]}),f.name||""," ",c.jsx("span",{className:"st-"+(f.status||""),children:h[f.status||""]||f.status||"?"})," | 过程调用 "+(f.calls?f.calls.length:0)+" 条",f.updated_ts?" | 最近活动 "+Le(f.updated_ts/1e3):"",f.prompt?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsxs("span",{className:"muted",children:["任务:",f.prompt]})]}):null,f.calls&&f.calls.length?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),f.calls.slice(-50).map((C,A)=>c.jsx("div",{children:yo(C)},A))]}):c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsx("span",{className:"muted",children:"(暂无过程调用)"})]})]})},y))})}function Eg(){const i=Lt();return c.jsxs(c.Fragment,{children:[c.jsxs(At,{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(ol,{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)+" "+Le(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 Ng(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState("");return c.jsxs(c.Fragment,{children:[c.jsx("input",{placeholder:"目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)",style:{width:"100%"},value:r,onChange:C=>h(C.target.value)}),c.jsx("textarea",{placeholder:"消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)",value:f,onChange:C=>y(C.target.value)}),c.jsxs(At,{children:[c.jsx("button",{onClick:async()=>{await i.postPeer("queued",r,f),y("")},children:"排队发给对方"}),c.jsx("button",{className:"primary",onClick:async()=>{await i.postPeer("direct",r,f),y("")},children:"直接发送"}),c.jsx("span",{className:"muted",children:i.peerMsg})]}),c.jsx(ol,{empty:"(本任务尚未发出任务间消息)",items:i.peerMessages.map((C,A)=>c.jsxs("span",{className:"row-main",children:["[发给 ",String(C.task_id).slice(0,8),"|",C.mode,"|",C.status,"] ",String(C.body||"").slice(0,120)]},A))})]})}function Cg(){const i=Lt(),[r,h]=d.useState(""),f=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(At,{children:[c.jsx("input",{type:"text",placeholder:"新线程名",value:r,onChange:y=>h(y.target.value)}),c.jsx("button",{disabled:!f,onClick:()=>i.threadAction("rename",r),children:"重命名"}),c.jsx("button",{disabled:!f,onClick:()=>i.threadAction("archive",""),children:"归档"}),c.jsx("button",{disabled:!f,onClick:()=>i.threadAction("unarchive",""),children:"取消归档"}),c.jsx("button",{disabled:!f,onClick:()=>i.threadAction("compact",""),children:"压缩"}),c.jsx("span",{className:"muted",children:i.threadGateNote}),c.jsx("span",{className:"muted",children:i.threadMsg})]}),c.jsx(ol,{empty:"暂无其他线程",items:i.threadList.map((y,C)=>c.jsxs("span",{className:"row-main",children:[y.name||y.thread_name||y.id||""," [",y.id||"","]",y.archived?" [已归档]":"",y.cwd?" "+y.cwd:""]},C))}),c.jsx("div",{className:"muted",children:"限制:Docker/异机任务线程操作一律 409;merged/merge-failed 不可改;turn/steer 与 review/start 不在本批。"})]})}function Ag(i){return/503|Service Unavailable/.test(i)?"上游模型服务暂时不可用(503):模型一轮都没跑出来,不是任务逻辑失败;等上游恢复或换模型重试":/429|rate limit/i.test(i)?"上游限流(429):模型拒绝了本次调用,可稍后重试":/timeout|timed out/i.test(i)?"上游调用超时:模型响应未在限时内返回":/401|403|Invalid API key|unauthorized/i.test(i)?"上游鉴权失败:网关 key 或权限有问题":/ECONNREFUSED|ENOTFOUND|network|fetch failed/i.test(i)?"连不上上游模型服务:网络或网关地址有问题":"任务失败(原因见原始错误文本)"}function Mg(i){return i===null||i<0?"未知":i<60?Math.floor(i)+" 秒前":i<3600?Math.floor(i/60)+" 分钟前":(i/3600).toFixed(1)+" 小时前"}const Og=[["overview","概览"],["collab","协作"],["review","评审与审批"],["threads","线程"],["browser","浏览器"]];function zg(){const i=Lt(),r=i.currentTask,[h,f]=d.useState("overview");if(!r)return c.jsx(Ft,{id:"nav-detail",title:"任务详情",children:c.jsx("div",{className:"muted",children:"点任务行查看详情"})});const[y,C]=$h(r),[A,S]=Ih(r),_=Wh(r),M=i.costSummary,Y=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.jsx("nav",{className:"detail-tabs","aria-label":"任务详情页签",children:Og.map(([x,B])=>c.jsx("button",{type:"button",className:h===x?"active":"",onClick:()=>f(x),children:B},x))}),h==="overview"?c.jsxs(c.Fragment,{children:[c.jsxs(Ft,{title:"任务详情",children:[c.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap"},children:[c.jsx("span",{className:"issue-first",title:"任务首字:"+_,"aria-hidden":"true",children:_}),c.jsxs("span",{children:["状态 ",c.jsx("b",{className:"st-"+r.status,children:r.status}),"(",Wy[r.status]||"未知状态",")"]}),c.jsxs("span",{className:"muted",children:["更新 ",Le(r.updated_at)]})]}),c.jsxs("div",{className:"detail-cards",children:[c.jsxs("div",{className:"detail-card",title:C,children:[c.jsx("div",{className:"detail-card-label",children:"耗时"}),c.jsx("div",{className:"detail-card-value",children:y})]}),c.jsxs("div",{className:"detail-card",title:S,children:[c.jsx("div",{className:"detail-card-label",children:"token"}),c.jsx("div",{className:"detail-card-value",children:A})]}),c.jsxs("div",{className:"detail-card",title:"LLM 请求数 = GET /tasks/{id}/cost 的 llm_requests,即 cost_records 的 completions 之和:host.py 每收到一次 thread/tokenUsage/updated(一次上游补全)计 1,worker 每轮终局记账时累加;估算行(无真实用量)计 0;部署前已记账的老任务没有 completions 列,显示 0 而非回填数",children:[c.jsx("div",{className:"detail-card-label",children:"LLM 请求数"}),c.jsx("div",{className:"detail-card-value",children:M===void 0?"加载中…":M===null?"—":(M.llm_requests??0).toLocaleString()}),M===void 0?c.jsx("div",{className:"muted",children:"成本加载中…"}):M===null?c.jsx("div",{className:"muted",children:"成本明细加载失败,LLM 请求数不可用"}):c.jsxs("div",{className:"muted",children:["上游补全次数之和| 轮数 ",M.turns??0," | fallback ",M.fallback_count??0]})]}),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:M===void 0?"加载中…":M===null?"—":dg(M.usd_micros)}),M===void 0?c.jsx("div",{className:"muted",children:"成本加载中…"}):M===null?c.jsx("div",{className:"muted",children:"成本明细加载失败(“查成本”按钮仍可手动拉取原始 JSON)"}):c.jsxs("div",{className:"muted",children:["token ",(M.total_tokens??0).toLocaleString(),"(实际 ",(M.actual_tokens??0).toLocaleString()," / 估算 ",(M.estimated_tokens??0).toLocaleString(),",缓存 ",(M.cached_input_tokens??0).toLocaleString(),",无价 ",(M.unpriced_actual_tokens??0).toLocaleString(),")| fallback ",M.fallback_count??0]})]})]})]}),r.status==="running"||r.status==="queued"?(()=>{const x=Date.now()/1e3,B=r.last_heartbeat||r.updated_at||null,V=B?x-B:null;return c.jsxs(Ft,{title:"LLM 进度",children:[c.jsxs("div",{children:["状态 ",r.status==="running"?"进行中":"排队中"," · 已用 ",y,V!==null?" · 上次活动 "+Mg(V):""]}),V!==null&&V>180?c.jsx("div",{className:"muted",children:"超过 3 分钟无活动:可能在等上游模型响应(上游 503 时 worker 会重试后失败,失败后这里会显示失败原因;无活动不等于已断连,服务端没有“LLM 已连接”字段,不作此断言)"}):c.jsx("div",{className:"muted",children:"首轮无输出时属正常:模型第一轮回复到达前 trace 里没有消息;回复到达后会在会话区出现,成本里的 LLM 请求数随之增加"})]})})():null,r.error_text?c.jsxs(Ft,{title:"失败原因",children:[c.jsx("div",{children:Ag(r.error_text)}),c.jsx("pre",{style:{whiteSpace:"pre-wrap",overflowWrap:"anywhere"},children:r.error_text.slice(0,1e3)}),c.jsxs("div",{className:"muted",children:["完整错误文本仍在下方“操作与结果”里;模型 ",r.model||"默认"," · executor ",r.executor||""]})]}):null,c.jsx(Ft,{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:xe(r.turn_id)})]}),c.jsxs("div",{children:[c.jsx("dt",{children:"root turn"}),c.jsx("dd",{children:xe(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:xe(r.project_id)})]}),Y?c.jsxs("div",{children:[c.jsx("dt",{children:"模式"}),c.jsx("dd",{children:Y})]}):null,r.forked_from?c.jsxs("div",{children:[c.jsx("dt",{children:"分支自"}),c.jsx("dd",{children:xe(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(x=>x.name).join("、"),")"]})]}):null,r.parent_task_id?c.jsxs("div",{children:[c.jsx("dt",{children:"协调子任务"}),c.jsxs("dd",{children:["父任务 ",xe(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(Ft,{title:"prompt",children:c.jsx("div",{style:{whiteSpace:"pre-wrap",overflowWrap:"anywhere"},children:r.prompt||"(无 prompt)"})}),c.jsxs(Ft,{title:"操作与结果",children:[c.jsx(xg,{}),c.jsx("pre",{children:i.detailBody||"(暂无 result/error 输出)"}),i.costBox?c.jsx("pre",{children:i.costBox}):null]})]}):h==="collab"?c.jsxs(c.Fragment,{children:[c.jsx(Ft,{title:"协调子任务",children:c.jsx(Tg,{})}),c.jsx(Ft,{title:"子代理链路",children:c.jsx(_g,{})}),c.jsx(Ft,{title:"给其他任务发消息",children:c.jsx(Ng,{})})]}):h==="review"?c.jsxs(c.Fragment,{children:[c.jsx(Ft,{title:"评审队列",children:c.jsx(bg,{})}),c.jsx(Ft,{title:"运行时审批队列",children:c.jsx(Eg,{})})]}):h==="browser"?c.jsx(c.Fragment,{children:c.jsx(Ft,{title:"浏览器远控",children:c.jsx(jg,{})})}):c.jsx(c.Fragment,{children:c.jsx(Ft,{title:"线程",children:c.jsx(Cg,{})})})]})}function Rg(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState(""),[C,A]=d.useState([]),[S,_]=d.useState(null),[M,Y]=d.useState(!1),[x,B]=d.useState(""),[V,et]=d.useState(""),ft=d.useCallback(async()=>{if(!i.keySaved){A([]);return}try{const Q=await $(W.userKeys);A(Q.keys||[]),et("")}catch(Q){et(Q instanceof Error?Q.message:"加载 key 列表失败")}},[i.keySaved]);d.useEffect(()=>{ft()},[ft]);const F=async()=>{B(""),et(""),Y(!1);try{const Q=await $(W.userKeys,"POST",{label:f.trim()||"api-key"});_(Q),y(""),B("新 key 已生成,只显示一次:复制后请妥善保存。"),await ft()}catch(Q){et(Q instanceof Error?Q.message:"生成 key 失败")}},yt=async()=>{if(S)try{await navigator.clipboard.writeText(S.api_key),Y(!0)}catch{et("复制失败:请手动选中上方 key 文本复制")}},_t=()=>{S&&(i.saveKeyInput(S.api_key),_(null),B("已存为当前浏览器 key(原有 key 未被撤销,需要时可单独撤销)。"))},kt=async Q=>{const dt=(()=>{try{return rl().slice(-4)}catch{return""}})(),R=Q.id==="legacy"?"(主 key:撤销后当前浏览器保存的 key 也可能随之失效,需重新登录拿新 key)":Q.hint&&Q.hint===dt?"(这就是本浏览器当前在用的 key,撤销后本页会立刻未连接)":"";if(window.confirm(`撤销 key「${Q.label}」(后 4 位 ${Q.hint||"无"})吗?${R}撤销不可恢复。`)){B(""),et("");try{await $(W.userKey(Q.id),"DELETE"),B(`已撤销 key「${Q.label}」。`),await ft()}catch(X){et(X instanceof Error?X.message:"撤销失败")}}};return c.jsxs(Ft,{id:"nav-key",title:"API Key",children:[c.jsxs(At,{children:[c.jsx("input",{type:"password",placeholder:"粘贴你的 X-API-Key(与调 API 用的同一个)",autoComplete:"off",value:r,onChange:Q=>h(Q.target.value)}),c.jsx("button",{className:"primary",onClick:()=>{i.saveKeyInput(r),h("")},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(At,{children:[c.jsx("input",{placeholder:"新 key 备注(可选,默认 api-key,如 harness2-temp)",autoComplete:"off",value:f,onChange:Q=>y(Q.target.value)}),c.jsx("button",{className:"primary",onClick:()=>void F(),children:"生成新 key"}),c.jsx("button",{onClick:()=>void ft(),children:"刷新列表"})]}),S&&c.jsxs("div",{children:[c.jsx("div",{children:c.jsxs("span",{className:"muted",children:["新 key(",S.label,",后 4 位 ",S.hint,"):只显示一次,关闭后无法再查看。"]})}),c.jsxs(At,{children:[c.jsx("input",{type:"text",readOnly:!0,value:S.api_key,onFocus:Q=>Q.target.select()}),c.jsx("button",{className:"primary",onClick:()=>void yt(),children:M?"已复制":"复制"}),c.jsx("button",{onClick:_t,children:"存为当前浏览器 key"}),c.jsx("button",{onClick:()=>_(null),children:"关闭(不再显示)"})]})]}),x&&c.jsx("div",{children:c.jsx("span",{className:"muted",children:x})}),V&&c.jsx("div",{children:c.jsx("span",{children:V})}),c.jsxs("div",{className:"api-key-list",children:[C.length===0&&c.jsx("span",{className:"muted",children:"暂无 key(或列表加载失败,见上方报错)。"}),C.map(Q=>c.jsxs("div",{children:[c.jsx("span",{children:Q.label})," ",c.jsxs("span",{className:"muted",children:["后 4 位 ",Q.hint||"无"," · 创建 ",Le(Q.created_at)," · 最近使用 ",Q.last_used_at?Le(Q.last_used_at):"未使用过"]})," ",Q.revoked_at?c.jsxs("span",{className:"muted",children:["已撤销(",Le(Q.revoked_at),")"]}):c.jsx("button",{onClick:()=>void kt(Q),children:"撤销"})]},Q.id))]})]})]})}function Dg(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState("");return c.jsxs(Ft,{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(At,{children:[c.jsx("input",{type:"text",placeholder:"要查配额的用户 id",value:i.adminUserId,onChange:C=>i.setAdminUserId(C.target.value)}),c.jsx("button",{onClick:i.adminQuota,children:"查该用户配额"})]}),c.jsxs(At,{children:[c.jsx("input",{type:"text",placeholder:"要设置配额的用户 id",value:r,onChange:C=>h(C.target.value)}),c.jsx("input",{type:"text",placeholder:"美元配额(留空 = 不限额)",value:f,onChange:C=>y(C.target.value)}),c.jsx("button",{className:"primary",onClick:()=>i.adminSetQuota(r,f),children:"设置配额"})]}),c.jsxs(At,{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 Ug(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState("contributor"),C=i.projects.find(A=>A.id===i.projectId);return c.jsxs(Ft,{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(At,{children:[c.jsx("input",{type:"text",placeholder:"成员 user_id 或用户名",value:r,onChange:A=>h(A.target.value)}),c.jsxs("select",{"aria-label":"邀请角色",value:f,onChange:A=>y(A.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,f),h("")},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(ou,{children:i.members.map(A=>{const S=(A.username||"")+(A.username?"("+String(A.user_id).slice(0,8)+")":String(A.user_id).slice(0,8));return c.jsxs("li",{children:[c.jsx("span",{className:"row-main",children:S}),c.jsx("select",{"aria-label":"成员角色",value:A.role||"viewer",onChange:_=>void i.changeMemberRole(A.user_id,_.target.value),children:$y.map(_=>c.jsx("option",{value:_,children:_},_))}),c.jsx("button",{onClick:()=>void i.removeMember(A.user_id),children:"移除"})]},A.user_id)})}),c.jsx("span",{className:"muted",children:i.memberMsg})]})}function wg(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState(""),[C,A]=d.useState("");return c.jsxs("div",{className:"project-nav",children:[c.jsxs(Ft,{title:"项目",children:[c.jsx(At,{children:c.jsx("button",{onClick:i.refreshProjects,children:"刷新项目"})}),i.projects.length===0?c.jsx("div",{className:"muted",children:"暂无项目"}):c.jsx("ul",{className:"project-nav-list",children:i.projects.map(S=>c.jsxs("li",{className:"project-nav-item"+(S.id===i.projectId?" selected":""),onClick:()=>i.selectProject(S.id),title:S.id,children:[c.jsx("span",{className:"project-nav-name",children:S.name}),c.jsxs("span",{className:"project-nav-meta",children:[xe(S.id),S.my_role?" · "+S.my_role:""]})]},S.id))}),c.jsx("h3",{children:"创建项目"}),c.jsx(At,{children:c.jsx("input",{type:"text",placeholder:"新项目名",value:r,onChange:S=>h(S.target.value)})}),c.jsx(At,{children:c.jsxs("select",{"aria-label":"从 GitHub 仓库选",value:f,onChange:S=>{y(S.target.value),S.target.value&&A(S.target.value)},children:[c.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选,或手动输入)"}),i.githubRepos.map(S=>c.jsx("option",{value:S.clone_url,children:S.repo_full_name},S.clone_url))]})}),c.jsxs(At,{children:[c.jsx("input",{type:"text",placeholder:"repo_url(可选)",value:C,onChange:S=>A(S.target.value)}),c.jsx("button",{className:"primary",onClick:async()=>{await i.createProject(r,C),h(""),A(""),y("")},children:"创建项目"})]}),c.jsx("span",{className:"muted",children:i.projectMsg})]}),c.jsx(Ug,{})]})}function kg(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState(""),[C,A]=d.useState("");return c.jsxs(Ft,{id:"nav-env",title:c.jsxs(c.Fragment,{children:["环境 ",c.jsx("span",{className:"muted",children:"(选、建、管:当前项目的基准检出)"})]}),children:[c.jsxs(At,{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(ou,{children:i.envs.map(S=>c.jsxs("li",{children:[c.jsxs("span",{className:"row-main",children:[S.name,"(",xe(S.id),") / 分支 ",S.branch||"默认分支"," / 执行器 ",S.executor||"不限"," / 状态 ",S.status,S.status==="failed"&&S.error_text?" / 失败原因:"+S.error_text:""]}),S.status==="archived"?null:c.jsx("button",{onClick:()=>void i.archiveEnv(S.id),children:"归档"})]},S.id))}),c.jsxs(At,{children:[c.jsx("input",{type:"text",placeholder:"新环境名",value:r,onChange:S=>h(S.target.value)}),c.jsx("input",{type:"text",placeholder:"分支(可选,空=默认分支)",value:f,onChange:S=>y(S.target.value)}),c.jsxs("select",{"aria-label":"新环境执行器",value:C,onChange:S=>A(S.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,f,C),h(""),y("")},children:"新建环境"})]}),c.jsx("span",{className:"muted",children:i.envMsg})]})}function Hg(){const i=Lt(),[r,h]=d.useState("");return c.jsxs(Ft,{title:"仓库与环境上下文",children:[c.jsx("div",{className:"muted",children:i.envRepoLine||"先选项目"}),c.jsx("div",{className:"muted",children:i.envCount}),i.envRepoBar?c.jsxs(At,{children:[c.jsxs("select",{"aria-label":"补仓库",value:r,onChange:f=>h(f.target.value),children:[c.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选)"}),i.githubRepos.map(f=>c.jsx("option",{value:f.clone_url,children:f.repo_full_name},f.clone_url))]}),c.jsx("button",{onClick:()=>void i.saveEnvRepo(r),children:"保存仓库"})]}):null,c.jsx("span",{className:"muted",children:i.envRepoMsg})]})}function Bg(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState("all"),C=_=>{const M=vo(_);return _.alive!==void 0&&_.alive!==null?!!_.alive:M.age!==null&&M.age<=120},A=r.trim().toLowerCase(),S=(i.workers||[]).filter(_=>!(A&&!((_.worker_id||_.id||"")+" "+(_.executor||"")).toLowerCase().includes(A)||f==="online"&&!C(_)||f==="offline"&&C(_)));return c.jsxs(Ft,{id:"nav-workers",title:"Workers",children:[c.jsx(At,{children:c.jsx("button",{onClick:i.refreshWorkers,children:"刷新"})}),c.jsxs(At,{children:[c.jsx("input",{type:"text",placeholder:"搜索 worker_id / 执行器","aria-label":"搜索 Worker",value:r,onChange:_=>h(_.target.value)}),c.jsxs("select",{"aria-label":"在线状态筛选",value:f,onChange:_=>y(_.target.value),children:[c.jsx("option",{value:"all",children:"在线状态:全部"}),c.jsx("option",{value:"online",children:"仅在线"}),c.jsx("option",{value:"offline",children:"仅离线"})]}),i.workers?c.jsxs("span",{className:"muted",children:["显示 ",S.length," / 共 ",i.workers.length," 个"]}):null]}),i.workersError?c.jsx("div",{className:"muted",children:i.workersError}):i.workers===null?c.jsxs("div",{className:"muted",children:[i.workersSummary||"未加载","(完整清单仅全局管理员可见,搜索/筛选仅对完整清单生效)"]}):i.workers.length===0?c.jsx("div",{className:"muted",children:"无 worker 注册"}):S.length===0?c.jsx("div",{className:"muted",children:"没有符合筛选条件的 worker"}):c.jsx(ou,{children:S.map((_,M)=>{const Y=_.running===void 0||_.running===null?"?":_.running,x=_.capacity===void 0||_.capacity===null?"?":_.capacity,B=vo(_),V=C(_),et=V?" / 在线":" / 离线(占用为上次上报值)";return c.jsx("li",{className:V?"is-online":"is-offline",children:c.jsxs("span",{className:"row-main",children:[_.worker_id||_.id||"?"," / ",_.executor||""," / 占用 ",Y,"/",x,et," / 最后心跳 ",B.text]})},M)})})]})}function qg(){const i=Lt();return c.jsxs(Ft,{title:"健康与配额",children:[c.jsxs(At,{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 Yg(){const i=Lt();return c.jsxs(Ft,{id:"nav-skills",title:"技能与 MCP",children:[c.jsx("div",{className:"muted",children:"反映宿主租户 home,容器内 home 可能不同;重载只在 schema 枚举里,当前 pin 的二进制拒绝时原样 502;OAuth 只发起登录,不代表登录完成。"}),c.jsxs(At,{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(ol,{empty:"暂无技能",items:i.skills.map((r,h)=>c.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:"",r.detail?" - "+r.detail:""]},h))}),c.jsx("h3",{children:"应用"}),c.jsx(ol,{empty:"暂无应用",items:i.apps.map((r,h)=>c.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:""]},h))}),c.jsx("h3",{children:"MCP 服务"}),c.jsx(ol,{empty:"暂无 MCP 服务",items:i.mcpServers.map((r,h)=>{const f=r.detail||r.details||r.state||"";return c.jsxs("span",{className:"row-main",children:[r.name||r.id||""," | 状态 ",r.status||"",f?" | "+f:""]},h)})})]})}function Gg(){const i=Lt(),[r,h]=d.useState("");return c.jsxs(Ft,{title:"MCP 操作",children:[c.jsxs(At,{children:[c.jsx("button",{onClick:i.reloadMcp,children:"重载配置"}),c.jsx("span",{className:"muted",children:i.mcpMsg})]}),c.jsxs(At,{children:[c.jsx("input",{type:"text",placeholder:"MCP 服务名",value:r,onChange:f=>h(f.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]})}const Vh=160;function Qg(i){return i?i%86400===0?"(每天)":i%3600===0?"(每小时)":i%60===0?"(每 "+i/60+" 分钟)":"":""}function Xg({detail:i}){const r=Lt(),h=f=>{if(f){r.showDetail(f);try{window.location.hash="#view-tasks"}catch{}}};return c.jsxs("div",{className:"card",children:[c.jsxs("h2",{children:["自动化详情:",i.name]}),c.jsxs("div",{className:"muted",children:["状态 ",i.status,i.due?"|到期":""," | 每 ",i.interval_seconds," 秒 | 下次 ",Le(i.next_run_at),"| 上次执行 ",Le(i.last_run_at)," | 创建人 ",i.created_by?xe(i.created_by):""," | 创建于 ",Le(i.created_at),i.cancelled_at?" | 已取消于 "+Le(i.cancelled_at):"",i.heartbeat_binding?" | 心跳绑定:已绑定":""]}),c.jsx("div",{className:"muted",style:{whiteSpace:"pre-wrap",marginTop:8},children:i.prompt||""}),i.repo_url?c.jsxs("div",{className:"muted",children:["仓库 ",i.repo_url]}):null,c.jsxs(At,{children:[c.jsx("button",{onClick:r.closeAutomationDetail,children:"关闭详情"}),c.jsxs("span",{className:"muted",children:["编辑请在下面列表里点“编辑”。",r.autoDetailMsg]})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["最近产出(",(i.runs||[]).length,")"]}),c.jsx(ol,{empty:"(无)",items:(i.runs||[]).map((f,y)=>c.jsxs("span",{className:"row-main",children:[f.status,f.created_at?"|"+Le(f.created_at):"",f.task_id?c.jsxs(c.Fragment,{children:[" | 任务 ",c.jsx("button",{onClick:()=>h(f.task_id),children:xe(f.task_id)})]}):"",f.detail?"|"+String(f.detail).slice(0,120):""]},y))})]}),i.runs_note?c.jsx("div",{className:"muted",children:i.runs_note}):null]})}function Lg(){const i=Lt(),[r,h]=d.useState(""),[f,y]=d.useState(""),[C,A]=d.useState(""),[S,_]=d.useState(""),[M,Y]=d.useState(""),[x,B]=d.useState(""),[V,et]=d.useState(""),[ft,F]=d.useState(""),[yt,_t]=d.useState(""),[kt,Q]=d.useState({}),dt=R=>{Y(R.id),B(R.name||""),et(R.prompt||""),F(R.interval_seconds?String(R.interval_seconds):""),_t(R.repo_url||"")};return c.jsxs(c.Fragment,{children:[c.jsx("input",{placeholder:"自动化名称(同项目内启用中的名称唯一)",style:{width:"100%"},value:r,onChange:R=>h(R.target.value)}),c.jsx("textarea",{placeholder:"定时任务内容(创建只登记定义与到期状态;执行由后续执行器经 claim 抢单后建任务,不另起调度器)",value:f,onChange:R=>y(R.target.value)}),c.jsxs(At,{children:[c.jsx("input",{placeholder:"间隔秒数(默认 86400,最小 60)",style:{width:"40%"},value:C,onChange:R=>A(R.target.value)}),c.jsx("input",{placeholder:"仓库(可选)",style:{width:"40%"},value:S,onChange:R=>_(R.target.value)}),c.jsx("button",{className:"primary",onClick:async()=>{await i.createAutomation(r,f,C,S),h(""),y(""),A(""),_("")},children:"创建自动化"}),c.jsx("button",{onClick:i.refreshAutomations,children:"刷新自动化"}),c.jsx("span",{className:"muted",children:i.autoMsg})]}),c.jsx(ol,{empty:"(暂无自动化)",items:i.automations.map(R=>{const X=R.prompt||"",lt=!!kt[R.id],pt=X.length>Vh,Et=X?lt||!pt?X:X.slice(0,Vh)+"…":"(无内容)";return c.jsxs("div",{children:[c.jsxs("div",{className:"row-main",children:["[",R.status,R.due?"|到期":"",R.run_once?"|一次性":"","] ",R.name,"|每 ",R.interval_seconds," 秒",Qg(R.interval_seconds),"|上次 ",Le(R.last_run_at)||"未运行","|下次 ",Le(R.next_run_at),c.jsx("button",{onClick:()=>void i.loadAutomationDetail(R.id),children:"详情"}),R.status==="active"?c.jsxs(c.Fragment,{children:[" ",c.jsx("button",{onClick:()=>dt(R),children:"编辑"})," ",c.jsx("button",{onClick:()=>i.cancelAutomation(R.id),children:"取消"})]}):null]}),R.repo_url?c.jsxs("div",{className:"muted",children:["仓库:",R.repo_url]}):null,R.status==="cancelled"&&R.cancelled_at?c.jsxs("div",{className:"muted",children:["已取消于 ",Le(R.cancelled_at)]}):null,c.jsxs("div",{className:"muted",style:{whiteSpace:"pre-wrap",overflowWrap:"anywhere"},children:[Et,pt?c.jsx("button",{onClick:()=>Q(mt=>({...mt,[R.id]:!mt[R.id]})),children:lt?"收起":"展开"}):null]}),M===R.id?c.jsxs("div",{children:[c.jsx("input",{placeholder:"自动化名称",style:{width:"100%"},value:x,onChange:mt=>B(mt.target.value)}),c.jsx("textarea",{placeholder:"定时任务内容",value:V,onChange:mt=>et(mt.target.value)}),c.jsxs(At,{children:[c.jsx("input",{placeholder:"间隔秒数(最小 60,留空保持原值)",style:{width:"40%"},value:ft,onChange:mt=>F(mt.target.value)}),c.jsx("input",{placeholder:"仓库(可选,清空则清除)",style:{width:"40%"},value:yt,onChange:mt=>_t(mt.target.value)}),c.jsx("button",{className:"primary",onClick:async()=>{const mt=i.automations.find(k=>k.id===M)||R;await i.updateAutomation(mt,x,V,ft,yt)&&Y("")},children:"保存"}),c.jsx("button",{onClick:()=>Y(""),children:"取消"})]})]}):null]},R.id)})}),i.autoDetailMsg&&!i.autoDetail?c.jsx("div",{className:"muted",children:i.autoDetailMsg}):null,i.autoDetail?c.jsx(Xg,{detail:i.autoDetail},i.autoDetail.id):null]})}function Vg(){var y,C,A,S;const i=Lt(),r=i.triage,h=_=>{if(_){i.showDetail(_);try{window.location.hash="#view-tasks"}catch{}}},f=_=>{if(_){i.loadAutomationDetail(_);try{window.location.hash="#view-automation"}catch{}}};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:["到期自动化(",((y=r.counts)==null?void 0:y.automations_due)||0,")"]}),c.jsx(ol,{empty:"(无)",items:(r.automations_due||[]).map((_,M)=>c.jsx("span",{className:"row-main",children:_.id?c.jsxs("button",{onClick:()=>f(_.id),children:[_.name,"|每 ",_.interval_seconds," 秒"]}):c.jsxs(c.Fragment,{children:[_.name,"|每 ",_.interval_seconds," 秒"]})},M))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["失败/中断任务(",((C=r.counts)==null?void 0:C.failed_tasks)||0,")"]}),c.jsx(ol,{empty:"(无)",items:(r.failed_tasks||[]).map((_,M)=>c.jsx("span",{className:"row-main",children:c.jsxs("button",{onClick:()=>h(_.id),children:[xe(_.id),"|",_.status,"|",String(_.prompt||"").slice(0,80)]})},M))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["待处理后续消息(",((A=r.counts)==null?void 0:A.pending_followups)||0,")"]}),c.jsx(ol,{empty:"(无)",items:(r.pending_followups||[]).map((_,M)=>c.jsx("span",{className:"row-main",children:c.jsxs("button",{onClick:()=>h(_.task_id),children:["任务 ",xe(_.task_id),"|",String(_.body||"").slice(0,80)]})},M))})]}),c.jsxs("div",{className:"data-group",children:[c.jsxs("b",{children:["最近自动化产出(",((S=r.counts)==null?void 0:S.recent_runs)||0,")"]}),c.jsx(ol,{empty:"(无)",items:(r.recent_runs||[]).map((_,M)=>c.jsxs("span",{className:"row-main",children:[xe(_.automation_id),"|",_.status,_.task_id?c.jsxs(c.Fragment,{children:["|任务 ",c.jsx("button",{onClick:()=>h(_.task_id),children:xe(_.task_id)})]}):"",_.task_status?"|"+_.task_status:""]},M))})]})]}):c.jsx("div",{className:"muted",children:"(先选项目)"})}function Zg(){return c.jsx(Ft,{id:"nav-automations",title:"自动化",children:c.jsx(Lg,{})})}function Kg(){const i=Lt();return c.jsxs(Ft,{id:"nav-triage",title:"分诊收件箱",children:[c.jsx(At,{children:c.jsx("button",{onClick:i.refreshTriage,children:"刷新分诊"})}),c.jsx(Vg,{})]})}const ho=["pending","in_progress","blocked","completed","cancelled"],wc={pending:"待办",in_progress:"进行中",blocked:"受阻",completed:"已完成",cancelled:"已取消"},Jg=["low","medium","high"],Zh={low:"低",medium:"中",high:"高"};function Fg(i){return i?new Date(i*1e3).toLocaleString():""}function Wg(){const i=Lt(),[r,h]=d.useState([]),[f,y]=d.useState({}),[C,A]=d.useState(0),[S,_]=d.useState(""),[M,Y]=d.useState(""),[x,B]=d.useState(""),[V,et]=d.useState(""),[ft,F]=d.useState(""),[yt,_t]=d.useState(""),[kt,Q]=d.useState("medium"),[dt,R]=d.useState(""),[X,lt]=d.useState(""),pt=d.useCallback(async()=>{if(!i.projectId){h([]),y({}),A(0);return}try{let k=W.projectTodos(i.projectId);const ut=new URLSearchParams;x&&ut.set("status",x),V.trim()&&ut.set("q",V.trim());const U=ut.toString();U&&(k+="?"+U);const G=await $(k);h(G.todos||[]),y(G.counts||{}),A(G.total||0),Y("")}catch(k){Y("待办加载失败:"+((k==null?void 0:k.message)||String(k)))}},[i.projectId,x,V]);d.useEffect(()=>{pt()},[pt]);const Et=async()=>{if(!i.projectId){_("先选项目");return}if(!ft.trim()){_("标题必填");return}_("");try{const k={title:ft.trim(),description:yt,priority:kt};dt.trim()&&(k.task_id=dt.trim()),X&&(k.due_at=Math.floor(new Date(X).getTime()/1e3)),await $(W.projectTodos(i.projectId),"POST",k),F(""),_t(""),R(""),lt(""),_("已创建"),await pt()}catch(k){_("创建失败:"+((k==null?void 0:k.message)||String(k)))}},mt=async(k,ut)=>{if(i.projectId)try{await $(W.projectTodo(i.projectId,k.id),"PATCH",ut),await pt()}catch(U){Y("待办更新失败:"+((U==null?void 0:U.message)||String(U)))}},Rt=async k=>{if(i.projectId&&window.confirm("删除待办“"+k.title+"”?删除后不可恢复(取消请改状态为已取消)。"))try{await $(W.projectTodo(i.projectId,k.id),"DELETE"),await pt()}catch(ut){Y("待办删除失败:"+((ut==null?void 0:ut.message)||String(ut)))}};return c.jsxs(Ft,{id:"nav-todos",title:"项目待办",children:[c.jsx("div",{className:"muted",children:i.projectId?"共 "+C+" 项 | "+ho.map(k=>wc[k]+" "+(f[k]||0)).join(" | "):"先选项目"}),M?c.jsx("div",{className:"err",children:M}):null,c.jsxs(At,{children:[c.jsxs("select",{"aria-label":"状态筛选",value:x,onChange:k=>B(k.target.value),children:[c.jsx("option",{value:"",children:"状态:全部"}),ho.map(k=>c.jsx("option",{value:k,children:wc[k]},k))]}),c.jsx("input",{type:"text",placeholder:"搜索标题/说明",value:V,onChange:k=>et(k.target.value)}),c.jsx("button",{onClick:()=>void pt(),children:"刷新"})]}),c.jsx("input",{type:"text",placeholder:"待办标题(必填)",style:{width:"100%"},value:ft,onChange:k=>F(k.target.value)}),c.jsx("textarea",{placeholder:"说明(可选)",value:yt,onChange:k=>_t(k.target.value)}),c.jsxs(At,{children:[c.jsx("select",{"aria-label":"优先级",value:kt,onChange:k=>Q(k.target.value),children:Jg.map(k=>c.jsxs("option",{value:k,children:["优先级:",Zh[k]]},k))}),c.jsx("input",{type:"text",placeholder:"关联任务 id(可选)",value:dt,onChange:k=>R(k.target.value)}),c.jsx("input",{type:"datetime-local","aria-label":"截止时间",value:X,onChange:k=>lt(k.target.value)}),c.jsx("button",{className:"primary",onClick:()=>void Et(),children:"新建待办"}),c.jsx("span",{className:"muted",children:S})]}),c.jsx(ol,{empty:i.projectId?"(暂无待办)":"(先选项目)",items:r.map(k=>c.jsxs("span",{className:"row-main",children:[c.jsx("b",{children:k.title})," | ",c.jsx("span",{className:"st-"+k.status,children:wc[k.status]||k.status})," | 优先级 "+(Zh[k.priority]||k.priority),k.task_id?" | 任务 "+xe(k.task_id):"",k.due_at?" | 截止 "+Fg(k.due_at):"",k.completed_at?" | 完成于 "+new Date(k.completed_at*1e3).toLocaleString():"",k.description?c.jsxs(c.Fragment,{children:[c.jsx("br",{}),c.jsx("span",{className:"muted",children:k.description})]}):null,c.jsx("br",{}),c.jsx("select",{"aria-label":"改状态",value:k.status,onChange:ut=>void mt(k,{status:ut.target.value}),children:ho.map(ut=>c.jsx("option",{value:ut,children:wc[ut]},ut))})," ",c.jsx("button",{onClick:()=>void mt(k,{status:"completed"}),children:"完成"})," ",c.jsx("button",{onClick:()=>void Rt(k),children:"删除"})]},k.id))}),c.jsx("div",{className:"muted",children:"状态与 Muse 待办同款五态;完成时服务端记完成时间,改回其它状态时清掉;已取消是软关闭,删除才是硬删除。"})]})}const So=[["tasks","任务工作台","任务"],["todos","项目待办","任务"],["resources","环境与 Workers","管理"],["automation","技能与自动化","管理"],["admin","系统与 Key","管理"]],$g=Object.fromEntries(So.map(([i,r])=>[i,r]));function Kh(){const i=window.location.hash.replace("#view-","");return So.some(([r])=>r===i)?i:"tasks"}function Ig({view:i,setView:r}){return c.jsxs("aside",{className:"shell-side",children:[c.jsx("div",{className:"shell-brand",children:"Codex 命令台"}),c.jsx("nav",{className:"shell-nav","aria-label":"导航",children:["任务","管理"].map(h=>c.jsxs("div",{className:"shell-nav-group",children:[c.jsx("div",{className:"shell-nav-group-label",children:h}),So.filter(([,,f])=>f===h).map(([f,y])=>c.jsx("button",{type:"button",className:i===f?"active":"",onClick:()=>r(f),children:y},f))]},h))}),c.jsx("div",{id:"nav-projects",className:"shell-project-nav",children:c.jsx(wg,{})}),c.jsxs("div",{className:"shell-stats",children:[c.jsx("div",{className:"shell-stats-label",children:"概览"}),c.jsx(og,{})]})]})}function Pg(){const i=Lt();return c.jsx("span",{className:i.keySaved?"dash-status ok":"dash-status off",children:i.keySaved?"● 已连接":"○ 未连接"})}function tp(){const i=rg();ig(S=>i.refreshAll(S),1e4),cg(()=>i.refreshSlow(),6e4);const[r,h]=d.useState(()=>Kh()),[f,y]=d.useState(!0),C=S=>{h(S);try{window.history.replaceState(null,"","#view-"+S)}catch{}};d.useEffect(()=>{const S=()=>h(Kh());return window.addEventListener("hashchange",S),()=>window.removeEventListener("hashchange",S)},[]);const A=()=>{C("tasks"),y(!0),setTimeout(()=>{var S;return(S=document.getElementById("sec-dispatch"))==null?void 0:S.scrollIntoView({behavior:"smooth"})},0)};return c.jsx(Fh.Provider,{value:i,children:c.jsxs("div",{className:"shell",children:[c.jsx(Ig,{view:r,setView:C}),c.jsxs("div",{className:"shell-main",children:[c.jsxs("header",{className:"shell-header",children:[c.jsx("h1",{children:$g[r]}),c.jsx(Pg,{}),c.jsx("span",{className:"muted shell-hide-sm",children:i.healthText}),c.jsx("span",{className:"muted shell-hide-sm",children:i.quotaText}),c.jsxs("span",{className:"muted shell-stamp",children:["自动刷新 · 每 10 秒 · 已刷新 ",i.refreshStamp]})]}),r==="tasks"?c.jsxs("div",{className:"workspace",children:[c.jsxs("section",{className:"workspace-rail","aria-label":"任务列表",children:[c.jsx("h2",{children:"任务列表"}),c.jsx(mg,{onNew:A})]}),c.jsxs("section",{className:"workspace-center",children:[c.jsx("div",{className:"composer-toggle",children:c.jsx("button",{type:"button",onClick:()=>y(!f),children:f?"收起新建任务":"新建任务"})}),f?c.jsx("section",{id:"sec-dispatch",children:c.jsx(fg,{})}):null,c.jsxs("section",{className:"card workspace-conv",children:[c.jsx("h2",{children:"对话"}),c.jsx(Sg,{})]})]}),c.jsx("section",{className:"workspace-inspector","aria-label":"任务详情",children:c.jsx(zg,{})})]}):c.jsx("main",{className:"page",children:r==="todos"?c.jsx(c.Fragment,{children:c.jsx(Wg,{})}):r==="resources"?c.jsxs(c.Fragment,{children:[c.jsx(kg,{}),c.jsx(Hg,{}),c.jsx(Bg,{}),c.jsx(qg,{})]}):r==="automation"?c.jsxs(c.Fragment,{children:[c.jsx(Yg,{}),c.jsx(Gg,{}),c.jsx(Zg,{}),c.jsx(Kg,{})]}):c.jsxs(c.Fragment,{children:[c.jsx(Dg,{}),c.jsx(Rg,{})]})})]})]})})}Jy.createRoot(document.getElementById("root")).render(c.jsx(Yy.StrictMode,{children:c.jsx(tp,{})}));