@tea-agent/loop-agent 0.26.5-beta.2 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +29 -0
- package/README.md +13 -23
- package/dist/application/dag/args.js +7 -7
- package/dist/application/dag/generate-task-dag.js +2 -2
- package/dist/application/dag/run-dag.js +3 -4
- package/dist/application/dag/validate-dag.js +1 -1
- package/dist/application/task-lifecycle/advance.js +845 -0
- package/dist/application/task-lifecycle/gates.js +80 -0
- package/dist/application/task-lifecycle/index.js +7 -0
- package/dist/application/task-lifecycle/observe.js +395 -0
- package/dist/application/task-lifecycle/plan-transitions.js +224 -0
- package/dist/application/task-lifecycle/recommendations.js +180 -0
- package/dist/application/task-lifecycle/record.js +73 -0
- package/dist/application/task-lifecycle/types.js +1 -0
- package/dist/cli/command-definitions.js +14 -111
- package/dist/cli/help.js +6 -7
- package/dist/cli/program.js +26 -90
- package/dist/cli/update/policy.js +0 -1
- package/dist/commands/dag-final-verification.js +1 -1
- package/dist/commands/dag-init-hybrid.js +1 -1
- package/dist/commands/delegate.js +2 -2
- package/dist/commands/init.js +21 -19
- package/dist/commands/run-dag-progress.js +1 -1
- package/dist/commands/status.js +18 -17
- package/dist/commands/study-init.js +2 -2
- package/dist/commands/task-advance.js +335 -0
- package/dist/commands/task-contract.js +3 -5
- package/dist/commands/task-source-prepare.js +9 -4
- package/dist/commands/task-status.js +133 -0
- package/dist/governance/manifest-types.js +2 -2
- package/dist/shared/operator/capabilities.js +1358 -243
- package/dist/task/contract/adopt.js +1 -1
- package/dist/task/contract/apply.js +1 -1
- package/dist/task/contract/import-revision.js +1 -1
- package/dist/task/contract/recover.js +2 -2
- package/dist/task/read-model.js +18 -23
- package/dist/task/runtime.js +1 -1
- package/dist/task/source-prepare/completeness.js +1 -1
- package/dist/task/source-prepare/parse-intent.js +6 -1
- package/dist/task/source-prepare/prepare.js +23 -20
- package/dist/worker/console/operator-actions.js +288 -95
- package/dist/worker/console/recovery-cta.js +4 -4
- package/dist/worker/console/static/assets/{index-CSRIhuzh.js → index-CNO7n6qB.js} +1 -1
- package/dist/worker/console/static/index.html +1 -1
- package/dist/worker/materialize/harness-task-materializer.js +6 -5
- package/dist/worker/run-task/run-task.js +204 -112
- package/dist/worker/runner/run-ready.js +1 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +6 -72
- package/dist/workflows/dag/frontend-prewrite-gate.js +4 -17
- package/dist/workflows/dag/init-hybrid.js +11 -66
- package/docs/templates/evaluation/agents-map-slim-v1.md +1 -1
- package/docs/templates/evaluation/agents-map-verbose-v0.md +3 -3
- package/docs/templates/harness.schema.json +2 -2
- package/docs/templates/init-managed-agents.md +13 -16
- package/docs/templates/production-readiness-checklist.md +3 -3
- package/harness.json +4 -4
- package/package.json +1 -1
- package/scripts/kb-bootstrap-init-skeleton.sh +2 -1
- package/scripts/kb-graph-incremental-prepare.mjs +2 -2
- package/skills/loop-agent/SKILL.md +18 -13
- package/skills/loop-agent/references/README.md +1 -1
- package/skills/loop-agent/references/command-reference.md +55 -84
- package/skills/loop-agent/references/harness-policy.md +19 -23
- package/skills/loop-agent/references/hybrid-dag.md +31 -33
- package/skills/loop-agent/references/long-running-loop.md +2 -2
- package/skills/loop-agent/references/one-shot-runs.md +4 -5
- package/skills/loop-agent/references/orchestrator-and-interventions.md +3 -3
- package/skills/loop-agent/references/post-implementation-and-patterns.md +4 -4
- package/skills/loop-agent/references/source-and-plan-practice.md +45 -51
- package/skills/loop-agent/references/task-workflow.md +14 -15
|
@@ -31,7 +31,7 @@ const CTA = {
|
|
|
31
31
|
label: "恢复运行",
|
|
32
32
|
lane: "dag",
|
|
33
33
|
guide: "仅当运行可安全 resume 时使用(经 CLI)",
|
|
34
|
-
commandHint: "loop-agent
|
|
34
|
+
commandHint: "loop-agent task advance <task-id> --json",
|
|
35
35
|
},
|
|
36
36
|
reconcile: {
|
|
37
37
|
id: "reconcile",
|
|
@@ -45,8 +45,8 @@ const CTA = {
|
|
|
45
45
|
id: "regenerate",
|
|
46
46
|
label: "重新生成契约/计划",
|
|
47
47
|
lane: "dag",
|
|
48
|
-
guide: "契约/计划过期时:回任务页或经 CLI 重新
|
|
49
|
-
commandHint: "loop-agent
|
|
48
|
+
guide: "契约/计划过期时:回任务页或经 CLI 重新 task advance(本页仅提示)",
|
|
49
|
+
commandHint: "loop-agent task advance <task-id> --json",
|
|
50
50
|
},
|
|
51
51
|
observeLink: {
|
|
52
52
|
id: "observeLink",
|
|
@@ -72,7 +72,7 @@ const CTA = {
|
|
|
72
72
|
action: "standaloneTaskRerun",
|
|
73
73
|
lane: "dag",
|
|
74
74
|
guide: "整单重跑:失败类默认首选;需确认原因后提交",
|
|
75
|
-
commandHint: "loop-agent
|
|
75
|
+
commandHint: "loop-agent task advance <task-id> --json",
|
|
76
76
|
},
|
|
77
77
|
workerTaskRetry: {
|
|
78
78
|
id: "workerTaskRetry",
|
|
@@ -16,7 +16,7 @@ Error generating stack: `+l.message+`
|
|
|
16
16
|
|
|
17
17
|
`);J=Se.pop()??"";for(const pt of Se){const Dt=ll(pt,U,{targetSessionId:S.sessionId});Dt&&(An.current=Dt)}}}catch(H){H?.name==="AbortError"||se.current?.sessionId===S.sessionId&&Z(H instanceof Error?H.message:String(H))}finally{se.current?.sessionId===S.sessionId&&(We.current=!1,Pt(!1),Pn(null),Zt.current=null,tl.current=null,In([])),hl.current.delete(S.sessionId),ba.current.delete(S.sessionId)}},[r,wt]),Mn=h.useCallback(()=>{Zt.current?.abort(),We.current=!1,Pt(!1),Pn(null)},[]),kn=h.useCallback(async(f,S)=>{for(;!S.aborted;)try{const A={Accept:"text/event-stream"},U=An.current;U&&(A["Last-Event-ID"]=U);const W=await fetch(`${r}/api/operator/v1/chat/sessions/${f}/events`,{headers:A,credentials:"include",signal:S});if(!W.ok||!W.body){if(W.status===404)return;await Nr(2e3,S);continue}const H=W.body.getReader(),qe=new TextDecoder;let ot="",J=tl.current;for(J||(J=cs("a"),tl.current=J);;){const{done:ge,value:vt}=await H.read();if(ge)break;ot+=qe.decode(vt,{stream:!0});const Se=ot.split(`
|
|
18
18
|
|
|
19
|
-
`);ot=Se.pop()??"";for(const pt of Se){const Dt=ll(pt,J,{replay:!0,targetSessionId:f});Dt&&(An.current=Dt)}}await Nr(1e3,S)}catch{if(S.aborted)return;await Nr(2e3,S)}},[r,ll]);h.useEffect(()=>{if(!D||Xt&&hl.current.has(D.sessionId))return;const f=new AbortController;return pl.current=f,kn(D.sessionId,f.signal),()=>{f.abort(),pl.current===f&&(pl.current=null)}},[D,Xt,kn]);const xa=h.useCallback(async()=>{const f=se.current;if(!f)return;const S=window.prompt("Task ID(例如 2026-07-26-my-task)")?.trim();if(!S)return;const A=await fetch(`${r}/api/operator/v1/chat/sessions/${f.sessionId}/interviews`,{method:"POST",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},credentials:"include",body:JSON.stringify({taskId:S})}),U=await A.json();if(!A.ok){Z(U.error?.message??`HTTP ${A.status}`);return}G({interviewSessionId:U.interview?.sessionId,taskId:S,state:U.interview?.state,question:U.question,draft:U.draft?.draft,draftSha256:U.draft?.draftSha256,assessment:U.assessment})},[r]),wn=h.useCallback(async f=>{const S=se.current;if(!S||!T?.interviewSessionId||!T.question)return;const A=await fetch(`${r}/api/operator/v1/chat/sessions/${S.sessionId}/interviews/${T.interviewSessionId}/answers`,{method:"POST",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},credentials:"include",body:JSON.stringify({questionId:T.question.id,response:f,...f==="override"?{text:Jn}:{}})}),U=await A.json();if(!A.ok){Z(U.error?.message??`HTTP ${A.status}`);return}G(W=>({...W??{},state:U.interview?.state,question:U.question,draft:U.draft?.draft,draftSha256:U.draft?.draftSha256,assessment:U.assessment,taskKindRecommendation:U.taskKindRecommendation??W?.taskKindRecommendation})),Ft("")},[r,T,Jn]),Al=h.useCallback(async()=>{const f=se.current;if(!f||!T?.interviewSessionId||!T.taskKindRecommendation)return;const S=await fetch(`${r}/api/operator/v1/chat/sessions/${f.sessionId}/interviews/${T.interviewSessionId}/task-kind/confirm`,{method:"POST",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},credentials:"include",body:JSON.stringify({taskKind:T.taskKindRecommendation})}),A=await S.json();if(!S.ok){Z(A.error?.message??`HTTP ${S.status}`);return}G(U=>({...U??{},confirmedTaskKind:U?.taskKindRecommendation,taskKindRecommendation:void 0,draft:A.draft?.draft,draftSha256:A.draft?.draftSha256,assessment:A.assessment}))},[r,T]);h.useEffect(()=>{D?.sessionId&&St(D.sessionId)},[D?.sessionId,St]),h.useEffect(()=>{const f=D?.sessionId;if(!f)return;const S=window.setTimeout(()=>{St(f,{background:!0})},350);return()=>window.clearTimeout(S)},[D?.sessionId,ht,xe,T,St]);const al=h.useCallback(f=>{const S=Np(f);Yt(""),$e(!1),S&&(S.action==="focus:interview"?xa():S.action==="show-help"?Z(`可用 shortcuts:${Or.map(A=>A.command).join("、")}`):S.action.startsWith("focus-panel:")?Vl.current?.scrollIntoView({behavior:"smooth",block:"nearest"}):Z(`未知 shortcut:${S.command}`))},[xa]),_t=h.useMemo(()=>Ke.startsWith("/")?Or.filter(f=>f.command.startsWith(Ke.trim().split(/\s+/,1)[0].toLowerCase())):[],[Ke]),Un=h.useCallback(f=>{if(Ge&&_t.length>0&&!f.nativeEvent.isComposing){if(f.key==="ArrowDown"||f.key==="ArrowUp"){f.preventDefault(),Kn(U=>(U+(f.key==="ArrowDown"?1:_t.length-1))%_t.length);return}if(f.key==="Escape"){f.preventDefault(),$e(!1);return}if(f.key==="Enter"){f.preventDefault(),al(_t[Gt]?.command??_t[0].command);return}}const S=Date.now()-Le.current<100,A=nl.current||f.nativeEvent.isComposing;if(f.key==="Enter"&&!f.shiftKey&&(A||S)){S&&f.preventDefault();return}if(f.key==="Enter"&&!f.shiftKey){f.preventDefault(),_n(Ke);return}},[Ke,_n,Ge,_t,Gt,al]),jt=h.useMemo(()=>be.filter(f=>f.role!=="system"||ga).slice(-z),[be,ga,z]);h.useEffect(()=>{const f=()=>{document.hidden||Ce(0)};return document.addEventListener("visibilitychange",f),()=>document.removeEventListener("visibilitychange",f)},[]);const it=h.useCallback(async()=>{const f=se.current;if(!(!f||We.current))try{const S=await fetch(`${r}/api/operator/v1/chat/sessions/${encodeURIComponent(f.sessionId)}/compact`,{method:"POST",credentials:"include",headers:{"x-loop-console-confirmation":$n()}}),A=await S.json().catch(()=>({}));if(!S.ok){Z(A.error?.message??"上下文压缩失败");return}Z(null)}catch(S){Z(S instanceof Error?S.message:"上下文压缩失败")}},[r]),an=h.useMemo(()=>{if(Pe.length===0)return null;const f=Pe.filter(H=>H.status==="running"),S=Pe.filter(H=>H.status==="error"),A=f[f.length-1];let U="完成",W="ok";return S.length>0?(U=`${S.length} 出错`,W="error"):f.length>0&&(U=A?`正在调用 ${A.toolName}`:"运行中",W="running"),{count:Pe.length,statusLabel:U,statusKind:W}},[Pe]),yn=D?.model??Fn?.model,sn=yn?Ha(yn.provider,yn.modelId):"",Jl=D?.thinkingLevel??Fn?.thinkingLevel??"",il=!sn||Wn.some(f=>Ha(f.provider,f.id)===sn),sl=h.useMemo(()=>{if(!b)return null;const f=(b.tools??[]).map(A=>({toolId:A.toolId,action:A.action,description:A.description,kind:A.kind??"read",cli:A.cli})),S=[...zp];return{explore:S,operator:f,total:S.length+f.length}},[b]),Mt=u.readiness==="setup-required"?"⚠ Pi 未就绪(setup-required):Chat 需要先完成 Pi 认证 / 模型配置。":u.readiness==="degraded"?"⚠ Pi 降级(degraded):可继续对话,但部分能力不可用。":null,Rl=async(f,S)=>{if(!(await fetch(`${r}/api/operator/v1/chat/sessions/${encodeURIComponent(f)}`,{method:"PATCH",credentials:"include",headers:{"content-type":"application/json","x-loop-console-confirmation":$n()},body:JSON.stringify(S)})).ok){Z("会话更新失败");return}await tn(),S.state==="archived"&&se.current?.sessionId===f&&(se.current=null,Q(null),window.localStorage.removeItem(fl))},pe=s.jsx(mp,{origin:r,open:K,activeSessionId:D?.sessionId,sessions:Y,tree:ee,expanded:le,treeError:nt,onToggleOpen:()=>X(f=>!f),onCreate:()=>{ln()},onActivate:f=>{It(f)},onRename:(f,S)=>{Rl(f,{title:S})},onSetState:(f,S)=>{Rl(f,{state:S})},onDelete:f=>{Cl(f)},onRefreshTree:()=>{zn()},onToggleDir:f=>{ce(S=>{const A=new Set(S);return A.has(f)?A.delete(f):A.add(f),A}),ee[f]||zn(f)},onInsert:f=>Yt(S=>`${S}${S&&!S.endsWith(" ")?" ":""}@${f} `),onPreview:f=>{lt(f)}}),Vt=jt.length>0||ht.length>0||xe.length>0||Ie.length>0||!!T;return s.jsxs("div",{className:"oc-shell",children:[d?null:s.jsxs("div",{className:"oc-banner",children:[s.jsxs("span",{className:"oc-banner-title",children:[s.jsx("span",{className:"oc-banner-dot","aria-hidden":"true"}),"对话"]}),s.jsxs("span",{className:"oc-banner-body",children:["用自然语言编排 loop-agent / agent-worker 的",s.jsx("strong",{children:"全部能力"}),"。这是 ",s.jsx("strong",{children:"Operator"})," ","面:可通过 safe-read/safe-grep/git-status/git-diff/find/ls 探查仓库、调用受策略约束的 operator action;",s.jsx("strong",{children:"无 bash 或直接写文件工具"}),"(业务写入仍应经受治理 DAG 的 implement-pi / repair-pi)。"]})]}),Mt&&s.jsx("div",{className:"oc-alert oc-alert-warning",children:Mt}),mn&&s.jsxs("div",{className:"oc-alert oc-alert-error",children:[s.jsx("strong",{children:"出错了:"}),mn]}),D?s.jsxs("div",{className:`oc-workspace${hn?" has-process":""}`,children:[pe,s.jsxs("div",{className:`oc-main${Vt?"":" is-landing"}`,children:[s.jsx(vp,{previews:we,activePath:bt,loading:ye,onActivate:ct,onClose:f=>{Ue(S=>{const A=S.filter(U=>U.path!==f);return D&&window.localStorage.setItem(`${fl}.previews.${D.sessionId}`,JSON.stringify(A.map(U=>U.path))),A}),ct(S=>S===f?we.find(A=>A.path!==f)?.path??null:S)}}),s.jsxs("div",{ref:en,className:`oc-messages${Vt?" has-thread":" is-empty"}`,onScroll:nn,children:[Vt?null:s.jsx(Em,{mode:"empty-session",readiness:u.readiness,disabled:Xt,onSuggest:f=>{_n(f)}}),Vt&&be.length>jt.length&&s.jsx("button",{type:"button",className:"btn btn-ghost oc-load-history",onClick:()=>V(f=>f+50),children:"加载更早消息"}),Vt&&jt.map((f,S)=>{const A=jt[S-1],U=!A||Tr(A.createdAt)!==Tr(f.createdAt);return s.jsxs("div",{children:[U&&s.jsx("div",{className:"oc-day-sep",children:Tr(f.createdAt)}),f.role==="system"?s.jsx("div",{className:"oc-row is-tool",children:s.jsx("div",{className:"oc-bubble oc-bubble-tool",children:f.text})}):s.jsx(Lp,{message:f,streaming:Xt,activeAssistantId:Kl})]},`row-${f.id}`)}),T&&s.jsxs("section",{className:"oc-draft-card","aria-label":"Requirement Interview",children:[s.jsxs("header",{children:[s.jsx("strong",{children:"Requirement Interview"}),s.jsx("span",{children:T.state})]}),T.question&&s.jsxs("div",{className:"oc-interview-bubble",children:[s.jsx("strong",{children:T.question.text}),s.jsxs("p",{children:["建议:",T.question.recommendation]}),s.jsx("textarea",{value:Jn,onChange:f=>Ft(f.target.value),placeholder:"输入答案"}),s.jsxs("div",{children:[s.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>{wn("override")},disabled:!Jn.trim(),children:"提交答案"}),s.jsx("button",{className:"btn btn-ghost",type:"button",onClick:()=>{wn("accept-recommendation")},children:"接受建议"})]})]}),T.draft&&s.jsxs("details",{open:!0,children:[s.jsxs("summary",{children:["TaskContractDraftV1 ·"," ",T.draftSha256?.slice(0,12)]}),s.jsx("pre",{children:JSON.stringify(T.draft,null,2)})]}),T.assessment&&s.jsxs("div",{className:`oc-assessment${T.assessment.fresh?" is-fresh":""}`,children:[s.jsxs("strong",{children:["完整性:",T.assessment.outcome]}),(T.assessment.missingFields??[]).length>0&&s.jsxs("p",{children:["缺失:",T.assessment.missingFields?.join("、")]})]}),T.taskKindRecommendation&&s.jsxs("div",{className:"oc-task-kind-card",children:[s.jsx("span",{children:"taskKind 建议"}),s.jsx("strong",{children:T.taskKindRecommendation}),s.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>{Al()},children:"由我确认"}),s.jsx("small",{children:"模型不能代替人类确认。"})]}),T.confirmedTaskKind&&s.jsxs("div",{className:"oc-task-kind-card is-confirmed",children:["已由人类确认:",s.jsx("strong",{children:T.confirmedTaskKind})]})]}),xe.map(f=>s.jsx(wp,{card:f,origin:r,sessionId:D.sessionId},f.cardId)),ht.map(f=>s.jsx(Up,{operation:f,origin:r,onNavigateWorkspace:u.onNavigateWorkspace},f.operationId)),Ie.map(f=>s.jsx(Hp,{artifact:f},f.artifactId)),s.jsx("div",{ref:El})]}),s.jsx("div",{className:"oc-composer",children:s.jsxs("div",{className:"oc-composer-inner",children:[jl.length>0&&s.jsx("div",{className:"oc-file-palette",role:"listbox","aria-label":"Repository files",children:jl.map(f=>s.jsx("button",{type:"button",role:"option",onMouseDown:S=>S.preventDefault(),onClick:()=>On(f),children:s.jsxs("code",{children:["@",f]})},f))}),wt.length>0&&s.jsx("div",{className:"oc-attachment-list",children:wt.map(f=>s.jsxs("span",{children:[f.name,s.jsx("button",{type:"button","aria-label":`移除 ${f.name}`,onClick:()=>In(S=>S.filter(A=>A!==f)),children:"×"})]},f.name))}),s.jsxs("div",{className:"oc-composer-toolbar",children:[s.jsxs("label",{className:"oc-attach-button",children:["添加图片",s.jsx("input",{type:"file",accept:"image/png,image/jpeg,image/gif,image/webp",multiple:!0,hidden:!0,onChange:f=>{const S=Array.from(f.target.files??[]).slice(0,4);for(const A of S){if(!A.type.startsWith("image/")||A.size>5*1024*1024){Z("图片仅支持 PNG/JPEG/GIF/WebP,单张不超过 5 MiB");continue}const U=new FileReader;U.onload=()=>{const W=String(U.result??""),H=W.slice(W.indexOf(",")+1);In(qe=>[...qe,{name:A.name,type:"image",mimeType:A.type,data:H}].slice(0,4))},U.readAsDataURL(A)}f.target.value=""}})]}),s.jsxs("span",{className:"oc-composer-hint",children:[s.jsx("span",{className:"oc-kbd",children:"Enter"})," 发送"]}),s.jsxs("span",{className:"oc-composer-hint",children:[s.jsx("span",{className:"oc-kbd",children:"Shift"}),"+",s.jsx("span",{className:"oc-kbd",children:"Enter"})," 换行"]})]}),Ge&&_t.length>0&&s.jsx("div",{className:"oc-shortcut-palette",role:"listbox","aria-label":"Chat shortcuts",children:_t.map((f,S)=>s.jsxs("button",{type:"button",role:"option","aria-selected":S===Gt,className:S===Gt?"is-active":"",onMouseDown:A=>A.preventDefault(),onClick:()=>al(f.command),children:[s.jsx("code",{children:f.command}),s.jsxs("span",{children:[s.jsx("strong",{children:f.label}),s.jsx("small",{children:f.description})]})]},f.command))}),s.jsxs("div",{className:`oc-composer-shell${Xt?" is-busy":""}`,children:[s.jsx("textarea",{ref:el,className:"oc-textarea",value:Ke,rows:3,placeholder:Xt?"正在生成回复…(可直接发起新问题)":Vt?"输入消息… Enter 发送 · Shift+Enter 换行":"描述目标,或点选上方建议开始…",onChange:f=>{Yt(f.target.value),$e(f.target.value.startsWith("/")),Kn(0)},onKeyDown:Un,onCompositionStart:()=>{nl.current=!0},onCompositionEnd:()=>{nl.current=!1,Le.current=Date.now()},disabled:Xt}),Xt?s.jsx("button",{type:"button",className:"oc-stop",title:"停止生成","aria-label":"停止生成",onClick:Mn,children:s.jsx(Zp,{})}):s.jsx("button",{type:"button",className:"oc-send",title:"发送","aria-label":"发送",onClick:()=>{_n(Ke)},disabled:!Ke.trim()&&wt.length===0,children:s.jsx(Qp,{})})]}),s.jsxs("div",{className:"oc-runtime-controls",children:[s.jsxs("select",{className:"oc-model-select","aria-label":"Model",value:sn,onChange:f=>{const S=Wn.find(A=>Ha(A.provider,A.id)===f.target.value);S&&rt({provider:S.provider,modelId:S.id})},children:[s.jsx("option",{value:"",children:"选择模型"}),yn&&!il?s.jsx("option",{value:sn,children:sn}):null,Wn.filter(f=>f.hasCredentials!==!1).map(f=>s.jsx("option",{value:Ha(f.provider,f.id),children:Ha(f.provider,f.id)},Ha(f.provider,f.id)))]}),s.jsxs("select",{className:"oc-thinking-select","aria-label":"Thinking level",value:Jl,onChange:f=>{rt({thinkingLevel:f.target.value})},children:[s.jsx("option",{value:"",children:"思考等级"}),Cn.map(f=>s.jsx("option",{value:f,children:f},f))]}),s.jsxs("span",{className:"oc-usage",children:[Xt?"运行中":"空闲",te>0?` · ${te} 未读`:""," ·"," ",fn.inputTokens," in · ",fn.outputTokens," out ·"," ",fn.totalTokens," tokens ·"," ",fn.cost===void 0?"—":`$${fn.cost.toFixed(4)}`]}),s.jsx("button",{type:"button",className:"btn btn-ghost",onClick:()=>{it()},disabled:Xt||!Vt,title:Vt?Xt?"生成中,暂不可压缩":"压缩上下文,释放 token":"先进行对话后再压缩上下文",children:"Compact"}),sl?s.jsxs("div",{className:"oc-tools-menu oc-tools-menu--composer",ref:pn,children:[s.jsxs("button",{type:"button",className:`oc-cap-chip oc-tools-toggle${Jt?" is-active":""}`,"aria-pressed":Jt,"aria-expanded":Jt,"aria-controls":"oc-tools-catalog",onClick:()=>{He(f=>!f),Jt||Ae(!1)},children:[sl.total," 工具"]}),Jt&&s.jsxs("div",{id:"oc-tools-catalog",className:"oc-tools-catalog",role:"dialog","aria-label":"可用工具列表",children:[s.jsxs("header",{className:"oc-tools-catalog-head",children:[s.jsx("strong",{children:"可用工具"}),s.jsxs("span",{className:"oc-tools-catalog-meta",children:[sl.total," 个 · 点选了解简介"]}),s.jsx("button",{type:"button",className:"btn btn-ghost oc-tools-catalog-close","aria-label":"关闭工具列表",onClick:()=>He(!1),children:"关闭"})]}),s.jsxs("div",{className:"oc-tools-catalog-body",children:[sl.explore.length>0&&s.jsxs("section",{className:"oc-tools-group",children:[s.jsx("h4",{className:"oc-tools-group-title",children:"仓库探查"}),s.jsx("ul",{className:"oc-tools-list",children:sl.explore.map(f=>s.jsxs("li",{className:"oc-tools-item",children:[s.jsxs("div",{className:"oc-tools-item-head",children:[s.jsx("code",{className:"oc-tools-name",children:f.toolId}),s.jsx("span",{className:"oc-tools-kind is-explore",children:Tm(f.kind)})]}),s.jsx("p",{className:"oc-tools-desc",children:f.description})]},f.toolId))})]}),s.jsxs("section",{className:"oc-tools-group",children:[s.jsx("h4",{className:"oc-tools-group-title",children:"Operator 动作"}),s.jsx("ul",{className:"oc-tools-list",children:sl.operator.map(f=>s.jsxs("li",{className:"oc-tools-item",children:[s.jsxs("div",{className:"oc-tools-item-head",children:[s.jsx("code",{className:"oc-tools-name",children:f.toolId}),s.jsx("span",{className:`oc-tools-kind is-${f.kind??"read"}`,children:Tm(f.kind)})]}),s.jsx("p",{className:"oc-tools-desc",children:f.description}),f.cli&&s.jsxs("p",{className:"oc-tools-cli",children:["CLI: ",s.jsx("code",{children:f.cli})]})]},f.toolId))})]})]})]})]}):null,an&&s.jsxs("button",{type:"button",className:`oc-process-summary is-${an.statusKind}${hn?" is-open":""}`,"aria-pressed":hn,"aria-controls":"oc-process-panel",onClick:()=>{Ae(f=>!f),hn||He(!1)},children:["执行过程 · ",an.count," 工具 ·"," ",an.statusLabel]}),Fn&&s.jsx(qp,{ref:he,open:vn,onToggle:()=>xt(f=>!f),onClose:()=>xt(!1),context:Fn})]})]})})]}),hn&&s.jsxs("aside",{id:"oc-process-panel",className:"oc-process","aria-label":"执行过程",children:[s.jsxs("header",{className:"oc-process-head",children:[s.jsxs("div",{className:"oc-process-title",children:[s.jsx("span",{className:"oc-process-title-mark","aria-hidden":"true"}),"执行过程",s.jsx("span",{className:"oc-process-count",children:Pe.length})]}),s.jsx("button",{type:"button",className:"btn btn-ghost oc-process-close","aria-label":"关闭执行过程",onClick:()=>Ae(!1),children:"关闭"})]}),s.jsx("div",{className:"oc-process-timeline",children:Pe.length===0?s.jsx("div",{className:"oc-process-empty",children:"本轮对话尚无工具调用。诊断细节会在这里按时间线展示。"}):Pe.map((f,S)=>s.jsxs("div",{className:`oc-process-item${S===0?" is-first":""}${S===Pe.length-1?" is-last":""}${f.status==="error"?" is-error":""}${f.status==="running"?" is-running":""}`,children:[s.jsx("div",{className:"oc-process-rail","aria-hidden":"true",children:s.jsx("span",{className:"oc-process-dot"})}),s.jsx("div",{className:"oc-process-time",children:km(f.createdAt)}),s.jsx("div",{className:"oc-process-body",children:s.jsx(Gp,{entry:f})})]},f.id))})]})]}):s.jsxs("div",{className:"oc-workspace",children:[pe,s.jsx("div",{className:"oc-main is-landing",children:s.jsx("div",{className:"oc-messages is-empty",children:s.jsx(Em,{mode:"no-session",readiness:u.readiness,onSuggest:async f=>{await ln()&&await _n(f)},onCreateSession:()=>{ln()}})})})]})]})}h.memo(h.forwardRef(function({context:r,loading:m},d){return s.jsxs("section",{ref:d,className:"oc-task-context","aria-label":"Task context",children:[s.jsxs("header",{children:[s.jsxs("div",{children:[s.jsx("small",{children:"Durable task context"}),s.jsx("strong",{children:r?.taskId??"当前任务"})]}),s.jsx("span",{children:m&&!r?"同步中…":r?.updatedAt?"已恢复":"等待事件"})]}),r?.taskId?s.jsxs("div",{className:"oc-task-context-grid",children:[s.jsxs("div",{children:[s.jsx("b",{children:"Draft"}),s.jsx("span",{children:r.draft?r.draft.draftSha256.slice(0,12):"未生成"})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Assessment"}),s.jsx("span",{children:r.assessment?`${r.assessment.outcome}${r.assessment.fresh?" · fresh":""}`:"未评估"})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Task kind"}),s.jsx("span",{children:r.taskKind?.value??r.draft?.taskKindRecommendation??"待确认"})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Contract"}),s.jsx("span",{children:r.contract?.confirmationState??"待准备"}),r.contract?.diffSummary&&s.jsx("small",{children:r.contract.diffSummary})]}),s.jsxs("div",{children:[s.jsx("b",{children:"DAG"}),s.jsx("span",{children:r.dag?.confirmationState??"待生成"}),r.dag?.spine&&s.jsx("small",{children:r.dag.spine.join(" → ")})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Operations"}),s.jsx("span",{children:r.operations.length?r.operations.map(b=>`${b.action}: ${b.state}`).join(" · "):"无"})]})]}):s.jsx("p",{className:"oc-task-context-empty",children:"Draft、assessment、Contract 与 DAG 状态会在此实时聚合。"})]})}));function wp({card:u,origin:r,sessionId:m}){const[d,b]=h.useState(!1),[C,D]=h.useState(),Q=async()=>{b(!0),D(void 0);try{const X=u.gateType==="dag-run"?u.state==="prepared"?"dag-confirm":"dag-run":u.gateType==="mutation"?"mutation-apply":"contract-apply",ee=u.gateType==="dag-run"?{confirmationId:u.confirmationId,...u.state==="prepared"?{humanGateToken:u.humanGateToken}:{}}:{receiptId:u.receiptId,humanGateToken:u.humanGateToken},B=await fetch(`${r}/api/operator/v1/chat/sessions/${encodeURIComponent(m)}/human-gate/${X}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},body:JSON.stringify(ee)}),le=await B.json();if(!B.ok)throw new Error(le.error?.message??`HTTP ${B.status}`)}catch(X){D(X instanceof Error?X.message:String(X))}finally{b(!1)}},Y=u.state==="prepared"||u.gateType==="dag-run"&&u.state==="confirmed",O=u.gateType==="contract-apply"?"Contract apply":u.gateType==="mutation"?"Mutation":"DAG run",K=u.gateType==="contract-apply"?"Apply":u.gateType==="mutation"?"Execute":u.state==="prepared"?"Confirm":"Run";return s.jsxs("section",{className:`oc-human-gate-card is-${u.state}`,"aria-label":`Human gate ${u.cardId}`,children:[s.jsxs("header",{children:[s.jsxs("div",{children:[s.jsx("small",{children:"HumanGateCard · 仅人类可确认"}),s.jsx("strong",{children:O})]}),s.jsx("span",{children:u.state})]}),u.contractDiffSummary&&s.jsx("p",{children:u.contractDiffSummary}),u.displayOnlyChallenges&&s.jsxs("div",{className:"oc-human-gate-challenges",children:[s.jsx("b",{children:"Challenge(仅展示,不是确认信号)"}),s.jsx("ul",{children:u.displayOnlyChallenges.map(X=>s.jsx("li",{children:X},X))})]}),u.dagSpine&&u.dagSpine.length>0&&s.jsxs("div",{children:[s.jsx("b",{children:"DAG spine"}),s.jsx("ol",{children:u.dagSpine.map(X=>s.jsx("li",{children:s.jsx("code",{children:X})},X))})]}),s.jsxs("footer",{children:[s.jsx("a",{href:u.inspectHref,children:"Inspect"}),s.jsx("button",{className:"btn btn-primary",type:"button",disabled:!Y||d,onClick:()=>{Q()},children:d?"提交中…":K})]}),C&&s.jsx("div",{className:"oc-human-gate-error",children:C})]})}function Up(u){const{operation:r}=u,m=r.inspectHref.startsWith("/")?`${u.origin}${r.inspectHref}`:r.inspectHref,d=r.state==="failed"||r.state==="timed-out"||r.state==="needs-reconcile",b=(D,Q)=>{u.onNavigateWorkspace?u.onNavigateWorkspace(D,Q):window.location.assign(Rp(D,Q))},C=[r.taskId?["task",r.taskId]:void 0,r.dagRunId?["dag",r.dagRunId]:void 0,r.featureId?["feature",r.featureId]:void 0,r.workerRunId?["worker",r.workerRunId]:void 0].filter(D=>!!D);return s.jsxs("section",{className:`oc-operation-card is-${r.state}`,"aria-label":`Operation ${r.operationId}`,children:[s.jsxs("header",{className:"oc-operation-head",children:[s.jsxs("div",{children:[s.jsx("div",{className:"oc-operation-kicker",children:"Operation"}),s.jsx("strong",{children:r.action})]}),s.jsx("span",{className:`oc-operation-state is-${r.state}`,children:r.state})]}),s.jsx("div",{className:"oc-operation-id",children:s.jsx("code",{children:r.operationId})}),C.length>0&&s.jsx("div",{className:"oc-operation-identities",children:C.map(([D,Q])=>s.jsxs("span",{children:[s.jsx("b",{children:D})," ",Q]},`${D}:${Q}`))}),r.controller&&s.jsxs("div",{className:"oc-operation-controller",children:["controller: ",r.controller]}),r.summaryPreview&&s.jsx("pre",{className:"oc-operation-preview",children:r.summaryPreview}),r.stderrPreview&&s.jsx("pre",{className:"oc-operation-preview is-error",children:r.stderrPreview}),r.stdoutPreview&&s.jsx("pre",{className:"oc-operation-preview",children:r.stdoutPreview}),s.jsxs("footer",{className:"oc-operation-actions",children:[s.jsx("a",{className:"btn btn-ghost",href:m,target:"_blank",rel:"noreferrer",children:"Inspect"}),r.taskId&&s.jsx("button",{className:"btn btn-ghost",type:"button",onClick:()=>b("tasks",{taskId:r.taskId}),children:"打开 Task Ops"}),r.dagRunId&&s.jsx("a",{className:"btn btn-ghost",href:`${u.origin}/inspect/#/dag/${encodeURIComponent(r.dagRunId)}`,target:"_blank",rel:"noreferrer",children:"打开 Run / Inspect"}),d&&(r.dagRunId||r.taskId)&&s.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>b("recovery",{taskId:r.taskId,dagRunId:r.dagRunId}),children:"打开 Recovery"}),s.jsx("time",{dateTime:r.updatedAt,children:new Date(r.updatedAt).toLocaleString()})]})]})}function Hp(u){const{artifact:r}=u;return s.jsxs("section",{className:"oc-artifact-card","aria-label":`${r.kind} artifact`,children:[s.jsxs("header",{children:[s.jsx("strong",{children:r.title??r.artifactId}),s.jsx("span",{children:r.kind})]}),r.summary&&s.jsx("p",{children:r.summary}),r.reportText&&s.jsx("pre",{children:r.reportText}),r.htmlPreview&&s.jsx("iframe",{title:`${r.title??r.artifactId} preview`,sandbox:"",srcDoc:r.htmlPreview}),r.inspectHref&&s.jsx("a",{href:r.inspectHref,children:"查看详情"})]})}function Lp(u){const{message:r,streaming:m,activeAssistantId:d}=u,b=r.role==="user",C=b?"你":"π",D=b?"你":"助手",Q=!b&&m&&d!==null&&r.id===d,Y=Q&&r.text.length===0,O=r.text.trim().length>0;return s.jsxs("div",{className:`oc-row ${b?"is-user":"is-assistant"}`,children:[s.jsxs("div",{className:"oc-meta",children:[s.jsx("span",{className:`oc-avatar ${b?"oc-avatar-user":"oc-avatar-assistant"}`,"aria-hidden":"true",children:C}),s.jsx("span",{className:"oc-role",children:D}),s.jsx("span",{className:"oc-time",children:km(r.createdAt)}),O&&s.jsx(Bp,{text:r.text})]}),s.jsxs("div",{className:`oc-bubble ${b?"oc-bubble-user":"oc-bubble-assistant"}`,children:[O?b?s.jsx("div",{style:{whiteSpace:"pre-wrap"},children:r.text}):s.jsx(ap,{text:r.text}):Y?s.jsx("span",{className:"oc-cursor","aria-hidden":"true"}):s.jsx("span",{style:{color:"var(--muted-soft)"},children:"…"}),Q&&O&&s.jsx("span",{className:"oc-cursor","aria-hidden":"true"})]})]})}const qp=h.forwardRef(function({open:r,onToggle:m,onClose:d,context:b},C){const D=Object.keys(b.resources??{}).length;return s.jsxs("div",{className:"oc-runtime-context-menu",ref:C,children:[s.jsx("button",{type:"button",className:`btn btn-ghost oc-runtime-context-toggle${r?" is-active":""}`,"aria-expanded":r,"aria-controls":"oc-runtime-context-panel",onClick:m,children:"注入上下文"}),r&&s.jsxs("div",{id:"oc-runtime-context-panel",className:"oc-runtime-context-panel",role:"dialog","aria-label":"注入上下文",children:[s.jsxs("header",{className:"oc-runtime-context-head",children:[s.jsx("strong",{children:"注入上下文"}),s.jsx("span",{className:"oc-runtime-context-meta",children:"只读 · 本轮请求实际注入"}),s.jsx("button",{type:"button",className:"btn btn-ghost oc-runtime-context-close","aria-label":"关闭",onClick:d,children:"关闭"})]}),s.jsxs("div",{className:"oc-runtime-context-body",children:[s.jsxs("dl",{className:"oc-runtime-context-dl",children:[s.jsxs("div",{children:[s.jsx("dt",{children:"System prompt"}),s.jsxs("dd",{children:[b.systemPrompt.summary??"—",s.jsxs("code",{className:"oc-runtime-context-hash",children:[b.systemPrompt.hash.slice(0,12),"…"]})]})]}),b.model&&s.jsxs("div",{children:[s.jsx("dt",{children:"Model"}),s.jsx("dd",{children:s.jsx("code",{children:Ha(b.model.provider,b.model.modelId)})})]}),b.thinkingLevel&&s.jsxs("div",{children:[s.jsx("dt",{children:"Thinking"}),s.jsx("dd",{children:b.thinkingLevel})]}),s.jsxs("div",{children:[s.jsx("dt",{children:"Skills"}),s.jsx("dd",{children:b.skills.length===0?"无":s.jsx("ul",{className:"oc-runtime-context-skills",children:b.skills.map(Q=>s.jsxs("li",{children:[s.jsx("code",{children:Q.name}),s.jsxs("span",{children:[Q.charCount.toLocaleString()," 字"]})]},Q.name))})})]}),s.jsxs("div",{children:[s.jsx("dt",{children:"Suffix"}),s.jsx("dd",{children:b.suffix.present?b.suffix.summary??"已注入":"未注入"})]}),s.jsxs("div",{children:[s.jsx("dt",{children:"Resources"}),s.jsx("dd",{children:D>0?`${D} 项`:"无"})]})]}),s.jsxs("details",{className:"oc-runtime-context-raw",children:[s.jsx("summary",{children:"原始 JSON"}),s.jsx("pre",{children:JSON.stringify(b,null,2)})]})]})]})]})});function Bp(u){const[r,m]=h.useState(!1),d=()=>{navigator.clipboard?.writeText(u.text).then(()=>{m(!0),window.setTimeout(()=>m(!1),1600)},()=>{})};return s.jsx("button",{type:"button",className:`oc-message-copy${r?" is-copied":""}`,"aria-label":r?"已复制":"复制消息",title:r?"已复制":"复制",onClick:d,children:r?s.jsx(Xp,{}):s.jsx(Yp,{})})}function Gp(u){const{entry:r}=u,[m,d]=h.useState(r.status==="error"),b=r.status==="running"?"运行中":r.status==="error"?"出错":"完成",C=`is-${r.status}`,D=Op(r.args);return s.jsxs("div",{className:`oc-tool ${r.status==="error"?"is-error":""} ${r.status==="running"?"is-running":""}`,children:[s.jsxs("button",{type:"button",className:"oc-tool-head","aria-expanded":m,onClick:()=>d(Q=>!Q),children:[s.jsx(Vp,{}),s.jsx("span",{className:"oc-tool-icon","aria-hidden":"true",children:s.jsx($p,{})}),s.jsx("span",{className:"oc-tool-name",children:r.toolName}),D&&s.jsx("span",{className:"oc-tool-args",children:D}),s.jsx("span",{className:`oc-tool-status ${C}`,children:b})]}),m&&s.jsxs("div",{className:"oc-tool-body",children:[r.args!==void 0&&s.jsxs("div",{className:"oc-tool-section",children:[s.jsx("div",{className:"oc-tool-label",children:"入参"}),s.jsx("pre",{className:"oc-tool-code",children:typeof r.args=="string"?r.args:JSON.stringify(r.args,null,2)})]}),r.resultText!==void 0&&s.jsxs("div",{className:"oc-tool-section",children:[s.jsx("div",{className:"oc-tool-label",children:r.status==="error"?"错误":"结果"}),s.jsx("pre",{className:"oc-tool-code",children:r.resultText})]}),r.status==="running"&&r.resultText===void 0&&r.args===void 0&&s.jsx("div",{className:"oc-tool-section",children:s.jsx("div",{className:"oc-tool-waiting",children:"等待结果…"})})]})]})}function Yp(){return s.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[s.jsx("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),s.jsx("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]})}function Xp(){return s.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("polyline",{points:"20 6 9 17 4 12"})})}function Qp(){return s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[s.jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),s.jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})}function Zp(){return s.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",children:s.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"2"})})}function Vp(){return s.jsx("svg",{className:"oc-tool-chevron",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("polyline",{points:"4 2.5 7.5 6 4 9.5"})})}function $p(){return s.jsx("svg",{width:"13",height:"13",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"})})}function fc(u){const r=(u??"").trim();return r?/controller identity changed|package fingerprint changed|entry binary sha256 changed/i.test(r)?"控制器版本已变更(Console 启动后代码被重新编译)。请重启 Console 后再试,一次会话中途不要升级/重建控制器。":r:"操作失败"}const Kp={report:{id:"report",label:"查看报告",action:"dagReport",lane:"dag",guide:"看失败分类与建议动作(交接报告摘要)",commandHint:"loop-agent dag report --run-id <run-id> --json"},doctor:{id:"doctor",label:"Doctor 诊断",action:"doctor",lane:"dag",guide:"只读诊断:检查 Console / Pi / 仓库就绪,不是重跑前置",commandHint:"agent-worker console doctor --repo ."},decision:{id:"decision",label:"人工决策",lane:"dag",guide:"暂停等人时:先看 doctor 输出再做决策(经 CLI)",commandHint:"loop-agent dag doctor --run-id <run-id> --markdown"},resume:{id:"resume",label:"恢复运行",lane:"dag",guide:"仅当运行可安全 resume 时使用(经 CLI)",commandHint:"loop-agent run-dag --resume --run-id <run-id>"},reconcile:{id:"reconcile",label:"对账 / reconcile",requiresReason:!0,lane:"dag",guide:"状态不一致时先对账,再决定是否重跑(需原因)",commandHint:"loop-agent dag reconcile-run --run-id <run-id> --reason <structured-reason>"},regenerate:{id:"regenerate",label:"重新生成契约/计划",lane:"dag",guide:"契约/计划过期时:回任务页或经 CLI 重新 run-task(本页仅提示)",commandHint:"loop-agent dag run-task <task-id> --profile auto"},observeLink:{id:"observeLink",label:"全屏观测",action:"observeLink",lane:"dag",guide:"打开完整 Inspect 画布;顶栏可返回操作台",commandHint:"agent-worker console serve --repo . --port 8790"},dagRerun:{id:"dagRerun",label:"从节点重跑",requiresReason:!0,action:"dagRerun",lane:"dag",guide:"子图重跑:需选起点且 plan 合格;含 writer 的早期节点常不可用",commandHint:"loop-agent dag rerun --run-id <run-id> --from-node <node-id> --plan"},standaloneTaskRerun:{id:"standaloneTaskRerun",label:"完整重跑任务",requiresReason:!0,action:"standaloneTaskRerun",lane:"dag",guide:"整单重跑:失败类默认首选;需确认原因后提交",commandHint:"loop-agent dag rerun-task --run-id <run-id> --reason <reason> --request-id <key>"},workerTaskRetry:{id:"workerTaskRetry",label:"重新排队 Worker Task",requiresReason:!0,action:"workerTaskRetry",lane:"worker",guide:"仅 Worker 队列任务失败时使用,不要与 DAG 重跑混用",commandHint:"agent-worker task retry <task-id> --feature-id <feature-id> --repo . --reason <reason>"}},Cm={"validation-failed":["report","doctor","regenerate"],"contract-drift":["report","doctor","decision","reconcile","regenerate"],"runtime-mismatch":["report","doctor","reconcile","regenerate"],"pause-on-human":["decision","resume","report","doctor"],"verification-failed":["report","doctor","standaloneTaskRerun","dagRerun","resume","regenerate"],"orphan-unknown":["report","doctor","reconcile"],"terminal-failed":["report","doctor","dagRerun","standaloneTaskRerun","workerTaskRetry","regenerate"],"terminal-succeeded":["report","observeLink"],"needs-reconcile":["report","doctor","reconcile","regenerate"]};function Jp(u){return(Cm[u]??Cm["orphan-unknown"]).map(m=>Kp[m])}function Ip(u){const r=[],m=[];for(const d of u)d.lane==="worker"?m.push(d):r.push(d);return{dag:r,worker:m}}function Wp(u){return typeof u.action=="string"&&u.action.trim().length>0}function wm(u){return Jp(u).filter(Wp)}function Fp(u){const r=new Set(wm(u).map(d=>d.id)),m=(...d)=>{for(const b of d)if(r.has(b))return b;return null};switch(u){case"terminal-failed":case"verification-failed":return m("standaloneTaskRerun","dagRerun","doctor","report");case"pause-on-human":return m("doctor","report");case"needs-reconcile":case"runtime-mismatch":case"contract-drift":return m("doctor","report");case"validation-failed":return m("doctor","report");case"terminal-succeeded":return m("observeLink","report");default:return m("doctor","report")}}function Pp(u){if(u.needsReconcile)return"needs-reconcile";const r=(u.errorCode??"").toLowerCase(),m=(u.operationState??"").toLowerCase(),d=(u.dagStatus??"").toLowerCase();return r.includes("validation")||r.includes("invalid")||m.includes("validation")?"validation-failed":r.includes("contract")||r.includes("drift")||r.includes("binding")?"contract-drift":r.includes("runtime")||r.includes("mismatch")||r.includes("fingerprint")?"runtime-mismatch":r.includes("human")||m.includes("paused")||d.includes("paused")||m.includes("awaiting")?"pause-on-human":r.includes("verif")||m.includes("verif")?"verification-failed":m==="succeeded"||m==="completed"||d==="succeeded"||d==="completed"?"terminal-succeeded":m==="failed"||m.includes("fail")||d==="failed"||r.includes("fail")?"terminal-failed":r.includes("reconcil")||m.includes("reconcil")?"needs-reconcile":"orphan-unknown"}const wr=new Set(["failed","error","partial_failed"]),Um=new Set(["blocked","paused","awaiting_human"]);function yc(u){return(u??"").trim().toLowerCase()}function ey(u){return wr.has(yc(u))}function Am(u){const r=yc(u.status);return wr.has(r)||r.includes("fail")?0:u.lifecycle==="paused"||r==="paused"?1:u.lifecycle==="active"?2:3}function ty(u){return[...u].sort((r,m)=>{const d=Am(r)-Am(m);return d!==0?d:m.mtimeMs-r.mtimeMs})}function ny(u){return ty(u)[0]?.dagRunId}function Rm(u){const r=yc(u.status);return wr.has(r)?0:Um.has(r)?1:2}function Hm(u){return[...u].sort((r,m)=>{const d=Rm(r)-Rm(m);return d!==0?d:r.nodeId.localeCompare(m.nodeId)})}function ly(u){const r=Hm(u);return r.find(d=>ey(d.status)||Um.has(yc(d.status)))?.nodeId??r[0]?.nodeId}function ay(u){const r=u.status?.trim()||u.lifecycle;return`${u.dagRunId.length>36?`${u.dagRunId.slice(0,18)}…${u.dagRunId.slice(-8)}`:u.dagRunId} · ${r}`}function iy(u){const r=u.status?.trim()||"unknown",m=u.label?.trim();return m&&m!==u.nodeId?`${u.nodeId} · ${r} · ${m}`:`${u.nodeId} · ${r}`}function sy(u){const m=[`operator-recovery: ${u.actionLabel?.trim()||"恢复"}`],d=u.dagRunId?.trim();if(d){const Q=u.runStatus?.trim();m.push(Q?`run=${d} (${Q})`:`run=${d}`)}const b=u.fromNodeId?.trim();if(b){const Q=u.nodeStatus?.trim();m.push(Q?`from-node=${b} (${Q})`:`from-node=${b}`)}const C=u.factClassLabel?.trim();C&&m.push(`fact=${C}`);const D=u.nodeError?.trim()||u.errorMessage?.trim()||(u.errorCode?.trim()?`code=${u.errorCode.trim()}`:"");return D&&m.push(`detail=${D.replace(/\s+/g," ").slice(0,280)}`),m.join(`
|
|
19
|
+
`);ot=Se.pop()??"";for(const pt of Se){const Dt=ll(pt,J,{replay:!0,targetSessionId:f});Dt&&(An.current=Dt)}}await Nr(1e3,S)}catch{if(S.aborted)return;await Nr(2e3,S)}},[r,ll]);h.useEffect(()=>{if(!D||Xt&&hl.current.has(D.sessionId))return;const f=new AbortController;return pl.current=f,kn(D.sessionId,f.signal),()=>{f.abort(),pl.current===f&&(pl.current=null)}},[D,Xt,kn]);const xa=h.useCallback(async()=>{const f=se.current;if(!f)return;const S=window.prompt("Task ID(例如 2026-07-26-my-task)")?.trim();if(!S)return;const A=await fetch(`${r}/api/operator/v1/chat/sessions/${f.sessionId}/interviews`,{method:"POST",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},credentials:"include",body:JSON.stringify({taskId:S})}),U=await A.json();if(!A.ok){Z(U.error?.message??`HTTP ${A.status}`);return}G({interviewSessionId:U.interview?.sessionId,taskId:S,state:U.interview?.state,question:U.question,draft:U.draft?.draft,draftSha256:U.draft?.draftSha256,assessment:U.assessment})},[r]),wn=h.useCallback(async f=>{const S=se.current;if(!S||!T?.interviewSessionId||!T.question)return;const A=await fetch(`${r}/api/operator/v1/chat/sessions/${S.sessionId}/interviews/${T.interviewSessionId}/answers`,{method:"POST",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},credentials:"include",body:JSON.stringify({questionId:T.question.id,response:f,...f==="override"?{text:Jn}:{}})}),U=await A.json();if(!A.ok){Z(U.error?.message??`HTTP ${A.status}`);return}G(W=>({...W??{},state:U.interview?.state,question:U.question,draft:U.draft?.draft,draftSha256:U.draft?.draftSha256,assessment:U.assessment,taskKindRecommendation:U.taskKindRecommendation??W?.taskKindRecommendation})),Ft("")},[r,T,Jn]),Al=h.useCallback(async()=>{const f=se.current;if(!f||!T?.interviewSessionId||!T.taskKindRecommendation)return;const S=await fetch(`${r}/api/operator/v1/chat/sessions/${f.sessionId}/interviews/${T.interviewSessionId}/task-kind/confirm`,{method:"POST",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},credentials:"include",body:JSON.stringify({taskKind:T.taskKindRecommendation})}),A=await S.json();if(!S.ok){Z(A.error?.message??`HTTP ${S.status}`);return}G(U=>({...U??{},confirmedTaskKind:U?.taskKindRecommendation,taskKindRecommendation:void 0,draft:A.draft?.draft,draftSha256:A.draft?.draftSha256,assessment:A.assessment}))},[r,T]);h.useEffect(()=>{D?.sessionId&&St(D.sessionId)},[D?.sessionId,St]),h.useEffect(()=>{const f=D?.sessionId;if(!f)return;const S=window.setTimeout(()=>{St(f,{background:!0})},350);return()=>window.clearTimeout(S)},[D?.sessionId,ht,xe,T,St]);const al=h.useCallback(f=>{const S=Np(f);Yt(""),$e(!1),S&&(S.action==="focus:interview"?xa():S.action==="show-help"?Z(`可用 shortcuts:${Or.map(A=>A.command).join("、")}`):S.action.startsWith("focus-panel:")?Vl.current?.scrollIntoView({behavior:"smooth",block:"nearest"}):Z(`未知 shortcut:${S.command}`))},[xa]),_t=h.useMemo(()=>Ke.startsWith("/")?Or.filter(f=>f.command.startsWith(Ke.trim().split(/\s+/,1)[0].toLowerCase())):[],[Ke]),Un=h.useCallback(f=>{if(Ge&&_t.length>0&&!f.nativeEvent.isComposing){if(f.key==="ArrowDown"||f.key==="ArrowUp"){f.preventDefault(),Kn(U=>(U+(f.key==="ArrowDown"?1:_t.length-1))%_t.length);return}if(f.key==="Escape"){f.preventDefault(),$e(!1);return}if(f.key==="Enter"){f.preventDefault(),al(_t[Gt]?.command??_t[0].command);return}}const S=Date.now()-Le.current<100,A=nl.current||f.nativeEvent.isComposing;if(f.key==="Enter"&&!f.shiftKey&&(A||S)){S&&f.preventDefault();return}if(f.key==="Enter"&&!f.shiftKey){f.preventDefault(),_n(Ke);return}},[Ke,_n,Ge,_t,Gt,al]),jt=h.useMemo(()=>be.filter(f=>f.role!=="system"||ga).slice(-z),[be,ga,z]);h.useEffect(()=>{const f=()=>{document.hidden||Ce(0)};return document.addEventListener("visibilitychange",f),()=>document.removeEventListener("visibilitychange",f)},[]);const it=h.useCallback(async()=>{const f=se.current;if(!(!f||We.current))try{const S=await fetch(`${r}/api/operator/v1/chat/sessions/${encodeURIComponent(f.sessionId)}/compact`,{method:"POST",credentials:"include",headers:{"x-loop-console-confirmation":$n()}}),A=await S.json().catch(()=>({}));if(!S.ok){Z(A.error?.message??"上下文压缩失败");return}Z(null)}catch(S){Z(S instanceof Error?S.message:"上下文压缩失败")}},[r]),an=h.useMemo(()=>{if(Pe.length===0)return null;const f=Pe.filter(H=>H.status==="running"),S=Pe.filter(H=>H.status==="error"),A=f[f.length-1];let U="完成",W="ok";return S.length>0?(U=`${S.length} 出错`,W="error"):f.length>0&&(U=A?`正在调用 ${A.toolName}`:"运行中",W="running"),{count:Pe.length,statusLabel:U,statusKind:W}},[Pe]),yn=D?.model??Fn?.model,sn=yn?Ha(yn.provider,yn.modelId):"",Jl=D?.thinkingLevel??Fn?.thinkingLevel??"",il=!sn||Wn.some(f=>Ha(f.provider,f.id)===sn),sl=h.useMemo(()=>{if(!b)return null;const f=(b.tools??[]).map(A=>({toolId:A.toolId,action:A.action,description:A.description,kind:A.kind??"read",cli:A.cli})),S=[...zp];return{explore:S,operator:f,total:S.length+f.length}},[b]),Mt=u.readiness==="setup-required"?"⚠ Pi 未就绪(setup-required):Chat 需要先完成 Pi 认证 / 模型配置。":u.readiness==="degraded"?"⚠ Pi 降级(degraded):可继续对话,但部分能力不可用。":null,Rl=async(f,S)=>{if(!(await fetch(`${r}/api/operator/v1/chat/sessions/${encodeURIComponent(f)}`,{method:"PATCH",credentials:"include",headers:{"content-type":"application/json","x-loop-console-confirmation":$n()},body:JSON.stringify(S)})).ok){Z("会话更新失败");return}await tn(),S.state==="archived"&&se.current?.sessionId===f&&(se.current=null,Q(null),window.localStorage.removeItem(fl))},pe=s.jsx(mp,{origin:r,open:K,activeSessionId:D?.sessionId,sessions:Y,tree:ee,expanded:le,treeError:nt,onToggleOpen:()=>X(f=>!f),onCreate:()=>{ln()},onActivate:f=>{It(f)},onRename:(f,S)=>{Rl(f,{title:S})},onSetState:(f,S)=>{Rl(f,{state:S})},onDelete:f=>{Cl(f)},onRefreshTree:()=>{zn()},onToggleDir:f=>{ce(S=>{const A=new Set(S);return A.has(f)?A.delete(f):A.add(f),A}),ee[f]||zn(f)},onInsert:f=>Yt(S=>`${S}${S&&!S.endsWith(" ")?" ":""}@${f} `),onPreview:f=>{lt(f)}}),Vt=jt.length>0||ht.length>0||xe.length>0||Ie.length>0||!!T;return s.jsxs("div",{className:"oc-shell",children:[d?null:s.jsxs("div",{className:"oc-banner",children:[s.jsxs("span",{className:"oc-banner-title",children:[s.jsx("span",{className:"oc-banner-dot","aria-hidden":"true"}),"对话"]}),s.jsxs("span",{className:"oc-banner-body",children:["用自然语言编排 loop-agent / agent-worker 的",s.jsx("strong",{children:"全部能力"}),"。这是 ",s.jsx("strong",{children:"Operator"})," ","面:可通过 safe-read/safe-grep/git-status/git-diff/find/ls 探查仓库、调用受策略约束的 operator action;",s.jsx("strong",{children:"无 bash 或直接写文件工具"}),"(业务写入仍应经受治理 DAG 的 implement-pi / repair-pi)。"]})]}),Mt&&s.jsx("div",{className:"oc-alert oc-alert-warning",children:Mt}),mn&&s.jsxs("div",{className:"oc-alert oc-alert-error",children:[s.jsx("strong",{children:"出错了:"}),mn]}),D?s.jsxs("div",{className:`oc-workspace${hn?" has-process":""}`,children:[pe,s.jsxs("div",{className:`oc-main${Vt?"":" is-landing"}`,children:[s.jsx(vp,{previews:we,activePath:bt,loading:ye,onActivate:ct,onClose:f=>{Ue(S=>{const A=S.filter(U=>U.path!==f);return D&&window.localStorage.setItem(`${fl}.previews.${D.sessionId}`,JSON.stringify(A.map(U=>U.path))),A}),ct(S=>S===f?we.find(A=>A.path!==f)?.path??null:S)}}),s.jsxs("div",{ref:en,className:`oc-messages${Vt?" has-thread":" is-empty"}`,onScroll:nn,children:[Vt?null:s.jsx(Em,{mode:"empty-session",readiness:u.readiness,disabled:Xt,onSuggest:f=>{_n(f)}}),Vt&&be.length>jt.length&&s.jsx("button",{type:"button",className:"btn btn-ghost oc-load-history",onClick:()=>V(f=>f+50),children:"加载更早消息"}),Vt&&jt.map((f,S)=>{const A=jt[S-1],U=!A||Tr(A.createdAt)!==Tr(f.createdAt);return s.jsxs("div",{children:[U&&s.jsx("div",{className:"oc-day-sep",children:Tr(f.createdAt)}),f.role==="system"?s.jsx("div",{className:"oc-row is-tool",children:s.jsx("div",{className:"oc-bubble oc-bubble-tool",children:f.text})}):s.jsx(Lp,{message:f,streaming:Xt,activeAssistantId:Kl})]},`row-${f.id}`)}),T&&s.jsxs("section",{className:"oc-draft-card","aria-label":"Requirement Interview",children:[s.jsxs("header",{children:[s.jsx("strong",{children:"Requirement Interview"}),s.jsx("span",{children:T.state})]}),T.question&&s.jsxs("div",{className:"oc-interview-bubble",children:[s.jsx("strong",{children:T.question.text}),s.jsxs("p",{children:["建议:",T.question.recommendation]}),s.jsx("textarea",{value:Jn,onChange:f=>Ft(f.target.value),placeholder:"输入答案"}),s.jsxs("div",{children:[s.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>{wn("override")},disabled:!Jn.trim(),children:"提交答案"}),s.jsx("button",{className:"btn btn-ghost",type:"button",onClick:()=>{wn("accept-recommendation")},children:"接受建议"})]})]}),T.draft&&s.jsxs("details",{open:!0,children:[s.jsxs("summary",{children:["TaskContractDraftV1 ·"," ",T.draftSha256?.slice(0,12)]}),s.jsx("pre",{children:JSON.stringify(T.draft,null,2)})]}),T.assessment&&s.jsxs("div",{className:`oc-assessment${T.assessment.fresh?" is-fresh":""}`,children:[s.jsxs("strong",{children:["完整性:",T.assessment.outcome]}),(T.assessment.missingFields??[]).length>0&&s.jsxs("p",{children:["缺失:",T.assessment.missingFields?.join("、")]})]}),T.taskKindRecommendation&&s.jsxs("div",{className:"oc-task-kind-card",children:[s.jsx("span",{children:"taskKind 建议"}),s.jsx("strong",{children:T.taskKindRecommendation}),s.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>{Al()},children:"由我确认"}),s.jsx("small",{children:"模型不能代替人类确认。"})]}),T.confirmedTaskKind&&s.jsxs("div",{className:"oc-task-kind-card is-confirmed",children:["已由人类确认:",s.jsx("strong",{children:T.confirmedTaskKind})]})]}),xe.map(f=>s.jsx(wp,{card:f,origin:r,sessionId:D.sessionId},f.cardId)),ht.map(f=>s.jsx(Up,{operation:f,origin:r,onNavigateWorkspace:u.onNavigateWorkspace},f.operationId)),Ie.map(f=>s.jsx(Hp,{artifact:f},f.artifactId)),s.jsx("div",{ref:El})]}),s.jsx("div",{className:"oc-composer",children:s.jsxs("div",{className:"oc-composer-inner",children:[jl.length>0&&s.jsx("div",{className:"oc-file-palette",role:"listbox","aria-label":"Repository files",children:jl.map(f=>s.jsx("button",{type:"button",role:"option",onMouseDown:S=>S.preventDefault(),onClick:()=>On(f),children:s.jsxs("code",{children:["@",f]})},f))}),wt.length>0&&s.jsx("div",{className:"oc-attachment-list",children:wt.map(f=>s.jsxs("span",{children:[f.name,s.jsx("button",{type:"button","aria-label":`移除 ${f.name}`,onClick:()=>In(S=>S.filter(A=>A!==f)),children:"×"})]},f.name))}),s.jsxs("div",{className:"oc-composer-toolbar",children:[s.jsxs("label",{className:"oc-attach-button",children:["添加图片",s.jsx("input",{type:"file",accept:"image/png,image/jpeg,image/gif,image/webp",multiple:!0,hidden:!0,onChange:f=>{const S=Array.from(f.target.files??[]).slice(0,4);for(const A of S){if(!A.type.startsWith("image/")||A.size>5*1024*1024){Z("图片仅支持 PNG/JPEG/GIF/WebP,单张不超过 5 MiB");continue}const U=new FileReader;U.onload=()=>{const W=String(U.result??""),H=W.slice(W.indexOf(",")+1);In(qe=>[...qe,{name:A.name,type:"image",mimeType:A.type,data:H}].slice(0,4))},U.readAsDataURL(A)}f.target.value=""}})]}),s.jsxs("span",{className:"oc-composer-hint",children:[s.jsx("span",{className:"oc-kbd",children:"Enter"})," 发送"]}),s.jsxs("span",{className:"oc-composer-hint",children:[s.jsx("span",{className:"oc-kbd",children:"Shift"}),"+",s.jsx("span",{className:"oc-kbd",children:"Enter"})," 换行"]})]}),Ge&&_t.length>0&&s.jsx("div",{className:"oc-shortcut-palette",role:"listbox","aria-label":"Chat shortcuts",children:_t.map((f,S)=>s.jsxs("button",{type:"button",role:"option","aria-selected":S===Gt,className:S===Gt?"is-active":"",onMouseDown:A=>A.preventDefault(),onClick:()=>al(f.command),children:[s.jsx("code",{children:f.command}),s.jsxs("span",{children:[s.jsx("strong",{children:f.label}),s.jsx("small",{children:f.description})]})]},f.command))}),s.jsxs("div",{className:`oc-composer-shell${Xt?" is-busy":""}`,children:[s.jsx("textarea",{ref:el,className:"oc-textarea",value:Ke,rows:3,placeholder:Xt?"正在生成回复…(可直接发起新问题)":Vt?"输入消息… Enter 发送 · Shift+Enter 换行":"描述目标,或点选上方建议开始…",onChange:f=>{Yt(f.target.value),$e(f.target.value.startsWith("/")),Kn(0)},onKeyDown:Un,onCompositionStart:()=>{nl.current=!0},onCompositionEnd:()=>{nl.current=!1,Le.current=Date.now()},disabled:Xt}),Xt?s.jsx("button",{type:"button",className:"oc-stop",title:"停止生成","aria-label":"停止生成",onClick:Mn,children:s.jsx(Zp,{})}):s.jsx("button",{type:"button",className:"oc-send",title:"发送","aria-label":"发送",onClick:()=>{_n(Ke)},disabled:!Ke.trim()&&wt.length===0,children:s.jsx(Qp,{})})]}),s.jsxs("div",{className:"oc-runtime-controls",children:[s.jsxs("select",{className:"oc-model-select","aria-label":"Model",value:sn,onChange:f=>{const S=Wn.find(A=>Ha(A.provider,A.id)===f.target.value);S&&rt({provider:S.provider,modelId:S.id})},children:[s.jsx("option",{value:"",children:"选择模型"}),yn&&!il?s.jsx("option",{value:sn,children:sn}):null,Wn.filter(f=>f.hasCredentials!==!1).map(f=>s.jsx("option",{value:Ha(f.provider,f.id),children:Ha(f.provider,f.id)},Ha(f.provider,f.id)))]}),s.jsxs("select",{className:"oc-thinking-select","aria-label":"Thinking level",value:Jl,onChange:f=>{rt({thinkingLevel:f.target.value})},children:[s.jsx("option",{value:"",children:"思考等级"}),Cn.map(f=>s.jsx("option",{value:f,children:f},f))]}),s.jsxs("span",{className:"oc-usage",children:[Xt?"运行中":"空闲",te>0?` · ${te} 未读`:""," ·"," ",fn.inputTokens," in · ",fn.outputTokens," out ·"," ",fn.totalTokens," tokens ·"," ",fn.cost===void 0?"—":`$${fn.cost.toFixed(4)}`]}),s.jsx("button",{type:"button",className:"btn btn-ghost",onClick:()=>{it()},disabled:Xt||!Vt,title:Vt?Xt?"生成中,暂不可压缩":"压缩上下文,释放 token":"先进行对话后再压缩上下文",children:"Compact"}),sl?s.jsxs("div",{className:"oc-tools-menu oc-tools-menu--composer",ref:pn,children:[s.jsxs("button",{type:"button",className:`oc-cap-chip oc-tools-toggle${Jt?" is-active":""}`,"aria-pressed":Jt,"aria-expanded":Jt,"aria-controls":"oc-tools-catalog",onClick:()=>{He(f=>!f),Jt||Ae(!1)},children:[sl.total," 工具"]}),Jt&&s.jsxs("div",{id:"oc-tools-catalog",className:"oc-tools-catalog",role:"dialog","aria-label":"可用工具列表",children:[s.jsxs("header",{className:"oc-tools-catalog-head",children:[s.jsx("strong",{children:"可用工具"}),s.jsxs("span",{className:"oc-tools-catalog-meta",children:[sl.total," 个 · 点选了解简介"]}),s.jsx("button",{type:"button",className:"btn btn-ghost oc-tools-catalog-close","aria-label":"关闭工具列表",onClick:()=>He(!1),children:"关闭"})]}),s.jsxs("div",{className:"oc-tools-catalog-body",children:[sl.explore.length>0&&s.jsxs("section",{className:"oc-tools-group",children:[s.jsx("h4",{className:"oc-tools-group-title",children:"仓库探查"}),s.jsx("ul",{className:"oc-tools-list",children:sl.explore.map(f=>s.jsxs("li",{className:"oc-tools-item",children:[s.jsxs("div",{className:"oc-tools-item-head",children:[s.jsx("code",{className:"oc-tools-name",children:f.toolId}),s.jsx("span",{className:"oc-tools-kind is-explore",children:Tm(f.kind)})]}),s.jsx("p",{className:"oc-tools-desc",children:f.description})]},f.toolId))})]}),s.jsxs("section",{className:"oc-tools-group",children:[s.jsx("h4",{className:"oc-tools-group-title",children:"Operator 动作"}),s.jsx("ul",{className:"oc-tools-list",children:sl.operator.map(f=>s.jsxs("li",{className:"oc-tools-item",children:[s.jsxs("div",{className:"oc-tools-item-head",children:[s.jsx("code",{className:"oc-tools-name",children:f.toolId}),s.jsx("span",{className:`oc-tools-kind is-${f.kind??"read"}`,children:Tm(f.kind)})]}),s.jsx("p",{className:"oc-tools-desc",children:f.description}),f.cli&&s.jsxs("p",{className:"oc-tools-cli",children:["CLI: ",s.jsx("code",{children:f.cli})]})]},f.toolId))})]})]})]})]}):null,an&&s.jsxs("button",{type:"button",className:`oc-process-summary is-${an.statusKind}${hn?" is-open":""}`,"aria-pressed":hn,"aria-controls":"oc-process-panel",onClick:()=>{Ae(f=>!f),hn||He(!1)},children:["执行过程 · ",an.count," 工具 ·"," ",an.statusLabel]}),Fn&&s.jsx(qp,{ref:he,open:vn,onToggle:()=>xt(f=>!f),onClose:()=>xt(!1),context:Fn})]})]})})]}),hn&&s.jsxs("aside",{id:"oc-process-panel",className:"oc-process","aria-label":"执行过程",children:[s.jsxs("header",{className:"oc-process-head",children:[s.jsxs("div",{className:"oc-process-title",children:[s.jsx("span",{className:"oc-process-title-mark","aria-hidden":"true"}),"执行过程",s.jsx("span",{className:"oc-process-count",children:Pe.length})]}),s.jsx("button",{type:"button",className:"btn btn-ghost oc-process-close","aria-label":"关闭执行过程",onClick:()=>Ae(!1),children:"关闭"})]}),s.jsx("div",{className:"oc-process-timeline",children:Pe.length===0?s.jsx("div",{className:"oc-process-empty",children:"本轮对话尚无工具调用。诊断细节会在这里按时间线展示。"}):Pe.map((f,S)=>s.jsxs("div",{className:`oc-process-item${S===0?" is-first":""}${S===Pe.length-1?" is-last":""}${f.status==="error"?" is-error":""}${f.status==="running"?" is-running":""}`,children:[s.jsx("div",{className:"oc-process-rail","aria-hidden":"true",children:s.jsx("span",{className:"oc-process-dot"})}),s.jsx("div",{className:"oc-process-time",children:km(f.createdAt)}),s.jsx("div",{className:"oc-process-body",children:s.jsx(Gp,{entry:f})})]},f.id))})]})]}):s.jsxs("div",{className:"oc-workspace",children:[pe,s.jsx("div",{className:"oc-main is-landing",children:s.jsx("div",{className:"oc-messages is-empty",children:s.jsx(Em,{mode:"no-session",readiness:u.readiness,onSuggest:async f=>{await ln()&&await _n(f)},onCreateSession:()=>{ln()}})})})]})]})}h.memo(h.forwardRef(function({context:r,loading:m},d){return s.jsxs("section",{ref:d,className:"oc-task-context","aria-label":"Task context",children:[s.jsxs("header",{children:[s.jsxs("div",{children:[s.jsx("small",{children:"Durable task context"}),s.jsx("strong",{children:r?.taskId??"当前任务"})]}),s.jsx("span",{children:m&&!r?"同步中…":r?.updatedAt?"已恢复":"等待事件"})]}),r?.taskId?s.jsxs("div",{className:"oc-task-context-grid",children:[s.jsxs("div",{children:[s.jsx("b",{children:"Draft"}),s.jsx("span",{children:r.draft?r.draft.draftSha256.slice(0,12):"未生成"})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Assessment"}),s.jsx("span",{children:r.assessment?`${r.assessment.outcome}${r.assessment.fresh?" · fresh":""}`:"未评估"})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Task kind"}),s.jsx("span",{children:r.taskKind?.value??r.draft?.taskKindRecommendation??"待确认"})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Contract"}),s.jsx("span",{children:r.contract?.confirmationState??"待准备"}),r.contract?.diffSummary&&s.jsx("small",{children:r.contract.diffSummary})]}),s.jsxs("div",{children:[s.jsx("b",{children:"DAG"}),s.jsx("span",{children:r.dag?.confirmationState??"待生成"}),r.dag?.spine&&s.jsx("small",{children:r.dag.spine.join(" → ")})]}),s.jsxs("div",{children:[s.jsx("b",{children:"Operations"}),s.jsx("span",{children:r.operations.length?r.operations.map(b=>`${b.action}: ${b.state}`).join(" · "):"无"})]})]}):s.jsx("p",{className:"oc-task-context-empty",children:"Draft、assessment、Contract 与 DAG 状态会在此实时聚合。"})]})}));function wp({card:u,origin:r,sessionId:m}){const[d,b]=h.useState(!1),[C,D]=h.useState(),Q=async()=>{b(!0),D(void 0);try{const X=u.gateType==="dag-run"?u.state==="prepared"?"dag-confirm":"dag-run":u.gateType==="mutation"?"mutation-apply":"contract-apply",ee=u.gateType==="dag-run"?{confirmationId:u.confirmationId,...u.state==="prepared"?{humanGateToken:u.humanGateToken}:{}}:{receiptId:u.receiptId,humanGateToken:u.humanGateToken},B=await fetch(`${r}/api/operator/v1/chat/sessions/${encodeURIComponent(m)}/human-gate/${X}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json","x-loop-console-confirmation":$n()},body:JSON.stringify(ee)}),le=await B.json();if(!B.ok)throw new Error(le.error?.message??`HTTP ${B.status}`)}catch(X){D(X instanceof Error?X.message:String(X))}finally{b(!1)}},Y=u.state==="prepared"||u.gateType==="dag-run"&&u.state==="confirmed",O=u.gateType==="contract-apply"?"Contract apply":u.gateType==="mutation"?"Mutation":"DAG run",K=u.gateType==="contract-apply"?"Apply":u.gateType==="mutation"?"Execute":u.state==="prepared"?"Confirm":"Run";return s.jsxs("section",{className:`oc-human-gate-card is-${u.state}`,"aria-label":`Human gate ${u.cardId}`,children:[s.jsxs("header",{children:[s.jsxs("div",{children:[s.jsx("small",{children:"HumanGateCard · 仅人类可确认"}),s.jsx("strong",{children:O})]}),s.jsx("span",{children:u.state})]}),u.contractDiffSummary&&s.jsx("p",{children:u.contractDiffSummary}),u.displayOnlyChallenges&&s.jsxs("div",{className:"oc-human-gate-challenges",children:[s.jsx("b",{children:"Challenge(仅展示,不是确认信号)"}),s.jsx("ul",{children:u.displayOnlyChallenges.map(X=>s.jsx("li",{children:X},X))})]}),u.dagSpine&&u.dagSpine.length>0&&s.jsxs("div",{children:[s.jsx("b",{children:"DAG spine"}),s.jsx("ol",{children:u.dagSpine.map(X=>s.jsx("li",{children:s.jsx("code",{children:X})},X))})]}),s.jsxs("footer",{children:[s.jsx("a",{href:u.inspectHref,children:"Inspect"}),s.jsx("button",{className:"btn btn-primary",type:"button",disabled:!Y||d,onClick:()=>{Q()},children:d?"提交中…":K})]}),C&&s.jsx("div",{className:"oc-human-gate-error",children:C})]})}function Up(u){const{operation:r}=u,m=r.inspectHref.startsWith("/")?`${u.origin}${r.inspectHref}`:r.inspectHref,d=r.state==="failed"||r.state==="timed-out"||r.state==="needs-reconcile",b=(D,Q)=>{u.onNavigateWorkspace?u.onNavigateWorkspace(D,Q):window.location.assign(Rp(D,Q))},C=[r.taskId?["task",r.taskId]:void 0,r.dagRunId?["dag",r.dagRunId]:void 0,r.featureId?["feature",r.featureId]:void 0,r.workerRunId?["worker",r.workerRunId]:void 0].filter(D=>!!D);return s.jsxs("section",{className:`oc-operation-card is-${r.state}`,"aria-label":`Operation ${r.operationId}`,children:[s.jsxs("header",{className:"oc-operation-head",children:[s.jsxs("div",{children:[s.jsx("div",{className:"oc-operation-kicker",children:"Operation"}),s.jsx("strong",{children:r.action})]}),s.jsx("span",{className:`oc-operation-state is-${r.state}`,children:r.state})]}),s.jsx("div",{className:"oc-operation-id",children:s.jsx("code",{children:r.operationId})}),C.length>0&&s.jsx("div",{className:"oc-operation-identities",children:C.map(([D,Q])=>s.jsxs("span",{children:[s.jsx("b",{children:D})," ",Q]},`${D}:${Q}`))}),r.controller&&s.jsxs("div",{className:"oc-operation-controller",children:["controller: ",r.controller]}),r.summaryPreview&&s.jsx("pre",{className:"oc-operation-preview",children:r.summaryPreview}),r.stderrPreview&&s.jsx("pre",{className:"oc-operation-preview is-error",children:r.stderrPreview}),r.stdoutPreview&&s.jsx("pre",{className:"oc-operation-preview",children:r.stdoutPreview}),s.jsxs("footer",{className:"oc-operation-actions",children:[s.jsx("a",{className:"btn btn-ghost",href:m,target:"_blank",rel:"noreferrer",children:"Inspect"}),r.taskId&&s.jsx("button",{className:"btn btn-ghost",type:"button",onClick:()=>b("tasks",{taskId:r.taskId}),children:"打开 Task Ops"}),r.dagRunId&&s.jsx("a",{className:"btn btn-ghost",href:`${u.origin}/inspect/#/dag/${encodeURIComponent(r.dagRunId)}`,target:"_blank",rel:"noreferrer",children:"打开 Run / Inspect"}),d&&(r.dagRunId||r.taskId)&&s.jsx("button",{className:"btn btn-primary",type:"button",onClick:()=>b("recovery",{taskId:r.taskId,dagRunId:r.dagRunId}),children:"打开 Recovery"}),s.jsx("time",{dateTime:r.updatedAt,children:new Date(r.updatedAt).toLocaleString()})]})]})}function Hp(u){const{artifact:r}=u;return s.jsxs("section",{className:"oc-artifact-card","aria-label":`${r.kind} artifact`,children:[s.jsxs("header",{children:[s.jsx("strong",{children:r.title??r.artifactId}),s.jsx("span",{children:r.kind})]}),r.summary&&s.jsx("p",{children:r.summary}),r.reportText&&s.jsx("pre",{children:r.reportText}),r.htmlPreview&&s.jsx("iframe",{title:`${r.title??r.artifactId} preview`,sandbox:"",srcDoc:r.htmlPreview}),r.inspectHref&&s.jsx("a",{href:r.inspectHref,children:"查看详情"})]})}function Lp(u){const{message:r,streaming:m,activeAssistantId:d}=u,b=r.role==="user",C=b?"你":"π",D=b?"你":"助手",Q=!b&&m&&d!==null&&r.id===d,Y=Q&&r.text.length===0,O=r.text.trim().length>0;return s.jsxs("div",{className:`oc-row ${b?"is-user":"is-assistant"}`,children:[s.jsxs("div",{className:"oc-meta",children:[s.jsx("span",{className:`oc-avatar ${b?"oc-avatar-user":"oc-avatar-assistant"}`,"aria-hidden":"true",children:C}),s.jsx("span",{className:"oc-role",children:D}),s.jsx("span",{className:"oc-time",children:km(r.createdAt)}),O&&s.jsx(Bp,{text:r.text})]}),s.jsxs("div",{className:`oc-bubble ${b?"oc-bubble-user":"oc-bubble-assistant"}`,children:[O?b?s.jsx("div",{style:{whiteSpace:"pre-wrap"},children:r.text}):s.jsx(ap,{text:r.text}):Y?s.jsx("span",{className:"oc-cursor","aria-hidden":"true"}):s.jsx("span",{style:{color:"var(--muted-soft)"},children:"…"}),Q&&O&&s.jsx("span",{className:"oc-cursor","aria-hidden":"true"})]})]})}const qp=h.forwardRef(function({open:r,onToggle:m,onClose:d,context:b},C){const D=Object.keys(b.resources??{}).length;return s.jsxs("div",{className:"oc-runtime-context-menu",ref:C,children:[s.jsx("button",{type:"button",className:`btn btn-ghost oc-runtime-context-toggle${r?" is-active":""}`,"aria-expanded":r,"aria-controls":"oc-runtime-context-panel",onClick:m,children:"注入上下文"}),r&&s.jsxs("div",{id:"oc-runtime-context-panel",className:"oc-runtime-context-panel",role:"dialog","aria-label":"注入上下文",children:[s.jsxs("header",{className:"oc-runtime-context-head",children:[s.jsx("strong",{children:"注入上下文"}),s.jsx("span",{className:"oc-runtime-context-meta",children:"只读 · 本轮请求实际注入"}),s.jsx("button",{type:"button",className:"btn btn-ghost oc-runtime-context-close","aria-label":"关闭",onClick:d,children:"关闭"})]}),s.jsxs("div",{className:"oc-runtime-context-body",children:[s.jsxs("dl",{className:"oc-runtime-context-dl",children:[s.jsxs("div",{children:[s.jsx("dt",{children:"System prompt"}),s.jsxs("dd",{children:[b.systemPrompt.summary??"—",s.jsxs("code",{className:"oc-runtime-context-hash",children:[b.systemPrompt.hash.slice(0,12),"…"]})]})]}),b.model&&s.jsxs("div",{children:[s.jsx("dt",{children:"Model"}),s.jsx("dd",{children:s.jsx("code",{children:Ha(b.model.provider,b.model.modelId)})})]}),b.thinkingLevel&&s.jsxs("div",{children:[s.jsx("dt",{children:"Thinking"}),s.jsx("dd",{children:b.thinkingLevel})]}),s.jsxs("div",{children:[s.jsx("dt",{children:"Skills"}),s.jsx("dd",{children:b.skills.length===0?"无":s.jsx("ul",{className:"oc-runtime-context-skills",children:b.skills.map(Q=>s.jsxs("li",{children:[s.jsx("code",{children:Q.name}),s.jsxs("span",{children:[Q.charCount.toLocaleString()," 字"]})]},Q.name))})})]}),s.jsxs("div",{children:[s.jsx("dt",{children:"Suffix"}),s.jsx("dd",{children:b.suffix.present?b.suffix.summary??"已注入":"未注入"})]}),s.jsxs("div",{children:[s.jsx("dt",{children:"Resources"}),s.jsx("dd",{children:D>0?`${D} 项`:"无"})]})]}),s.jsxs("details",{className:"oc-runtime-context-raw",children:[s.jsx("summary",{children:"原始 JSON"}),s.jsx("pre",{children:JSON.stringify(b,null,2)})]})]})]})]})});function Bp(u){const[r,m]=h.useState(!1),d=()=>{navigator.clipboard?.writeText(u.text).then(()=>{m(!0),window.setTimeout(()=>m(!1),1600)},()=>{})};return s.jsx("button",{type:"button",className:`oc-message-copy${r?" is-copied":""}`,"aria-label":r?"已复制":"复制消息",title:r?"已复制":"复制",onClick:d,children:r?s.jsx(Xp,{}):s.jsx(Yp,{})})}function Gp(u){const{entry:r}=u,[m,d]=h.useState(r.status==="error"),b=r.status==="running"?"运行中":r.status==="error"?"出错":"完成",C=`is-${r.status}`,D=Op(r.args);return s.jsxs("div",{className:`oc-tool ${r.status==="error"?"is-error":""} ${r.status==="running"?"is-running":""}`,children:[s.jsxs("button",{type:"button",className:"oc-tool-head","aria-expanded":m,onClick:()=>d(Q=>!Q),children:[s.jsx(Vp,{}),s.jsx("span",{className:"oc-tool-icon","aria-hidden":"true",children:s.jsx($p,{})}),s.jsx("span",{className:"oc-tool-name",children:r.toolName}),D&&s.jsx("span",{className:"oc-tool-args",children:D}),s.jsx("span",{className:`oc-tool-status ${C}`,children:b})]}),m&&s.jsxs("div",{className:"oc-tool-body",children:[r.args!==void 0&&s.jsxs("div",{className:"oc-tool-section",children:[s.jsx("div",{className:"oc-tool-label",children:"入参"}),s.jsx("pre",{className:"oc-tool-code",children:typeof r.args=="string"?r.args:JSON.stringify(r.args,null,2)})]}),r.resultText!==void 0&&s.jsxs("div",{className:"oc-tool-section",children:[s.jsx("div",{className:"oc-tool-label",children:r.status==="error"?"错误":"结果"}),s.jsx("pre",{className:"oc-tool-code",children:r.resultText})]}),r.status==="running"&&r.resultText===void 0&&r.args===void 0&&s.jsx("div",{className:"oc-tool-section",children:s.jsx("div",{className:"oc-tool-waiting",children:"等待结果…"})})]})]})}function Yp(){return s.jsxs("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[s.jsx("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),s.jsx("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]})}function Xp(){return s.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("polyline",{points:"20 6 9 17 4 12"})})}function Qp(){return s.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[s.jsx("line",{x1:"22",y1:"2",x2:"11",y2:"13"}),s.jsx("polygon",{points:"22 2 15 22 11 13 2 9 22 2"})]})}function Zp(){return s.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",children:s.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"2"})})}function Vp(){return s.jsx("svg",{className:"oc-tool-chevron",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.6",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("polyline",{points:"4 2.5 7.5 6 4 9.5"})})}function $p(){return s.jsx("svg",{width:"13",height:"13",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"})})}function fc(u){const r=(u??"").trim();return r?/controller identity changed|package fingerprint changed|entry binary sha256 changed/i.test(r)?"控制器版本已变更(Console 启动后代码被重新编译)。请重启 Console 后再试,一次会话中途不要升级/重建控制器。":r:"操作失败"}const Kp={report:{id:"report",label:"查看报告",action:"dagReport",lane:"dag",guide:"看失败分类与建议动作(交接报告摘要)",commandHint:"loop-agent dag report --run-id <run-id> --json"},doctor:{id:"doctor",label:"Doctor 诊断",action:"doctor",lane:"dag",guide:"只读诊断:检查 Console / Pi / 仓库就绪,不是重跑前置",commandHint:"agent-worker console doctor --repo ."},decision:{id:"decision",label:"人工决策",lane:"dag",guide:"暂停等人时:先看 doctor 输出再做决策(经 CLI)",commandHint:"loop-agent dag doctor --run-id <run-id> --markdown"},resume:{id:"resume",label:"恢复运行",lane:"dag",guide:"仅当运行可安全 resume 时使用(经 CLI)",commandHint:"loop-agent task advance <task-id> --json"},reconcile:{id:"reconcile",label:"对账 / reconcile",requiresReason:!0,lane:"dag",guide:"状态不一致时先对账,再决定是否重跑(需原因)",commandHint:"loop-agent dag reconcile-run --run-id <run-id> --reason <structured-reason>"},regenerate:{id:"regenerate",label:"重新生成契约/计划",lane:"dag",guide:"契约/计划过期时:回任务页或经 CLI 重新 task advance(本页仅提示)",commandHint:"loop-agent task advance <task-id> --json"},observeLink:{id:"observeLink",label:"全屏观测",action:"observeLink",lane:"dag",guide:"打开完整 Inspect 画布;顶栏可返回操作台",commandHint:"agent-worker console serve --repo . --port 8790"},dagRerun:{id:"dagRerun",label:"从节点重跑",requiresReason:!0,action:"dagRerun",lane:"dag",guide:"子图重跑:需选起点且 plan 合格;含 writer 的早期节点常不可用",commandHint:"loop-agent dag rerun --run-id <run-id> --from-node <node-id> --plan"},standaloneTaskRerun:{id:"standaloneTaskRerun",label:"完整重跑任务",requiresReason:!0,action:"standaloneTaskRerun",lane:"dag",guide:"整单重跑:失败类默认首选;需确认原因后提交",commandHint:"loop-agent task advance <task-id> --json"},workerTaskRetry:{id:"workerTaskRetry",label:"重新排队 Worker Task",requiresReason:!0,action:"workerTaskRetry",lane:"worker",guide:"仅 Worker 队列任务失败时使用,不要与 DAG 重跑混用",commandHint:"agent-worker task retry <task-id> --feature-id <feature-id> --repo . --reason <reason>"}},Cm={"validation-failed":["report","doctor","regenerate"],"contract-drift":["report","doctor","decision","reconcile","regenerate"],"runtime-mismatch":["report","doctor","reconcile","regenerate"],"pause-on-human":["decision","resume","report","doctor"],"verification-failed":["report","doctor","standaloneTaskRerun","dagRerun","resume","regenerate"],"orphan-unknown":["report","doctor","reconcile"],"terminal-failed":["report","doctor","dagRerun","standaloneTaskRerun","workerTaskRetry","regenerate"],"terminal-succeeded":["report","observeLink"],"needs-reconcile":["report","doctor","reconcile","regenerate"]};function Jp(u){return(Cm[u]??Cm["orphan-unknown"]).map(m=>Kp[m])}function Ip(u){const r=[],m=[];for(const d of u)d.lane==="worker"?m.push(d):r.push(d);return{dag:r,worker:m}}function Wp(u){return typeof u.action=="string"&&u.action.trim().length>0}function wm(u){return Jp(u).filter(Wp)}function Fp(u){const r=new Set(wm(u).map(d=>d.id)),m=(...d)=>{for(const b of d)if(r.has(b))return b;return null};switch(u){case"terminal-failed":case"verification-failed":return m("standaloneTaskRerun","dagRerun","doctor","report");case"pause-on-human":return m("doctor","report");case"needs-reconcile":case"runtime-mismatch":case"contract-drift":return m("doctor","report");case"validation-failed":return m("doctor","report");case"terminal-succeeded":return m("observeLink","report");default:return m("doctor","report")}}function Pp(u){if(u.needsReconcile)return"needs-reconcile";const r=(u.errorCode??"").toLowerCase(),m=(u.operationState??"").toLowerCase(),d=(u.dagStatus??"").toLowerCase();return r.includes("validation")||r.includes("invalid")||m.includes("validation")?"validation-failed":r.includes("contract")||r.includes("drift")||r.includes("binding")?"contract-drift":r.includes("runtime")||r.includes("mismatch")||r.includes("fingerprint")?"runtime-mismatch":r.includes("human")||m.includes("paused")||d.includes("paused")||m.includes("awaiting")?"pause-on-human":r.includes("verif")||m.includes("verif")?"verification-failed":m==="succeeded"||m==="completed"||d==="succeeded"||d==="completed"?"terminal-succeeded":m==="failed"||m.includes("fail")||d==="failed"||r.includes("fail")?"terminal-failed":r.includes("reconcil")||m.includes("reconcil")?"needs-reconcile":"orphan-unknown"}const wr=new Set(["failed","error","partial_failed"]),Um=new Set(["blocked","paused","awaiting_human"]);function yc(u){return(u??"").trim().toLowerCase()}function ey(u){return wr.has(yc(u))}function Am(u){const r=yc(u.status);return wr.has(r)||r.includes("fail")?0:u.lifecycle==="paused"||r==="paused"?1:u.lifecycle==="active"?2:3}function ty(u){return[...u].sort((r,m)=>{const d=Am(r)-Am(m);return d!==0?d:m.mtimeMs-r.mtimeMs})}function ny(u){return ty(u)[0]?.dagRunId}function Rm(u){const r=yc(u.status);return wr.has(r)?0:Um.has(r)?1:2}function Hm(u){return[...u].sort((r,m)=>{const d=Rm(r)-Rm(m);return d!==0?d:r.nodeId.localeCompare(m.nodeId)})}function ly(u){const r=Hm(u);return r.find(d=>ey(d.status)||Um.has(yc(d.status)))?.nodeId??r[0]?.nodeId}function ay(u){const r=u.status?.trim()||u.lifecycle;return`${u.dagRunId.length>36?`${u.dagRunId.slice(0,18)}…${u.dagRunId.slice(-8)}`:u.dagRunId} · ${r}`}function iy(u){const r=u.status?.trim()||"unknown",m=u.label?.trim();return m&&m!==u.nodeId?`${u.nodeId} · ${r} · ${m}`:`${u.nodeId} · ${r}`}function sy(u){const m=[`operator-recovery: ${u.actionLabel?.trim()||"恢复"}`],d=u.dagRunId?.trim();if(d){const Q=u.runStatus?.trim();m.push(Q?`run=${d} (${Q})`:`run=${d}`)}const b=u.fromNodeId?.trim();if(b){const Q=u.nodeStatus?.trim();m.push(Q?`from-node=${b} (${Q})`:`from-node=${b}`)}const C=u.factClassLabel?.trim();C&&m.push(`fact=${C}`);const D=u.nodeError?.trim()||u.errorMessage?.trim()||(u.errorCode?.trim()?`code=${u.errorCode.trim()}`:"");return D&&m.push(`detail=${D.replace(/\s+/g," ").slice(0,280)}`),m.join(`
|
|
20
20
|
`).slice(0,500)}function Dm(u){const r=u.trim();return r?r==="operator-recovery"||r.startsWith("operator-recovery:")||r.startsWith("recovery:"):!0}const _r=8*1024*1024,cy=10*1024*1024,pc=8,uy=".md,.markdown,.txt,text/markdown,text/plain",ry=[".md",".markdown",".txt"],Ur=/\.[^.]+$/;function oy(u){const r=Ur.exec(u.trim());return r?r[0].toLowerCase():""}function dy(u){const r=oy(u);return ry.includes(r)}function Mr(u){if(!Number.isFinite(u)||u<0)return"0 B";if(u<1024)return`${u} B`;if(u<1024*1024){const m=u/1024;return`${m>=10?m.toFixed(0):m.toFixed(1)} KiB`}const r=u/(1024*1024);return`${r>=10?r.toFixed(1):r.toFixed(2)} MiB`}function Zl(u,r){return{ok:!1,code:u,message:r}}function fy(u,r){const m=u?Array.from(u):[],d=r?.maxFiles??pc,b=r?.existingCount??0;return m.length===0?Zl("file-count","请选择至少一个 .md / .markdown / .txt 文件"):b+m.length>d?Zl("file-count",`最多支持 ${d} 个文件(当前已有 ${b} 个)`):null}async function my(u){const r=u.name?.trim()||"untitled.md";if(!dy(r))return Zl("unsupported-extension","仅支持 .md、.markdown、.txt 文件");if(u.size>_r)return Zl("file-too-large",`文件不能超过 ${Mr(_r)}`);let m;try{m=await u.arrayBuffer()}catch{return Zl("read-failed","文件读取失败,请重试或直接粘贴")}let d;try{d=new TextDecoder("utf-8",{fatal:!0}).decode(m)}catch{return Zl("invalid-utf8","文件不是有效 UTF-8,请另存为 UTF-8")}if(d.trim().length===0)return Zl("empty-content","文件内容不能为空或只有空白");const b=new TextEncoder().encode(d).byteLength;return{ok:!0,text:d,fileName:r,sourceBytes:u.size,textBytes:b}}async function hy(u){if(u.length===0)return Zl("file-count","请选择至少一个 .md / .markdown / .txt 文件");if(u.length>pc)return Zl("file-count",`最多支持 ${pc} 个文件`);const r=[];for(const m of u){const d=await my(m);if(!d.ok)return d;r.push({fileName:d.fileName,text:d.text,sourceBytes:d.sourceBytes,textBytes:d.textBytes})}return{ok:!0,documents:r}}function vy(u,r){const m=u.split(/\r?\n/);for(const b of m){const C=/^(#{1,6})\s+(.+)$/.exec(b.trim());if(C?.[2])return C[2].trim()}for(const b of m){const C=b.trim();if(C&&!/^---+$/.test(C)&&!/^```/.test(C)&&!/^<!--/.test(C))return C.replace(/^>\s+/,"").slice(0,120)}return r.replace(Ur,"").trim()||"需求"}function py(u){return u.trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"").replace(/-{2,}/g,"-")||"requirement"}function yy(u,r){const m=u.replace(Ur,"").trim(),d=py(m);return d==="requirement"&&/[^\u0000-\u007f]/.test(m)?`part-${r+1}`:d==="requirement"?m?`part-${r+1}`:`part-${r+1}`:d}function gy(u){const r=new Set;return u.map((m,d)=>{let b=yy(m.fileName,d);if(r.has(b)){let C=2;for(;r.has(`${b}-${C}`);)C+=1;b=`${b}-${C}`}return r.add(b),{name:b,content:m.text,fileName:m.fileName}})}function by(u,r){if(u.length===0)return"";if(u.length===1)return u[0].text;const m=Math.min(Math.max(0,r?.primaryIndex??0),u.length-1),d=u[m],b=vy(d.text,d.fileName),D=[`<!-- composed-from: ${u.map(Q=>Q.fileName).join(", ")} -->`,"",`# ${b}`,""];for(const Q of u)D.push(`## 来源:${Q.fileName}`,"",Q.text.trim(),"");return`${D.join(`
|
|
21
21
|
`).trimEnd()}
|
|
22
22
|
`}function xy(u,r,m){const d={action:u,actionParams:r};return new TextEncoder().encode(JSON.stringify(d)).byteLength<=cy}function Sy(){return"最终内容导致请求体超过服务端限制,请缩小文档或减少文件数量"}function jy(u){return u==="validate"||u==="apply"||u==="spine"?"contract":u}const Lm="X-Loop-Console-Confirmation",Ny="agent-worker console doctor --repo .",Er=[{kind:"standard",label:"后端研发(默认 DAG)",hint:"生成标准 hybrid DAG(contract → implement → verify)"},{kind:"frontend-implementation",label:"前端研发",hint:"生成 frontend-implementation 专用节点链"},{kind:"backend-test",label:"后端测试",hint:"生成 backend-test-dag(分析 / 用例 / pytest)"},{kind:"frontend-test",label:"前端测试",hint:"生成 frontend-test-dag(RAG 用例 + Playwright CLI)"}],Cr={"setup-required":"需要设置",ready:"已就绪",degraded:"降级可用",unknown:"未知"},Ty={idle:"未探测",match:"匹配",mismatch:"仓库不匹配",unavailable:"不可用"},zm={low:"低",medium:"中",high:"高"},Om={"validation-failed":"校验失败","contract-drift":"契约漂移","runtime-mismatch":"运行时不匹配","pause-on-human":"等待人工","verification-failed":"验证失败","orphan-unknown":"孤立/未知","terminal-failed":"已终止(失败)","terminal-succeeded":"已终止(成功)","needs-reconcile":"需要对账"},Ey={idle:"空闲","not-started":"未开始","not-run":"未运行","n/a (MVP)":"不适用(MVP)",accepted:"已接受",succeeded:"已成功",running:"运行中",ran:"已执行"};function mc(u){return Ey[u]??u}function qm(){return window.__CONSOLE_CONFIRMATION_TOKEN__??""}function hc(u){return`${u}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`}async function Ar(u,r={},m){const d={"Content-Type":"application/json",[Lm]:qm()},b=await fetch("/api/operator/v1/operations",{method:"POST",credentials:"same-origin",headers:d,body:JSON.stringify({action:u,actionParams:r,...m?{clientRequestId:m}:{}})});let C={};try{C=await b.json()}catch{C={ok:!1,error:{code:"INVALID_INPUT",message:"操作响应不是合法 JSON"}}}return{status:b.status,body:C}}const Cy=new Set(["runDag","dagRerun","standaloneTaskRerun"]);function Rr(u){const r=(u.blockedReasons??[]).map(String),m=(u.blockingNodes??[]).map(b=>[b.nodeId,b.reasonCode].filter(Boolean).join(":")),d=[...r,...m].filter(Boolean);return d.length===0?"从节点重跑不具备安全资格(子图含 writer / unsafe shell / decision-gate 等)。可改用「完整重跑任务」,或另选只读安全子图的起始节点。":`从节点重跑不具备安全资格:${d.slice(0,6).join("; ")}${d.length>6?"…":""}。可改用「完整重跑任务」。`}async function _m(u,r=9e4){const m=Date.now();for(;Date.now()-m<r;){const d=await fetch(`/api/operator/v1/operations/${encodeURIComponent(u)}`,{credentials:"same-origin"});if(!d.ok)return null;const b=await d.json(),C=b.operation??b,D=C.state??"";if(D==="succeeded"||D==="failed"||D==="needs-reconcile"||D==="timed-out")return C;await new Promise(Q=>setTimeout(Q,250))}return{state:"needs-reconcile",errorMessage:"等待操作结果超时"}}function Ay(){const[u,r]=h.useState(()=>Ap({env:void 0,storage:window.localStorage,location:window.location})),[m,d]=h.useState(null),[b,C]=h.useState("setup-required"),[D,Q]=h.useState(null),[Y,O]=h.useState(null),[K,X]=h.useState("setup"),ee=h.useCallback(p=>{X(M=>jy(typeof p=="function"?p(M):p))},[]),[B,le]=h.useState(""),[ce,nt]=h.useState(""),[oe,we]=h.useState("standard"),Ue=Er.find(p=>p.kind===oe)??Er[0],[bt,ct]=h.useState(`# 需求
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Loop 操作台 · Operator Console</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-CNO7n6qB.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-Yyn3ynVv.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -2,12 +2,12 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import YAML from "yaml";
|
|
5
|
-
import { writeTaskConfig, writeTaskArtifactFile } from "../../infrastructure/harness/task-store.js";
|
|
5
|
+
import { writeTaskConfig, writeTaskArtifactFile, } from "../../infrastructure/harness/task-store.js";
|
|
6
6
|
import { getTaskPaths, loadTaskConfig } from "../../task/runtime.js";
|
|
7
7
|
import { adoptTaskContract } from "../../task/contract/adopt.js";
|
|
8
8
|
import { observeTaskContractState } from "../../task/contract/observe.js";
|
|
9
9
|
import { sha256Utf8 } from "../../task/contract/hash.js";
|
|
10
|
-
import { resolveLoopAgentProfile } from "../profile-mapping.js";
|
|
10
|
+
import { resolveLoopAgentProfile, } from "../profile-mapping.js";
|
|
11
11
|
import { mapRiskLevelToComplexity } from "../task-spec/complexity-mapping.js";
|
|
12
12
|
import { resolveWorkflow } from "../task-spec/workflow-routing.js";
|
|
13
13
|
import { validateTaskSpec } from "../task-spec/validate.js";
|
|
@@ -24,14 +24,15 @@ export async function materializeTaskSpec(options) {
|
|
|
24
24
|
const resolvedWorkflow = resolveWorkflow(options.taskSpec);
|
|
25
25
|
const existingConfig = await loadExistingTaskConfig(options.repoRoot, harnessTaskId);
|
|
26
26
|
if (!existingConfig) {
|
|
27
|
-
|
|
27
|
+
// Prefer task advance create path (new-task is being purged from the public surface).
|
|
28
|
+
const newTaskResult = await options.client.run(["task", "advance", harnessTaskId, options.taskSpec.title, "--json"], {
|
|
28
29
|
cwd: options.repoRoot,
|
|
29
|
-
artifactName: `
|
|
30
|
+
artifactName: `task-advance-create-${harnessTaskId}`,
|
|
30
31
|
});
|
|
31
32
|
if (!newTaskResult.ok) {
|
|
32
33
|
const racedConfig = await loadExistingTaskConfig(options.repoRoot, harnessTaskId);
|
|
33
34
|
if (!racedConfig) {
|
|
34
|
-
throw new Error(`loop-agent
|
|
35
|
+
throw new Error(`loop-agent task advance (create) failed with exit ${newTaskResult.exitCode}: ${newTaskResult.stderr}`);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
}
|