diff --git a/cloud/console-react/src/api/client.ts b/cloud/console-react/src/api/client.ts index 164944d..47a9d49 100644 --- a/cloud/console-react/src/api/client.ts +++ b/cloud/console-react/src/api/client.ts @@ -117,7 +117,7 @@ export function traceLineText(e: TraceEntry): string { let body = ""; if (e.kind === "exec") body = (e.command || "") + "(exit=" + (e.exitCode ?? "") + "," + (e.durationMs ?? "") + "ms,cwd=" + (e.cwd || "") + ")"; else if (e.kind === "file") body = (e.path || "") + " " + (e.change || "") + " " + (e.status || ""); - else if (e.kind === "message") body = (e.phase ? "[" + e.phase + "] " : "") + (e.text || ""); + else if (e.kind === "message") body = (e.phase ? "[" + e.phase + "] " : "") + (e.text || "") + (e.truncated ? "(链路摘要已截断至 300 字,完整回复见右侧任务结果)" : ""); else if (e.kind === "reasoning") body = e.summary || ""; else if (e.kind === "tool") body = (e.server || "") + "/" + (e.tool || "") + " " + (e.status || ""); else if (e.kind === "call") body = e.name || ""; diff --git a/cloud/console-react/src/api/types.ts b/cloud/console-react/src/api/types.ts index eb6ae22..0594c18 100644 --- a/cloud/console-react/src/api/types.ts +++ b/cloud/console-react/src/api/types.ts @@ -40,7 +40,7 @@ export interface Automation { id: string; name?: string; status?: string; due?: export interface Member { user_id: string; username?: string; role?: string } export interface SkillItem { name?: string; id?: string; description?: string; detail?: string } export interface McpServer { name?: string; id?: string; status?: string; detail?: string; details?: string; state?: string } -export interface TraceEntry { id?: string; kind?: string; command?: string; exitCode?: number | string; durationMs?: number | string; cwd?: string; path?: string; change?: string; status?: string; phase?: string; text?: string; summary?: string; server?: string; tool?: string; name?: string; prompt?: string } +export interface TraceEntry { id?: string; kind?: string; command?: string; exitCode?: number | string; durationMs?: number | string; cwd?: string; path?: string; change?: string; status?: string; phase?: string; text?: string; summary?: string; server?: string; tool?: string; name?: string; prompt?: string; truncated?: boolean } export interface Agent { kind?: string; name?: string; status?: string; prompt?: string; updated_ts?: number; calls?: TraceEntry[] } export interface ThreadInfo { id?: string; name?: string; thread_name?: string; archived?: boolean | null; cwd?: string; turns?: number; turn_count?: number; turns_count?: number } export interface Triage { diff --git a/cloud/console-react/src/components/chat/mapTrace.ts b/cloud/console-react/src/components/chat/mapTrace.ts index cffc62d..37c658e 100644 --- a/cloud/console-react/src/components/chat/mapTrace.ts +++ b/cloud/console-react/src/components/chat/mapTrace.ts @@ -13,7 +13,12 @@ export interface ChatMessage { id: string; role: ChatRole; text: string; label?: export function traceEntryToChatMessage(e: TraceEntry, i: number): ChatMessage { const id = e.id || "trace-" + i; if (e.kind === "message") { - return { id, role: "assistant", text: (e.phase ? "[" + e.phase + "] " : "") + (e.text || ""), label: "助手" }; + // 链路消息是 host 侧截断后的摘要(消息截 300 字),不是模型 + // 的完整回复:被截断时必须标注,否则半个词结尾会被误读 + // 成模型没写完(2026-10-29 实弹:468 字 final_answer 断在 fu)。 + // 完整回复在任务的 result_text(右侧详情),不在链路条目里。 + const text = (e.phase ? "[" + e.phase + "] " : "") + (e.text || ""); + return { id, role: "assistant", text: e.truncated ? text + "\n(链路摘要已截断至 300 字,完整回复见右侧任务结果)" : text, label: "助手" }; } if (e.kind === "exec" || e.kind === "file" || e.kind === "tool" || e.kind === "call") { const label = e.kind === "exec" ? "命令" : e.kind === "file" ? "文件" : e.kind === "tool" ? "工具" : "调用"; diff --git a/cloud/console.html b/cloud/console.html index 661d321..e639159 100644 --- a/cloud/console.html +++ b/cloud/console.html @@ -52,7 +52,7 @@ `+d[a].replace(" at new "," at ");return t.displayName&&E.includes("")&&(E=E.replace("",t.displayName)),E}while(1<=a&&0<=n);break}}}finally{sl=!1,Error.prepareStackTrace=l}return(l=t?t.displayName||t.name:"")?ue(l):""}function da(t,e){switch(t.tag){case 26:case 27:case 5:return ue(t.type);case 16:return ue("Lazy");case 13:return t.child!==e&&e!==null?ue("Suspense Fallback"):ue("Suspense");case 19:return ue("SuspenseList");case 0:case 15:return Jl(t.type,!1);case 11:return Jl(t.type.render,!1);case 1:return Jl(t.type,!0);case 31:return ue("Activity");case 30:return ue("ViewTransition");default:return""}}function Dl(t){try{var e="",l=null;do e+=da(t,l),l=t,t=t.return;while(t);return e}catch(a){return` Error generating stack: `+a.message+` `+a.stack}}var Zt=Object.prototype.hasOwnProperty,Pe=i.unstable_scheduleCallback,qe=i.unstable_cancelCallback,Tl=i.unstable_shouldYield,fl=i.unstable_requestPaint,Gt=i.unstable_now,Ul=i.unstable_getCurrentPriorityLevel,mn=i.unstable_ImmediatePriority,Qa=i.unstable_UserBlockingPriority,ge=i.unstable_NormalPriority,Xa=i.unstable_LowPriority,ma=i.unstable_IdlePriority,su=i.log,fu=i.unstable_setDisableYieldValue,Fl=null,Ee=null;function rl(t){if(typeof su=="function"&&fu(t),Ee&&typeof Ee.setStrictMode=="function")try{Ee.setStrictMode(Fl,t)}catch{}}var Ne=Math.clz32?Math.clz32:du,ru=Math.log,ou=Math.LN2;function du(t){return t>>>=0,t===0?32:31-(ru(t)/ou|0)|0}var H=256,D=262144,X=4194304;function K(t){var e=t&42;if(e!==0)return e;switch(t&-t){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return t&-t;case 262144:case 524288:case 1048576:case 2097152:return t&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return t&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return t}}function O(t,e,l){var a=t.pendingLanes;if(a===0)return 0;var n=0,u=t.suspendedLanes,c=t.pingedLanes;t=t.warmLanes;var f=a&134217727;return f!==0?(a=f&~u,a!==0?n=K(a):(c&=f,c!==0?n=K(c):l||(l=f&~t,l!==0&&(n=K(l))))):(f=a&~u,f!==0?n=K(f):c!==0?n=K(c):l||(l=a&~t,l!==0&&(n=K(l)))),n===0?0:e!==0&&e!==n&&(e&u)===0&&(u=n&-n,l=e&-e,u>=l||u===32&&(l&4194048)!==0)?e:n}function k(t,e){return(t.pendingLanes&~(t.suspendedLanes&~t.pingedLanes)&e)===0}function J(t,e){(e&8)!==0&&(e|=e&32);var l=t.entangledLanes;if(l!==0)for(t=t.entanglements,l&=e;0l;l++)e.push(t);return e}function pe(t,e){t.pendingLanes|=e,e!==268435456&&(t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0)}function Rc(t,e,l,a,n,u){var c=t.pendingLanes;t.pendingLanes=l,t.suspendedLanes=0,t.pingedLanes=0,t.warmLanes=0,t.expiredLanes&=l,t.entangledLanes&=l,t.errorRecoveryDisabledLanes&=l,t.shellSuspendCounter=0;var f=t.entanglements,d=t.expirationTimes,p=t.hiddenUpdates;for(l=c&~l;0"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Gc=!1;if(Il)try{var Su={};Object.defineProperty(Su,"passive",{get:function(){Gc=!0}}),window.addEventListener("test",Su,Su),window.removeEventListener("test",Su,Su)}catch{Gc=!1}var ha=null,kc=null,mi=null;function Rr(){if(mi)return mi;var t,e=kc,l=e.length,a,n="value"in ha?ha.value:ha.textContent,u=n.length;for(t=0;t=xu),Yr=" ",wr=!1;function Gr(t,e){switch(t){case"keyup":return Av.indexOf(e.keyCode)!==-1;case"keydown":return e.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function kr(t){return t=t.detail,typeof t=="object"&&"data"in t?t.data:null}var Tn=!1;function Mv(t,e){switch(t){case"compositionend":return kr(e);case"keypress":return e.which!==32?null:(wr=!0,Yr);case"textInput":return t=e.data,t===Yr&&wr?null:t;default:return null}}function zv(t,e){if(Tn)return t==="compositionend"||!Zc&&Gr(t,e)?(t=Rr(),mi=kc=ha=null,Tn=!1,t):null;switch(t){case"paste":return null;case"keypress":if(!(e.ctrlKey||e.altKey||e.metaKey)||e.ctrlKey&&e.altKey){if(e.char&&1"u")return null;try{return t.activeElement||t.body}catch{return t.body}}function Fr(t){for(;t&&t.firstChild;)t=t.firstChild;return t}function Wr(t,e){var l=Fr(t);t=0;for(var a;l;){if(l.nodeType===3){if(a=t+l.textContent.length,t<=e&&a>=e)return{node:l,offset:e-t};t=a}t:{for(;l;){if(l.nextSibling){l=l.nextSibling;break t}l=l.parentNode}l=void 0}l=Fr(l)}}function $r(t,e){return t&&e?t===e?!0:t&&t.nodeType===3?!1:e&&e.nodeType===3?$r(t,e.parentNode):"contains"in t?t.contains(e):t.compareDocumentPosition?!!(t.compareDocumentPosition(e)&16):!1:!1}function Ir(t){t=t!=null&&t.ownerDocument!=null&&t.ownerDocument.defaultView!=null?t.ownerDocument.defaultView:window;for(var e=Fc(t.document);e instanceof t.HTMLIFrameElement;){try{var l=typeof e.contentWindow.location.href=="string"}catch{l=!1}if(l)t=e.contentWindow;else break;e=Fc(t.document)}return e}function Wc(t){var e=t&&t.nodeName&&t.nodeName.toLowerCase();return e&&(e==="input"&&(t.type==="text"||t.type==="search"||t.type==="tel"||t.type==="url"||t.type==="password")||e==="textarea"||t.contentEditable==="true")}var wv=Il&&"documentMode"in document&&11>=document.documentMode,_n=null,$c=null,Eu=null,Ic=!1;function Pr(t,e,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Ic||_n==null||_n!==Fc(a)||(a=_n,"selectionStart"in a&&Wc(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Eu&&_u(Eu,a)||(Eu=a,a=Sc($c,"onSelect"),0>=c,n-=c,ql=1<<32-Ne(e)+n|l<it?(fe=I,I=null):fe=I.sibling;var Nt=g(S,I,j[it],M);if(Nt===null){I===null&&(I=fe);break}t&&I&&Nt.alternate===null&&e(S,I),h=u(Nt,h,it),Tt===null?Q=Nt:Tt.sibling=Nt,Tt=Nt,I=fe}if(it===j.length)return l(S,I),ht&&la(S,it),Q;if(I===null){for(;itit?(fe=I,I=null):fe=I.sibling;var wa=g(S,I,Nt.value,M);if(wa===null){I===null&&(I=fe);break}t&&I&&wa.alternate===null&&e(S,I),h=u(wa,h,it),Tt===null?Q=wa:Tt.sibling=wa,Tt=wa,I=fe}if(Nt.done)return l(S,I),ht&&la(S,it),Q;if(I===null){for(;!Nt.done;it++,Nt=j.next())Nt=z(S,Nt.value,M),Nt!==null&&(h=u(Nt,h,it),Tt===null?Q=Nt:Tt.sibling=Nt,Tt=Nt);return ht&&la(S,it),Q}for(I=a(I);!Nt.done;it++,Nt=j.next())Nt=T(I,S,it,Nt.value,M),Nt!==null&&(t&&(fe=Nt.alternate,fe!==null&&I.delete(fe.key===null?it:fe.key)),h=u(Nt,h,it),Tt===null?Q=Nt:Tt.sibling=Nt,Tt=Nt);return t&&I.forEach(function(My){return e(S,My)}),ht&&la(S,it),Q}function rt(S,h,j,M){if(typeof j=="object"&&j!==null&&j.type===Vt&&j.key===null&&j.props.ref===void 0&&(j=j.props.children),typeof j=="object"&&j!==null){switch(j.$$typeof){case re:t:{for(var Q=j.key;h!==null;){if(h.key===Q){if(Q=j.type,Q===Vt){if(h.tag===7){l(S,h.sibling),M=n(h,j.props.children),ba(M,j),M.return=S,S=M;break t}}else if(h.elementType===Q||typeof Q=="object"&&Q!==null&&Q.$$typeof===St&&ln(Q)===h.type){l(S,h.sibling),M=n(h,j.props),ba(M,j),M.return=S,S=M;break t}l(S,h);break}else e(S,h);h=h.sibling}j.type===Vt?(M=Fa(j.props.children,S.mode,M,j.key),ba(M,j),M.return=S,S=M):(M=Ti(j.type,j.key,j.props,null,S.mode,M),ba(M,j),M.return=S,S=M)}return c(S);case he:t:{for(Q=j.key;h!==null;){if(h.key===Q)if(h.tag===4&&h.stateNode.containerInfo===j.containerInfo&&h.stateNode.implementation===j.implementation){l(S,h.sibling),M=n(h,j.children||[]),M.return=S,S=M;break t}else{l(S,h);break}else e(S,h);h=h.sibling}M=us(j,S.mode,M),M.return=S,S=M}return c(S);case St:return j=ln(j),rt(S,h,j,M)}if(_t(j))return q(S,h,j,M);if(F(j)){if(Q=F(j),typeof Q!="function")throw Error(o(150));return j=Q.call(j),Z(S,h,j,M)}if(typeof j.then=="function")return rt(S,h,Di(j),M);if(j.$$typeof===vt)return rt(S,h,Oi(S,j),M);Ui(S,j)}return typeof j=="string"&&j!==""||typeof j=="number"||typeof j=="bigint"?(j=""+j,h!==null&&h.tag===6?(l(S,h.sibling),M=n(h,j),M.return=S,S=M):(l(S,h),M=ns(j,S.mode,M),M.return=S,S=M),c(S)):l(S,h)}return function(S,h,j,M){try{zu=0;var Q=rt(S,h,j,M);return Dn=null,Q}catch(I){if(I===Rn||I===zi)throw I;var Tt=Ke(29,I,null,S.mode);return Tt.lanes=M,Tt.return=S,Tt}finally{}}}var nn=_o(!0),Eo=_o(!1),xa=!1;function vs(t){t.updateQueue={baseState:t.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function ys(t,e){t=t.updateQueue,e.updateQueue===t&&(e.updateQueue={baseState:t.baseState,firstBaseUpdate:t.firstBaseUpdate,lastBaseUpdate:t.lastBaseUpdate,shared:t.shared,callbacks:null})}function ja(t){return{lane:t,tag:0,payload:null,callback:null,next:null}}function Ta(t,e,l){var a=t.updateQueue;if(a===null)return null;if(a=a.shared,(Ot&2)!==0){var n=a.pending;return n===null?e.next=e:(e.next=n.next,n.next=e),a.pending=e,e=ji(t),co(t,null,l),e}return xi(t,a,e,l),ji(t)}function Ru(t,e,l){if(e=e.updateQueue,e!==null&&(e=e.shared,(l&4194048)!==0)){var a=e.lanes;a&=t.pendingLanes,l|=a,e.lanes=l,hn(t,l)}}function gs(t,e){var l=t.updateQueue,a=t.alternate;if(a!==null&&(a=a.updateQueue,l===a)){var n=null,u=null;if(l=l.firstBaseUpdate,l!==null){do{var c={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};u===null?n=u=c:u=u.next=c,l=l.next}while(l!==null);u===null?n=u=e:u=u.next=e}else n=u=e;l={baseState:a.baseState,firstBaseUpdate:n,lastBaseUpdate:u,shared:a.shared,callbacks:a.callbacks},t.updateQueue=l;return}t=l.lastBaseUpdate,t===null?l.firstBaseUpdate=e:t.next=e,l.lastBaseUpdate=e}var Ss=!1;function Du(){if(Ss){var t=zn;if(t!==null)throw t}}function Uu(t,e,l,a){Ss=!1;var n=t.updateQueue;xa=!1;var u=n.firstBaseUpdate,c=n.lastBaseUpdate,f=n.shared.pending;if(f!==null){n.shared.pending=null;var d=f,p=d.next;d.next=null,c===null?u=p:c.next=p,c=d;var E=t.alternate;E!==null&&(E=E.updateQueue,f=E.lastBaseUpdate,f!==c&&(f===null?E.firstBaseUpdate=p:f.next=p,E.lastBaseUpdate=d))}if(u!==null){var z=n.baseState;c=0,E=p=d=null,f=u;do{var g=f.lane&-536870913,T=g!==f.lane;if(T?(jt&g)===g:(a&g)===g){g!==0&&g===tn&&(Ss=!0),E!==null&&(E=E.next={lane:0,tag:f.tag,payload:f.payload,callback:null,next:null});t:{var q=t,Z=f;g=e;var rt=l;switch(Z.tag){case 1:if(q=Z.payload,typeof q=="function"){z=q.call(rt,z,g);break t}z=q;break t;case 3:q.flags=q.flags&-65537|128;case 0:if(q=Z.payload,g=typeof q=="function"?q.call(rt,z,g):q,g==null)break t;z=ct({},z,g);break t;case 2:xa=!0}}g=f.callback,g!==null&&(t.flags|=64,T&&(t.flags|=8192),T=n.callbacks,T===null?n.callbacks=[g]:T.push(g))}else T={lane:g,tag:f.tag,payload:f.payload,callback:f.callback,next:null},E===null?(p=E=T,d=z):E=E.next=T,c|=g;if(f=f.next,f===null){if(f=n.shared.pending,f===null)break;T=f,f=T.next,T.next=null,n.lastBaseUpdate=T,n.shared.pending=null}}while(!0);E===null&&(d=z),n.baseState=d,n.firstBaseUpdate=p,n.lastBaseUpdate=E,u===null&&(n.shared.lanes=0),Ma|=c,t.lanes=c,t.memoizedState=z}}function No(t,e){if(typeof t!="function")throw Error(o(191,t));t.call(e)}function Co(t,e){var l=t.callbacks;if(l!==null)for(t.callbacks=null,t=0;tu?u:8;var c=V.T,f={};f.types=c!==null?c.types:null,V.T=f,Ys(t,!1,e,l);try{var d=n(),p=V.S;if(p!==null&&p(f,d),d!==null&&typeof d=="object"&&typeof d.then=="function"){var E=Wv(d,a);Yu(t,e,E,il(t))}else Yu(t,e,a,il(t))}catch(z){Yu(t,e,{then:function(){},status:"rejected",reason:z},il())}finally{ut.p=u,c!==null&&f.types!==null&&(c.types=f.types),V.T=c}}function l0(){}function Bs(t,e,l,a){if(t.tag!==5)throw Error(o(476));var n=ud(t).queue;nd(t,n,e,ae,l===null?l0:function(){return id(t),l(a)})}function ud(t){var e=t.memoizedState;if(e!==null)return e;e={memoizedState:ae,baseState:ae,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ia,lastRenderedState:ae},next:null};var l={};return e.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ia,lastRenderedState:l},next:null},t.memoizedState=e,t=t.alternate,t!==null&&(t.memoizedState=e),e}function id(t){var e=ud(t);e.next===null&&(e=t.alternate.memoizedState),Yu(t,e.next.queue,{},il())}function qs(){return Ce(eu)}function cd(){return ee().memoizedState}function sd(){return ee().memoizedState}function a0(t){for(var e=t.return;e!==null;){switch(e.tag){case 24:case 3:var l=il();t=ja(l);var a=Ta(e,t,l);a!==null&&($e(a,e,l),Ru(a,e,l)),e={cache:os()},t.payload=e;return}e=e.return}}function n0(t,e,l){var a=il();l={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Vi(t)?rd(e,l):(l=ls(t,e,l,a),l!==null&&($e(l,t,a),od(l,e,a)))}function fd(t,e,l){var a=il();Yu(t,e,l,a)}function Yu(t,e,l,a){var n={lane:a,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Vi(t))rd(e,n);else{var u=t.alternate;if(t.lanes===0&&(u===null||u.lanes===0)&&(u=e.lastRenderedReducer,u!==null))try{var c=e.lastRenderedState,f=u(c,l);if(n.hasEagerState=!0,n.eagerState=f,el(f,c))return xi(t,e,n,0),wt===null&&bi(),!1}catch{}finally{}if(l=ls(t,e,n,a),l!==null)return $e(l,t,a),od(l,e,a),!0}return!1}function Ys(t,e,l,a){if(a={lane:2,revertLane:Of(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},Vi(t)){if(e)throw Error(o(479))}else e=ls(t,l,a,2),e!==null&&$e(e,t,2)}function Vi(t){var e=t.alternate;return t===ft||e!==null&&e===ft}function rd(t,e){Un=qi=!0;var l=t.pending;l===null?e.next=e:(e.next=l.next,l.next=e),t.pending=e}function od(t,e,l){if((l&4194048)!==0){var a=e.lanes;a&=t.pendingLanes,l|=a,e.lanes=l,hn(t,l)}}var Li={readContext:Ce,use:Gi,useCallback:It,useContext:It,useEffect:It,useImperativeHandle:It,useLayoutEffect:It,useInsertionEffect:It,useMemo:It,useReducer:It,useRef:It,useState:It,useDebugValue:It,useDeferredValue:It,useTransition:It,useSyncExternalStore:It,useId:It,useHostTransitionStatus:It,useFormState:It,useActionState:It,useOptimistic:It,useMemoCache:It,useCacheRefresh:It,useEffectEvent:It},dd={readContext:Ce,use:Gi,useCallback:function(t,e){return we().memoizedState=[t,e===void 0?null:e],t},useContext:Ce,useEffect:Fo,useImperativeHandle:function(t,e,l){l=l!=null?l.concat([t]):null,Qi(4194308,4,Po.bind(null,e,t),l)},useLayoutEffect:function(t,e){return Qi(4194308,4,t,e)},useInsertionEffect:function(t,e){Qi(4,2,t,e)},useMemo:function(t,e){var l=we();e=e===void 0?null:e;var a=t();if(un){rl(!0);try{t()}finally{rl(!1)}}return l.memoizedState=[a,e],a},useReducer:function(t,e,l){var a=we();if(l!==void 0){var n=l(e);if(un){rl(!0);try{l(e)}finally{rl(!1)}}}else n=e;return a.memoizedState=a.baseState=n,t={pending:null,lanes:0,dispatch:null,lastRenderedReducer:t,lastRenderedState:n},a.queue=t,t=t.dispatch=n0.bind(null,ft,t),[a.memoizedState,t]},useRef:function(t){var e=we();return t={current:t},e.memoizedState=t},useState:function(t){t=zs(t);var e=t.queue,l=fd.bind(null,ft,e);return e.dispatch=l,[t.memoizedState,l]},useDebugValue:Us,useDeferredValue:function(t,e){var l=we();return Hs(l,t,e)},useTransition:function(){var t=zs(!1);return t=nd.bind(null,ft,t.queue,!0,!1),we().memoizedState=t,[!1,t]},useSyncExternalStore:function(t,e,l){var a=ft,n=we();if(ht){if(l===void 0)throw Error(o(407));l=l()}else{if(l=e(),wt===null)throw Error(o(349));(jt&127)!==0||Do(a,e,l)}n.memoizedState=l;var u={value:l,getSnapshot:e};return n.queue=u,Fo(Ho.bind(null,a,u,t),[t]),a.flags|=2048,Bn(9,{destroy:void 0},Uo.bind(null,a,u,l,e),null),l},useId:function(){var t=we(),e=wt.identifierPrefix;if(ht){var l=Yl,a=ql;l=(a&~(1<<32-Ne(a)-1)).toString(32)+l,e="_"+e+"R_"+l,l=Yi++,0<\/script>",u=u.removeChild(u.firstChild);break;case"select":u=typeof a.is=="string"?c.createElement("select",{is:a.is}):c.createElement("select"),a.multiple?u.multiple=!0:a.size&&(u.size=a.size);break;default:u=typeof a.is=="string"?c.createElement(n,{is:a.is}):c.createElement(n)}}u[de]=e,u[Ze]=a;t:for(c=e.child;c!==null;){if(c.tag===5||c.tag===6)u.appendChild(c.stateNode);else if(c.tag!==4&&c.tag!==27&&c.child!==null){c.child.return=c,c=c.child;continue}if(c===e)break t;for(;c.sibling===null;){if(c.return===null||c.return===e)break t;c=c.return}c.sibling.return=c.return,c=c.sibling}e.stateNode=u;t:switch(ze(u,n,a),n){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break t;case"img":a=!0;break t;default:a=!1}a&&sa(e)}}return Qt(e),e.subtreeFlags&=-33554433,$s(e,e.type,t===null?null:t.memoizedProps,e.pendingProps,l),null;case 6:if(t&&e.stateNode!=null)t.memoizedProps!==a&&sa(e);else{if(typeof a!="string"&&e.stateNode===null)throw Error(o(166));if(t=ye.current,Mn(e)){if(t=e.stateNode,l=e.memoizedProps,a=null,n=xe,n!==null)switch(n.tag){case 27:case 5:a=n.memoizedProps}t[de]=e,t=!!(t.nodeValue===l||a!==null&&a.suppressHydrationWarning===!0||Hm(t.nodeValue,l)),t||Sa(e,!0)}else t=$u(t).createTextNode(a),t[de]=e,e.stateNode=t}return Qt(e),null;case 31:if(l=e.memoizedState,t===null||t.memoizedState!==null){if(a=Mn(e),l!==null){if(t===null){if(!a)throw Error(o(318));if(t=e.memoizedState,t=t!==null?t.dehydrated:null,!t)throw Error(o(557));t[de]=e}else Wa(),(e.flags&128)===0&&(e.memoizedState=null),e.flags|=4;Qt(e),t=!1}else l=ss(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=l),t=!0;if(!t)return e.flags&256?(ll(e),e):(ll(e),null);if((e.flags&128)!==0)throw Error(o(558))}return Qt(e),null;case 13:if(a=e.memoizedState,t===null||t.memoizedState!==null&&t.memoizedState.dehydrated!==null){if(n=Mn(e),a!==null&&a.dehydrated!==null){if(t===null){if(!n)throw Error(o(318));if(n=e.memoizedState,n=n!==null?n.dehydrated:null,!n)throw Error(o(317));n[de]=e}else Wa(),(e.flags&128)===0&&(e.memoizedState=null),e.flags|=4;Qt(e),n=!1}else n=ss(),t!==null&&t.memoizedState!==null&&(t.memoizedState.hydrationErrors=n),n=!0;if(!n)return e.flags&256?(ll(e),e):(ll(e),null)}return ll(e),(e.flags&128)!==0?(e.lanes=l,e):(l=a!==null,t=t!==null&&t.memoizedState!==null,l&&(a=e.child,n=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(n=a.alternate.memoizedState.cachePool.pool),u=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(u=a.memoizedState.cachePool.pool),u!==n&&(a.flags|=2048)),l!==t&&l&&(e.child.flags|=8192),$i(e,e.updateQueue),Qt(e),null);case 4:return zl(),t===null&&Df(e.stateNode.containerInfo),e.flags|=67108864,Qt(e),null;case 10:return na(e.type),Qt(e),null;case 19:if(js(e),a=e.memoizedState,a===null)return Qt(e),null;if(n=(e.flags&128)!==0,u=a.rendering,u===null)if(n)Gu(a,!1);else{if(Pt!==0||t!==null&&(t.flags&128)!==0)for(t=e.child;t!==null;){if(u=Bi(t),u!==null){for(e.flags|=128,Gu(a,!1),t=u.updateQueue,e.updateQueue=t,$i(e,t),e.subtreeFlags=0,t=l,l=e.child;l!==null;)so(l,t),l=l.sibling;return Hu(e,Oe.current&1|2),ht&&la(e,a.treeForkCount),e.child}t=t.sibling}a.tail!==null&&Gt()>fc&&(e.flags|=128,n=!0,Gu(a,!1),e.lanes=4194304)}else{if(!n)if(t=Bi(u),t!==null){if(e.flags|=128,n=!0,t=t.updateQueue,e.updateQueue=t,$i(e,t),Gu(a,!0),a.tail===null&&a.tailMode!=="collapsed"&&a.tailMode!=="visible"&&!u.alternate&&!ht)return Qt(e),null}else 2*Gt()-a.renderingStartTime>fc&&l!==536870912&&(e.flags|=128,n=!0,Gu(a,!1),e.lanes=4194304);a.isBackwards?(u.sibling=e.child,e.child=u):(t=a.last,t!==null?t.sibling=u:e.child=u,a.last=u)}if(a.tail!==null){t=a.tail;t:{for(l=t;l!==null;){if(l.alternate!==null){l=!1;break t}l=l.sibling}l=!0}return a.rendering=t,a.tail=t.sibling,a.renderingStartTime=Gt(),t.sibling=null,u=Oe.current,u=n?u&1|2:u&1,a.tailMode==="visible"||a.tailMode==="collapsed"||!l||ht?Hu(e,u):(l=u,Rt(Ae,e),Rt(Oe,l),He===null&&(He=e)),ht&&la(e,a.treeForkCount),t}return Qt(e),null;case 22:case 23:return ll(e),bs(),a=e.memoizedState!==null,t!==null?t.memoizedState!==null!==a&&(e.flags|=8192):a&&(e.flags|=8192),a?(l&536870912)!==0&&(e.flags&128)===0&&(Qt(e),e.subtreeFlags&6&&(e.flags|=8192)):Qt(e),l=e.updateQueue,l!==null&&$i(e,l.retryQueue),l=null,t!==null&&t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(l=t.memoizedState.cachePool.pool),a=null,e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(a=e.memoizedState.cachePool.pool),a!==l&&(e.flags|=2048),t!==null&&Wt(en),null;case 24:return l=null,t!==null&&(l=t.memoizedState.cache),e.memoizedState.cache!==l&&(e.flags|=2048),na(ie),Qt(e),null;case 25:return null;case 30:return e.flags|=33554432,Qt(e),null}throw Error(o(156,e.tag))}function o0(t,e){switch(is(e),e.tag){case 1:return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 3:return na(ie),zl(),t=e.flags,(t&65536)!==0&&(t&128)===0?(e.flags=t&-65537|128,e):null;case 26:case 27:case 5:return jl(e),null;case 31:if(e.memoizedState!==null){if(ll(e),e.alternate===null)throw Error(o(340));Wa()}return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 13:if(ll(e),t=e.memoizedState,t!==null&&t.dehydrated!==null){if(e.alternate===null)throw Error(o(340));Wa()}return t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 19:return js(e),t=e.flags,t&65536?(e.flags=t&-65537|128,t=e.memoizedState,t!==null&&(t.rendering=null,t.tail=null),e.flags|=4,e):null;case 4:return zl(),null;case 10:return na(e.type),null;case 22:case 23:return ll(e),bs(),t!==null&&Wt(en),t=e.flags,t&65536?(e.flags=t&-65537|128,e):null;case 24:return na(ie),null;case 25:return null;default:return null}}function qd(t,e){switch(is(e),e.tag){case 3:na(ie),zl();break;case 26:case 27:case 5:jl(e);break;case 4:zl();break;case 31:e.memoizedState!==null&&ll(e);break;case 13:ll(e);break;case 19:js(e);break;case 10:na(e.type);break;case 22:case 23:ll(e),bs(),t!==null&&Wt(en);break;case 24:na(ie)}}function ku(t,e){try{var l=e.updateQueue,a=l!==null?l.lastEffect:null;if(a!==null){var n=a.next;l=n;do{if((l.tag&t)===t){a=void 0;var u=l.create,c=l.inst;a=u(),c.destroy=a}l=l.next}while(l!==n)}}catch(f){Bt(e,e.return,f)}}function Ca(t,e,l){try{var a=e.updateQueue,n=a!==null?a.lastEffect:null;if(n!==null){var u=n.next;a=u;do{if((a.tag&t)===t){var c=a.inst,f=c.destroy;if(f!==void 0){c.destroy=void 0,n=e;var d=l,p=f;try{p()}catch(E){Bt(n,d,E)}}}a=a.next}while(a!==u)}}catch(E){Bt(e,e.return,E)}}function Yd(t){var e=t.updateQueue;if(e!==null){var l=t.stateNode;try{Co(e,l)}catch(a){Bt(t,t.return,a)}}}function wd(t,e,l){l.props=cn(t.type,t.memoizedProps),l.state=t.memoizedState;try{l.componentWillUnmount()}catch(a){Bt(t,e,a)}}function wl(t,e){try{var l=t.ref;if(l!==null){switch(t.tag){case 26:case 27:case 5:var a=t.stateNode;break;case 30:var n=t.stateNode,u=Pl(t.memoizedProps,n);(n.ref===null||n.ref.name!==u)&&(n.ref=Zm(u)),a=n.ref;break;case 7:if(t.stateNode===null){var c=new cl(t);b(t.child,!1,ey,c,void 0,void 0),t.stateNode=c}a=t.stateNode;break;default:a=t.stateNode}typeof l=="function"?t.refCleanup=l(a):l.current=a}}catch(f){Bt(t,e,f)}}function Me(t,e){var l=t.ref,a=t.refCleanup;if(l!==null)if(typeof a=="function")try{a()}catch(n){Bt(t,e,n)}finally{t.refCleanup=null,t=t.alternate,t!=null&&(t.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(n){Bt(t,e,n)}else l.current=null}function Ii(t,e){if((t.tag===5||t.tag===27||t.tag===6)&&t.alternate===null&&e!==null)for(var l=0;l title"))),ze(a,e,l),a[de]=t,be(a),e=a;break t;case"link":if(u=fh("link","href",n).get(e+(l.href||""))){for(c=0;crt&&(c=rt,rt=Z,Z=c);var S=Wr(f,Z),h=Wr(f,rt);if(S&&h&&(T.rangeCount!==1||T.anchorNode!==S.node||T.anchorOffset!==S.offset||T.focusNode!==h.node||T.focusOffset!==h.offset)){var j=z.createRange();j.setStart(S.node,S.offset),T.removeAllRanges(),Z>rt?(T.addRange(j),T.extend(h.node,h.offset)):(j.setEnd(h.node,h.offset),T.addRange(j))}}}}for(z=[],T=f;T=T.parentNode;)T.nodeType===1&&z.push({element:T,left:T.scrollLeft,top:T.scrollTop});for(typeof f.focus=="function"&&f.focus(),f=0;fl?32:l,V.T=null,l=pf,pf=null;var u=Al,c=Ll;if(Kt=0,on=Al=null,Ll=0,(Ot&6)!==0)throw Error(o(331));var f=Ot;if(Ot|=4,sm(u.current),um(u,u.current,c,l),Ot=f,Ju(0,!1),Ee&&typeof Ee.onPostCommitFiberRoot=="function")try{Ee.onPostCommitFiberRoot(Fl,u)}catch{}return!0}finally{ut.p=n,V.T=a,Tm(t,e)}}function _m(t,e,l){e=ml(l,e),e=ks(t.stateNode,e,2),t=Ta(t,e,2),t!==null&&(pe(t,2),Zl(t))}function Bt(t,e,l){if(t.tag===3)_m(t,t,l);else for(;e!==null;){if(e.tag===3){_m(e,t,l);break}else if(e.tag===1){var a=e.stateNode;if(typeof e.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(za===null||!za.has(a))){t=ml(l,t),l=bd(2),a=Ta(e,l,2),a!==null&&(xd(l,a,e,t),pe(a,2),Zl(a));break}}e=e.return}}function Nf(t,e,l){var a=t.pingCache;if(a===null){a=t.pingCache=new v0;var n=new Set;a.set(e,n)}else n=a.get(e),n===void 0&&(n=new Set,a.set(e,n));n.has(l)||(yf=!0,n.add(l),t=T0.bind(null,t,e,l),e.then(t,t))}function T0(t,e,l){var a=t.pingCache;a!==null&&a.delete(e),t.pingedLanes|=t.suspendedLanes&l,t.warmLanes&=~l,wt===t&&(jt&l)===l&&((Pt===4||Pt===3&&(jt&62914560)===jt&&300>Gt()-sc)&&(Ot&2)===0?Kn(t,0):cc|=l,Qn===jt&&(Qn=0)),Zl(t)}function Em(t,e){e===0&&(e=Et()),t=Ja(t,e),t!==null&&(pe(t,e),Zl(t))}function _0(t){var e=t.memoizedState,l=0;e!==null&&(l=e.retryLane),Em(t,l)}function E0(t,e){var l=0;switch(t.tag){case 31:case 13:var a=t.stateNode,n=t.memoizedState;n!==null&&(l=n.retryLane);break;case 19:a=t.stateNode;break;case 22:a=t.stateNode._retryCache;break;default:throw Error(o(314))}a!==null&&a.delete(e),Em(t,l)}function N0(t,e){return Pe(t,e)}var Fn=null,Wn=null,Cf=!1,yc=!1,Af=!1,Da=0;function Zl(t){t!==Wn&&t.next===null&&(Wn===null?Fn=Wn=t:Wn=Wn.next=t),yc=!0,Cf||(Cf=!0,A0())}function Ju(t,e){if(!Af&&yc){Af=!0;do for(var l=!1,a=Fn;a!==null;){if(t!==0){var n=a.pendingLanes;if(n===0)var u=0;else{var c=a.suspendedLanes,f=a.pingedLanes;u=(1<<31-Ne(42|t)+1)-1,u&=n&~(c&~f),u=u&201326741?u&201326741|1:u?u|2:0}u!==0&&(l=!0,Om(a,u))}else u=jt,u=O(a,a===wt?u:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(u&3)===0||k(a,u)||(l=!0,Om(a,u));a=a.next}while(l);Af=!1}}function C0(){Nm()}function Nm(){yc=Cf=!1;var t=0;Da!==0&&w0()&&(t=Da);for(var e=Gt(),l=null,a=Fn;a!==null;){var n=a.next,u=Cm(a,e);u===0?(a.next=null,l===null?Fn=n:l.next=n,n===null&&(Wn=l)):(l=a,(t!==0||(u&3)!==0)&&(yc=!0)),a=n}Kt!==0&&Kt!==5||Ju(t),Da!==0&&(Da=0)}function Cm(t,e){for(var l=t.suspendedLanes,a=t.pingedLanes,n=t.expirationTimes,u=t.pendingLanes&-62914561;0f)break;var E=d.transferSize,z=d.initiatorType;E&&Bm(z)&&(d=d.responseEnd,c+=E*(dxc){Z.length=q;break}j=new Promise(L0.bind(j)),Z.push(j)}}}if(0"u"?null:document;function uh(t,e,l){var a=In;if(a&&typeof e=="string"&&e){var n=ol(e);n='link[rel="'+t+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),nh.has(n)||(nh.add(n),t={rel:t,crossOrigin:l,href:e},a.querySelector(n)===null&&(e=a.createElement("link"),ze(e,"link",t),be(e),a.head.appendChild(e)))}}function ry(t){ra.D(t),uh("dns-prefetch",t,null)}function oy(t,e){ra.C(t,e),uh("preconnect",t,e)}function dy(t,e,l){ra.L(t,e,l);var a=In;if(a&&t&&e){var n='link[rel="preload"][as="'+ol(e)+'"]';e==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+ol(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+ol(l.imageSizes)+'"]')):n+='[href="'+ol(t)+'"]';var u=n;switch(e){case"style":u=Pn(t);break;case"script":u=tu(t)}if(!(pl.has(u)||(t=ct({rel:"preload",href:e==="image"&&l&&l.imageSrcSet?void 0:t,as:e},l),pl.set(u,t),a.querySelector(n)!==null||e==="style"&&a.querySelector(Pu(u))||e==="script"&&a.querySelector(ti(u))))){var c=a.createElement("link");ze(c,"link",t),e==="style"&&(c[si]=!0,c.onload=c.onerror=function(){gr(c)}),be(c),a.head.appendChild(c)}}}function my(t,e){ra.m(t,e);var l=In;if(l&&t){var a=e&&typeof e.as=="string"?e.as:"script",n='link[rel="modulepreload"][as="'+ol(a)+'"][href="'+ol(t)+'"]',u=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":u=tu(t)}if(!pl.has(u)&&(t=ct({rel:"modulepreload",href:t},e),pl.set(u,t),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ti(u)))return}a=l.createElement("link"),ze(a,"link",t),be(a),l.head.appendChild(a)}}}function hy(t,e,l){ra.S(t,e,l);var a=In;if(a&&t){var n=gn(a).hoistableStyles,u=Pn(t);e=e||"default";var c=n.get(u);if(!c){var f={loading:0,preload:null};if(c=a.querySelector(Pu(u)))f.loading=5;else{t=ct({rel:"stylesheet",href:t,"data-precedence":e},l),(l=pl.get(u))&&Ff(t,l);var d=c=a.createElement("link");be(d),ze(d,"link",t),d._p=new Promise(function(p,E){d.onload=p,d.onerror=E}),d.addEventListener("load",function(){f.loading|=1}),d.addEventListener("error",function(){f.loading|=2}),f.loading|=4,pc(c,e,a)}c={type:"stylesheet",instance:c,count:1,state:f},n.set(u,c)}}}function vy(t,e){ra.X(t,e);var l=In;if(l&&t){var a=gn(l).hoistableScripts,n=tu(t),u=a.get(n);u||(u=l.querySelector(ti(n)),u||(t=ct({src:t,async:!0},e),(e=pl.get(n))&&Wf(t,e),u=l.createElement("script"),be(u),ze(u,"link",t),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function yy(t,e){ra.M(t,e);var l=In;if(l&&t){var a=gn(l).hoistableScripts,n=tu(t),u=a.get(n);u||(u=l.querySelector(ti(n)),u||(t=ct({src:t,async:!0,type:"module"},e),(e=pl.get(n))&&Wf(t,e),u=l.createElement("script"),be(u),ze(u,"link",t),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function ih(t,e,l,a){var n=(n=ye.current)?Iu(n):null;if(!n)throw Error(o(446));switch(t){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(l=Pn(l.href),e=gn(n).hoistableStyles,a=e.get(l),a||(a={type:"style",instance:null,count:0,state:null},e.set(l,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){t=Pn(l.href);var u=gn(n).hoistableStyles,c=u.get(t);if(c||(n=n.ownerDocument||n,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},u.set(t,c),(u=n.querySelector(Pu(t)))?u._p||(c.instance=u,c.state.loading=5):(u=pl.get(t),u||(u={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},pl.set(t,u)),gy(n,t,u,c.state))),e&&a===null)throw Error(o(528,""));return c}if(e&&a!==null)throw Error(o(529,""));return null;case"script":return e=l.async,l=l.src,typeof l=="string"&&e&&typeof e!="function"&&typeof e!="symbol"?(l=tu(l),e=gn(n).hoistableScripts,a=e.get(l),a||(a={type:"script",instance:null,count:0,state:null},e.set(l,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,t))}}function Pn(t){return'href="'+ol(t)+'"'}function Pu(t){return'link[rel="stylesheet"]['+t+"]"}function ch(t){return ct({},t,{"data-precedence":t.precedence,precedence:null})}function gy(t,e,l,a){if(e=t.querySelector('link[rel="preload"][as="style"]['+e+"]")){if(e[si]!==!0){a.loading=1;return}}else e=t.createElement("link"),e[si]=!0,e.onload=e.onerror=gr.bind(null,e),ze(e,"link",l),be(e),t.head.appendChild(e);a.preload=e,e.addEventListener("load",function(){return a.loading|=1}),e.addEventListener("error",function(){return a.loading|=2})}function tu(t){return'[src="'+ol(t)+'"]'}function ti(t){return"script[async]"+t}function sh(t,e,l){if(e.count++,e.instance===null)switch(e.type){case"style":var a=t.querySelector('style[data-href~="'+ol(l.href)+'"]');if(a)return e.instance=a,be(a),a;var n=ct({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(t.ownerDocument||t).createElement("style"),be(a),ze(a,"style",n),pc(a,l.precedence,t),e.instance=a;case"stylesheet":n=Pn(l.href);var u=t.querySelector(Pu(n));if(u)return e.state.loading|=4,e.instance=u,be(u),u;a=ch(l),(n=pl.get(n))&&Ff(a,n),u=(t.ownerDocument||t).createElement("link"),be(u);var c=u;return c._p=new Promise(function(f,d){c.onload=f,c.onerror=d}),ze(u,"link",a),e.state.loading|=4,pc(u,l.precedence,t),e.instance=u;case"script":return u=tu(l.src),(n=t.querySelector(ti(u)))?(e.instance=n,be(n),n):(a=l,(n=pl.get(u))&&(a=ct({},l),Wf(a,n)),t=t.ownerDocument||t,n=t.createElement("script"),be(n),ze(n,"link",a),t.head.appendChild(n),e.instance=n);case"void":return null;default:throw Error(o(443,e.type))}else e.type==="stylesheet"&&(e.state.loading&4)===0&&(a=e.instance,e.state.loading|=4,pc(a,l.precedence,t));return e.instance}function pc(t,e,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,u=n,c=0;c title"):null)}function Sy(t,e,l){if(l===1||e.itemProp!=null)return!1;switch(t){case"meta":case"title":return!0;case"style":if(typeof e.precedence!="string"||typeof e.href!="string"||e.href==="")break;return!0;case"link":if(typeof e.rel!="string"||typeof e.href!="string"||e.href===""||e.onLoad||e.onError)break;switch(e.rel){case"stylesheet":return t=e.disabled,typeof e.precedence=="string"&&t==null;default:return!0}case"script":if(e.async&&typeof e.async!="function"&&typeof e.async!="symbol"&&!e.onLoad&&!e.onError&&e.src&&typeof e.src=="string")return!0}return!1}function rh(t,e){return t==="img"&&e.src!=null&&e.src!==""&&e.onLoad==null&&e.loading!=="lazy"}function oh(t){return!(t.type==="stylesheet"&&(t.state.loading&3)===0)}function dh(t){return(t.width||100)*(t.height||100)*(typeof devicePixelRatio=="number"?devicePixelRatio:1)*.25}function mh(t,e){typeof e.decode=="function"&&(t.imgCount++,e.complete||(t.imgBytes+=dh(e),t.suspenseyImages.push(e)),t=xy.bind(t),e.decode().then(t,t))}function py(t,e,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=Pn(a.href),u=e.querySelector(Pu(n));if(u){e=u._p,e!==null&&typeof e=="object"&&typeof e.then=="function"&&(t.count++,t=ei.bind(t),e.then(t,t)),l.state.loading|=4,l.instance=u,be(u);return}u=e.ownerDocument||e,a=ch(a),(n=pl.get(n))&&Ff(a,n),u=u.createElement("link"),be(u);var c=u;c._p=new Promise(function(f,d){c.onload=f,c.onerror=d}),ze(u,"link",a),l.instance=u}t.stylesheets===null&&(t.stylesheets=new Map),t.stylesheets.set(l,e),(e=l.state.preload)&&(l.state.loading&3)===0&&(t.count++,l=ei.bind(t),e.addEventListener("load",l),e.addEventListener("error",l))}}var xc=0;function by(t,e){return t.stylesheets&&t.count===0&&Tc(t,t.stylesheets),0xc?50:800)+e);return t.unsuspend=l,function(){t.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function hh(t){if(t.count===0&&(t.imgCount===0||!t.waitingForImages)){if(t.stylesheets)Tc(t,t.stylesheets);else if(t.unsuspend){var e=t.unsuspend;t.unsuspend=null,e()}}}function ei(){this.count--,hh(this)}function xy(){this.imgCount--,hh(this)}var jc=null;function Tc(t,e){t.stylesheets=null,t.unsuspend!==null&&(t.count++,jc=new Map,e.forEach(jy,t),jc=null,ei.call(t))}function jy(t,e){if(!(e.state.loading&4)){var l=jc.get(t);if(l)var a=l.get(null);else{l=new Map,jc.set(t,l);for(var n=t.querySelectorAll("link[data-precedence],style[data-precedence]"),u=0;u"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(r){console.error(r)}}return i(),ir.exports=wy(),ir.exports}var ky=Gy();const Qy=wh(ky),Gh=v.createContext(null);function Mt(){const i=v.useContext(Gh);if(!i)throw new Error("ConsoleContext missing");return i}const ot=encodeURIComponent,$={health:"/health",relayModels:"/relay/models",quotaMe:"/users/me/quota",userKeys:"/users/me/keys",userKey:i=>"/users/me/keys/"+ot(i),githubRepos:"/github/repos",projects:"/projects",project:i=>"/projects/"+ot(i),projectMembers:i=>"/projects/"+ot(i)+"/members",projectMember:(i,r)=>"/projects/"+ot(i)+"/members/"+ot(r),projectSkills:i=>"/projects/"+ot(i)+"/skills",projectApps:i=>"/projects/"+ot(i)+"/apps",projectMcp:i=>"/projects/"+ot(i)+"/mcp-servers",projectMcpReload:i=>"/projects/"+ot(i)+"/mcp-servers/reload",projectMcpOauth:(i,r)=>"/projects/"+ot(i)+"/mcp-servers/"+ot(r)+"/oauth-login",projectAutomations:i=>"/projects/"+ot(i)+"/automations",projectAutomationCancel:(i,r)=>"/projects/"+ot(i)+"/automations/"+ot(r)+"/cancel",projectTriage:i=>"/projects/"+ot(i)+"/triage",workers:"/workers",environments:i=>"/environments?project_id="+ot(i),environmentsCreate:"/environments",environmentArchive:i=>"/environments/"+ot(i)+"/archive",tasks:i=>"/tasks?project_id="+ot(i),tasksByParent:(i,r)=>"/tasks?project_id="+ot(i)+"&parent_task_id="+ot(r),tasksCreate:"/tasks",task:i=>"/tasks/"+ot(i),taskAction:(i,r)=>"/tasks/"+ot(i)+"/"+r,taskFork:i=>"/tasks/"+ot(i)+"/fork",taskContinue:i=>"/tasks/"+ot(i)+"/continue",taskTrace:i=>"/tasks/"+ot(i)+"/trace",taskTraceStream:i=>"/tasks/"+ot(i)+"/trace/stream",taskAgents:i=>"/tasks/"+ot(i)+"/agents",taskReviews:i=>"/tasks/"+ot(i)+"/reviews",taskReviewFindings:(i,r)=>"/tasks/"+ot(i)+"/reviews/"+ot(r)+"/findings",taskApprovals:i=>"/tasks/"+ot(i)+"/approvals",taskApprovalDecision:(i,r,m)=>"/tasks/"+ot(i)+"/approvals/"+ot(r)+"/"+m,taskFollowups:i=>"/tasks/"+ot(i)+"/followups",taskChatHistory:i=>"/tasks/"+ot(i)+"/chat-history",taskMessages:i=>"/tasks/"+ot(i)+"/messages",taskMessagesTo:i=>"/tasks/"+ot(i)+"/messages",taskThread:i=>"/tasks/"+ot(i)+"/thread",taskThreads:i=>"/tasks/"+ot(i)+"/threads",taskThreadAction:(i,r)=>"/tasks/"+ot(i)+"/thread/"+r,taskCost:i=>"/tasks/"+ot(i)+"/cost",uploads:"/uploads",adminQuotas:"/admin/quotas",adminQuotaUser:i=>"/admin/quotas?user_id="+ot(i),adminSweep:"/admin/sweep",adminBackup:"/admin/backup"},Xy={exec:"命令",file:"文件",call:"调用",tool:"工具",message:"消息",reasoning:"思考",plan:"计划","agent-start":"子代理","agent-done":"子代理"},uu=["completed","failed","interrupted","merged","merge-failed"],Vy={queued:"排队中,尚未被 worker 认领",running:"运行中,模型回合进行中",completed:"模型回合结束、改动在 worktree 里尚未合并",failed:"模型回合失败,可重试",interrupted:"已被取消/中断,可重试",merged:"控制面已标记 merged,不代表 git 主分支已合入","merge-failed":"合并落盘失败,可重试"},Yh=["low","medium","high","xhigh","max"],Ly=["viewer","contributor","maintainer","owner"],hr="codex-console-key";function bl(){try{return localStorage.getItem(hr)||""}catch{return""}}function Zy(i){localStorage.setItem(hr,i)}function Ky(){localStorage.removeItem(hr)}function De(i){return i?i.slice(0,8):""}function Ga(i){return i?new Date(i*1e3).toLocaleString():""}async function P(i,r="GET",m){const o={"Content-Type":"application/json"},_=bl();_&&(o["X-API-Key"]=_);const C={method:r,headers:o};m!==void 0&&(C.body=JSON.stringify(m));const N=await fetch(i,C);let x=null;try{x=await N.json()}catch{x=null}if(!N.ok){const w=x;let U=w&&w.error?w.error:"HTTP "+N.status;throw N.status===401&&(U+="(key 未填或无效)"),N.status===429&&(U+="(触发限流,稍后再试)"),N.status===402&&(w&&w.unpriced_token_cap!==void 0?U+="(无价 token 已满,联系管理员调整)":w&&w.error==="coordinator_quota_reserve_exceeded"?U="协调员分工预留不足:剩余美元配额不够覆盖全部分工,子任务费用记父任务创建人账,整个父任务已被挡下(未建任何子任务)":U+="(美元配额已满,联系管理员调整)"),new Error(U)}return x}async function Jy(i){const r=new FormData;r.append("paths",JSON.stringify(i.map(_=>_.path))),i.forEach((_,C)=>r.append("file"+C,_.file));const m=await fetch($.uploads,{method:"POST",headers:{"X-API-Key":bl()},body:r}),o=await m.json().catch(()=>({}));if(!m.ok)throw new Error(o&&o.error||"HTTP "+m.status);return o.upload_id}function Fy(i,r,m){const o=[],_={},C=(N,x)=>{if(N)for(let w=0;wN.name),C(r,N=>N.webkitRelativePath||N.name),C(m,N=>N.name),o}function kh(i){const r=Date.now()/1e3;let m=null;if(typeof i.last_seen=="number"?m=r-i.last_seen:typeof i.last_seen_seconds_ago=="number"&&(m=i.last_seen_seconds_ago),(m===null||m<0)&&(m=null),m===null)return{text:"未知",age:null};const o=Math.floor(m);return o<60?{text:o+" 秒前",age:m}:o<3600?{text:Math.floor(o/60)+" 分钟前",age:m}:{text:Math.floor(o/3600)+" 小时前",age:m}}function Mc(i){const r=i.message||"";return r.includes("forbidden")?"没有权限:只有项目 owner 或全局管理员可以管理成员":r.includes("already_member")?"该用户已是成员,改角色请用成员行的下拉框":r.includes("cannot demote the only owner")?"不能把唯一 owner 降为非 owner:请先把另一位成员升为 owner":r.includes("user not found")?"找不到该用户:请核对 user_id 或用户名是否正确":r.includes("member not found")?"该用户不是本项目成员":r.includes("unknown role")?"角色无效:只能是 viewer / contributor / maintainer / owner":r.includes("project not found")?"项目不存在(可能已被删除)":"成员操作失败:"+r}function rr(i){const r=i.message||"";return r.includes("forbidden")?"无全局管理员权限:服务端返回 403(CODEX_GLOBAL_ADMINS 未包含当前用户),请联系管理员":r.includes("user not found")?"找不到该用户:请核对用户 id 是否正确":"管理操作失败:"+r}function or(i){return i==null?"不限额":"$"+(i/1e6).toFixed(2)}function dr(i){const r=Xy[i.kind||""]||i.kind||"?";let m="";return i.kind==="exec"?m=(i.command||"")+"(exit="+(i.exitCode??"")+","+(i.durationMs??"")+"ms,cwd="+(i.cwd||"")+")":i.kind==="file"?m=(i.path||"")+" "+(i.change||"")+" "+(i.status||""):i.kind==="message"?m=(i.phase?"["+i.phase+"] ":"")+(i.text||""):i.kind==="reasoning"?m=i.summary||"":i.kind==="tool"?m=(i.server||"")+"/"+(i.tool||"")+" "+(i.status||""):i.kind==="call"?m=i.name||"":i.kind==="plan"?m=i.text||"":i.kind==="agent-start"?m="开始:"+(i.name||"")+(i.prompt?"("+i.prompt+")":""):i.kind==="agent-done"?m="结束:"+(i.name||"")+" "+(i.status||""):m=JSON.stringify(i).slice(0,300),"["+r+"] "+m}function Wy(){const[i,r]=v.useState(!!bl()),[m,o]=v.useState(bl()?"已保存到本浏览器(只用于调本站 API)":"未填 key,数据接口会返回 401"),[_,C]=v.useState("未加载"),[N,x]=v.useState("未加载"),[w,U]=v.useState("填 key 后判断权限…"),[G,b]=v.useState(!1),[B,tt]=v.useState(""),[at,et]=v.useState(""),[L,dt]=v.useState([]),[zt,Jt]=v.useState(""),[nt,Xt]=v.useState(""),[te,ct]=v.useState([]),[yt,re]=v.useState(null),[he,Vt]=v.useState("未加载"),[Ft,le]=v.useState(""),[Ie,vt]=v.useState([]),[Y,A]=v.useState(""),[lt,gt]=v.useState(""),[St,ve]=v.useState([]),[Ue,_e]=v.useState([]),[y,R]=v.useState([]),[W,F]=v.useState("先选项目"),[pt,mt]=v.useState(""),[_t,V]=v.useState(""),[ut,ae]=v.useState(""),[ka,xl]=v.useState(""),[Xe,Wt]=v.useState([]),[Rt,oe]=v.useState(""),[Kl,ye]=v.useState(""),[oa,Ve]=v.useState(""),[zl,Rl]=v.useState(!1),[jl,Be]=v.useState(""),[ne,ue]=v.useState(""),[sl,Jl]=v.useState([]),[da,Dl]=v.useState(!1),Zt=v.useRef("");Zt.current=zt;const Pe=v.useRef("");Pe.current=ne;const qe=v.useCallback(async()=>{try{const O=await P($.health);x("backend="+O.backend+" db_ok="+O.db_ok+" worker_ok="+O.worker_ok+" commit="+String(O.commit||"").slice(0,7))}catch(O){x("加载失败:"+O.message)}},[]),Tl=v.useCallback(async()=>{if(!bl()){C("未填 key,配额不显示");return}try{const O=await P($.quotaMe),k=((O.used_usd_micros||0)/1e6).toFixed(2),J=O.quota_usd_micros===null||O.quota_usd_micros===void 0?"美元:本月用量 $"+k+"(不限额)":"美元:本月用量 $"+k+" / $"+((O.quota_usd_micros||0)/1e6).toFixed(2)+"(剩余 $"+((O.remaining_usd_micros||0)/1e6).toFixed(2)+")",At=O.unpriced_token_cap===void 0||O.unpriced_tokens_used===void 0?"无价 token:未返回(旧服务端)":"无价 token:"+O.unpriced_tokens_used+" / "+O.unpriced_token_cap+" tokens";C(J+" | "+At)}catch(O){C("配额加载失败:"+O.message)}},[]),fl=v.useCallback(async()=>{if(!bl()){U("未填 key,管理区不可用"),b(!1);return}try{const O=await fetch($.adminQuotas,{headers:{"X-API-Key":bl()}});O.status===400?(U("已确认为全局管理员,管理操作可用"),b(!0)):O.status===403?(U("管理区仅全局管理员可用:当前 key 无全局管理员权限(服务端返回 403)"),b(!1)):O.status===401?(U("key 无效,管理区不可用(服务端返回 401)"),b(!1)):(U("管理权限判断失败(HTTP "+O.status+"),管理操作暂不可用"),b(!1))}catch(O){U("管理权限判断失败:"+O.message),b(!1)}},[]),Gt=v.useCallback(async()=>{try{const k=(await P($.projects)).projects||[];dt(k),Xt(k.length+" 个项目"),Zt.current&&k.some(J=>J.id===Zt.current)}catch(O){Xt("加载失败:"+O.message)}},[]),Ul=v.useCallback(async()=>{try{const O=await P($.githubRepos);ct(O.repos||[])}catch{}},[]),mn=v.useCallback(async()=>{try{const O=await P($.relayModels);Jl(O.models||[]),Dl(!1)}catch{Dl(!0)}},[]),Qa=v.useCallback(async()=>{try{const O=await P($.workers);if(!Array.isArray(O)&&O.workers===void 0&&O.workers_total!==void 0){re(null),Vt(O.workers_total?"在线 "+O.workers_online+" / 离线 "+O.workers_offline+"(共 "+O.workers_total+";完整 worker 清单仅全局管理员可见)":"无 worker 注册"),le("");return}const k=Array.isArray(O)?O:O.workers||[];re(k),Vt(k.length?"":"无 worker 注册"),le("")}catch(O){le("加载失败:"+O.message)}},[]),ge=v.useCallback(async O=>{const k=O!==void 0?O:Zt.current,J=Pe.current;if(!k){Wt([]),oe(""),ue("");return}try{const Et=(await P($.environments(k))).environments||[];Wt(Et),oe(Et.length+" 个环境"),(J&&Et.some(pe=>pe.id===J&&pe.status==="ready")||J&&Et.some(pe=>pe.id===J))&&ue(J);const Se=L.find(pe=>pe.id===k);Se&&Se.repo_url?(Ve("仓库:"+Se.repo_url),Rl(!1)):Se?(Ve("该项目未绑定仓库,环境无法创建——先选一个仓库保存"),Rl(!0)):(Ve(""),Rl(!1))}catch(At){ye("加载失败:"+At.message)}},[L]),Xa=v.useCallback(async O=>{const k=O!==void 0?O:Zt.current;if(!k){vt([]);return}try{const J=await P($.projectMembers(k));vt(J.members||[]),gt("")}catch(J){gt("成员加载失败:"+Mc(J))}},[]),ma=v.useCallback(async O=>{const k=O!==void 0?O:Zt.current;if(!k){ve([]),_e([]),R([]),F("先选项目");return}F("");try{const J=await P($.projectSkills(k));ve(J.skills||[])}catch(J){mt("技能加载失败:"+J.message)}try{const J=await P($.projectApps(k));_e(J.apps||[])}catch(J){mt("应用加载失败:"+J.message)}try{const J=await P($.projectMcp(k));R(J.servers||J.mcp_servers||[])}catch(J){mt("MCP 服务加载失败:"+J.message)}},[]),su=v.useCallback(O=>{if(!O.trim()){o("key 为空,未保存");return}Zy(O.trim()),r(!0),o("已保存到本浏览器(只用于调本站 API)")},[]),fu=v.useCallback(()=>{Ky(),r(!1),o("未填 key,数据接口会返回 401"),fl()},[fl]),Fl=v.useCallback(async(O,k)=>{if(!O.trim()){Xt("项目名必填");return}const J={name:O.trim()};k.trim()&&(J.repo_url=k.trim());try{await P($.projects,"POST",J),Xt("项目已建"),await Gt()}catch(At){Xt("新建失败:"+At.message)}},[Gt]),Ee=v.useCallback(async(O,k,J)=>{const At=Zt.current;if(!At){ye("先选项目");return}if(!O.trim()){ye("环境名必填");return}const Et={project_id:At,name:O.trim()};k.trim()&&(Et.branch=k.trim()),J&&(Et.executor=J);try{await P($.environmentsCreate,"POST",Et),ye("环境已建,worker 准备中(creating → ready,失败会在列表里写原因)"),await ge(At)}catch(Se){ye("新建失败:"+Se.message)}},[ge]),rl=v.useCallback(async O=>{if(window.confirm("确定归档该环境吗?归档后新任务不能再选它,进行中的任务不受影响(有进行中任务在用它时归档会被拒绝)。"))try{await P($.environmentArchive(O),"POST",{}),await ge()}catch(k){ye("归档失败:"+k.message)}},[ge]),Ne=v.useCallback(async O=>{const k=Zt.current;if(!k){Be("先选项目");return}if(!O){Be("先选一个仓库");return}try{await P($.project(k),"PATCH",{repo_url:O}),Be("仓库已保存,现在可以建环境了"),await Gt(),await ge(k)}catch(J){Be("保存失败:"+J.message)}},[Gt,ge]),ru=v.useCallback(async(O,k)=>{const J=Zt.current;if(!J){A("先选项目");return}if(!O.trim()){A("请填成员 user_id 或用户名");return}try{await P($.projectMembers(J),"POST",{user_id:O.trim(),role:k})}catch(At){if(At.message.includes("user not found"))try{await P($.projectMembers(J),"POST",{username:O.trim(),role:k})}catch(Et){A(Mc(Et));return}else{A(Mc(At));return}}A("已邀请成员"),await Xa(J)},[Xa]),ou=v.useCallback(async(O,k)=>{const J=Zt.current;if(J)try{await P($.projectMember(J,O),"PATCH",{role:k}),vt(At=>At.map(Et=>Et.user_id===O?{...Et,role:k}:Et)),A("角色已改为 "+k)}catch(At){A(Mc(At))}},[]),du=v.useCallback(async()=>{const O=Zt.current;if(!O){V("先选项目");return}try{await P($.projectMcpReload(O),"POST",{}),V("配置已重载"),await ma(O)}catch(k){V("重载失败:"+k.message)}},[ma]),H=v.useCallback(async O=>{const k=Zt.current;if(!k){ae("先选项目");return}if(!O.trim()){ae("服务名不能为空");return}try{const J=await P($.projectMcpOauth(k,O.trim()),"POST",{}),At=J.url||J.auth_url||J.login_url||J.authorization_url||"",Et=J.steps||J.instructions||"";let Se=`登录尚未完成:请在浏览器打开下面的链接或按步骤完成,完成后回到本页刷新 MCP 状态。 +`).replace(H0,"")}function Hm(t,e){return e=Um(e),Um(t)===e}function qt(t,e,l,a,n,u){switch(l){case"children":if(typeof a=="string")e==="body"||e==="textarea"&&a===""||bn(t,a);else if(typeof a=="number"||typeof a=="bigint")e!=="body"&&bn(t,""+a);else return;break;case"className":oi(t,"class",a);break;case"tabIndex":oi(t,"tabindex",a);break;case"dir":case"role":case"viewBox":case"width":case"height":oi(t,l,a);break;case"style":Or(t,a,u);return;case"data":if(e!=="object"){oi(t,"data",a);break}case"src":case"href":if(a===""&&(e!=="a"||l!=="href")){t.removeAttribute(l);break}if(a==null||typeof a=="function"||typeof a=="symbol"||typeof a=="boolean"){t.removeAttribute(l);break}a=di(a),t.setAttribute(l,a);break;case"action":case"formAction":if(typeof a=="function"){t.setAttribute(l,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof u=="function"&&(l==="formAction"?(e!=="input"&&qt(t,e,"name",n.name,n,null),qt(t,e,"formEncType",n.formEncType,n,null),qt(t,e,"formMethod",n.formMethod,n,null),qt(t,e,"formTarget",n.formTarget,n,null)):(qt(t,e,"encType",n.encType,n,null),qt(t,e,"method",n.method,n,null),qt(t,e,"target",n.target,n,null)));if(a==null||typeof a=="symbol"||typeof a=="boolean"){t.removeAttribute(l);break}a=di(a),t.setAttribute(l,a);break;case"onClick":a!=null&&(t.onclick=Bl);return;case"onScroll":a!=null&&xt("scroll",t);return;case"onScrollEnd":a!=null&&xt("scrollend",t);return;case"dangerouslySetInnerHTML":if(a!=null){if(typeof a!="object"||!("__html"in a))throw Error(o(61));if(l=a.__html,l!=null){if(n.children!=null)throw Error(o(60));(u!=null?u.__html:void 0)!==l&&(t.innerHTML=l)}}break;case"multiple":t.multiple=a&&typeof a!="function"&&typeof a!="symbol";break;case"muted":t.muted=a&&typeof a!="function"&&typeof a!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(a==null||typeof a=="function"||typeof a=="boolean"||typeof a=="symbol"){t.removeAttribute("xlink:href");break}l=di(a),t.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",l);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":a!=null&&typeof a!="function"&&typeof a!="symbol"?t.setAttribute(l,a):t.removeAttribute(l);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":a&&typeof a!="function"&&typeof a!="symbol"?t.setAttribute(l,""):t.removeAttribute(l);break;case"capture":case"download":a===!0?t.setAttribute(l,""):a!==!1&&a!=null&&typeof a!="function"&&typeof a!="symbol"?t.setAttribute(l,a):t.removeAttribute(l);break;case"cols":case"rows":case"size":case"span":a!=null&&typeof a!="function"&&typeof a!="symbol"&&!isNaN(a)&&1<=a?t.setAttribute(l,a):t.removeAttribute(l);break;case"rowSpan":case"start":a==null||typeof a=="function"||typeof a=="symbol"||isNaN(a)?t.removeAttribute(l):t.setAttribute(l,a);break;case"popover":xt("beforetoggle",t),xt("toggle",t),ri(t,"popover",a);break;case"xlinkActuate":$l(t,"http://www.w3.org/1999/xlink","xlink:actuate",a);break;case"xlinkArcrole":$l(t,"http://www.w3.org/1999/xlink","xlink:arcrole",a);break;case"xlinkRole":$l(t,"http://www.w3.org/1999/xlink","xlink:role",a);break;case"xlinkShow":$l(t,"http://www.w3.org/1999/xlink","xlink:show",a);break;case"xlinkTitle":$l(t,"http://www.w3.org/1999/xlink","xlink:title",a);break;case"xlinkType":$l(t,"http://www.w3.org/1999/xlink","xlink:type",a);break;case"xmlBase":$l(t,"http://www.w3.org/XML/1998/namespace","xml:base",a);break;case"xmlLang":$l(t,"http://www.w3.org/XML/1998/namespace","xml:lang",a);break;case"xmlSpace":$l(t,"http://www.w3.org/XML/1998/namespace","xml:space",a);break;case"is":ri(t,"is",a);break;case"innerText":case"textContent":return;default:if(!(2f)break;var E=d.transferSize,z=d.initiatorType;E&&Bm(z)&&(d=d.responseEnd,c+=E*(dxc){Z.length=q;break}j=new Promise(L0.bind(j)),Z.push(j)}}}if(0"u"?null:document;function uh(t,e,l){var a=In;if(a&&typeof e=="string"&&e){var n=ol(e);n='link[rel="'+t+'"][href="'+n+'"]',typeof l=="string"&&(n+='[crossorigin="'+l+'"]'),nh.has(n)||(nh.add(n),t={rel:t,crossOrigin:l,href:e},a.querySelector(n)===null&&(e=a.createElement("link"),ze(e,"link",t),be(e),a.head.appendChild(e)))}}function ry(t){ra.D(t),uh("dns-prefetch",t,null)}function oy(t,e){ra.C(t,e),uh("preconnect",t,e)}function dy(t,e,l){ra.L(t,e,l);var a=In;if(a&&t&&e){var n='link[rel="preload"][as="'+ol(e)+'"]';e==="image"&&l&&l.imageSrcSet?(n+='[imagesrcset="'+ol(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(n+='[imagesizes="'+ol(l.imageSizes)+'"]')):n+='[href="'+ol(t)+'"]';var u=n;switch(e){case"style":u=Pn(t);break;case"script":u=tu(t)}if(!(pl.has(u)||(t=ct({rel:"preload",href:e==="image"&&l&&l.imageSrcSet?void 0:t,as:e},l),pl.set(u,t),a.querySelector(n)!==null||e==="style"&&a.querySelector(Pu(u))||e==="script"&&a.querySelector(ti(u))))){var c=a.createElement("link");ze(c,"link",t),e==="style"&&(c[si]=!0,c.onload=c.onerror=function(){gr(c)}),be(c),a.head.appendChild(c)}}}function my(t,e){ra.m(t,e);var l=In;if(l&&t){var a=e&&typeof e.as=="string"?e.as:"script",n='link[rel="modulepreload"][as="'+ol(a)+'"][href="'+ol(t)+'"]',u=n;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":u=tu(t)}if(!pl.has(u)&&(t=ct({rel:"modulepreload",href:t},e),pl.set(u,t),l.querySelector(n)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(ti(u)))return}a=l.createElement("link"),ze(a,"link",t),be(a),l.head.appendChild(a)}}}function hy(t,e,l){ra.S(t,e,l);var a=In;if(a&&t){var n=gn(a).hoistableStyles,u=Pn(t);e=e||"default";var c=n.get(u);if(!c){var f={loading:0,preload:null};if(c=a.querySelector(Pu(u)))f.loading=5;else{t=ct({rel:"stylesheet",href:t,"data-precedence":e},l),(l=pl.get(u))&&Ff(t,l);var d=c=a.createElement("link");be(d),ze(d,"link",t),d._p=new Promise(function(p,E){d.onload=p,d.onerror=E}),d.addEventListener("load",function(){f.loading|=1}),d.addEventListener("error",function(){f.loading|=2}),f.loading|=4,pc(c,e,a)}c={type:"stylesheet",instance:c,count:1,state:f},n.set(u,c)}}}function vy(t,e){ra.X(t,e);var l=In;if(l&&t){var a=gn(l).hoistableScripts,n=tu(t),u=a.get(n);u||(u=l.querySelector(ti(n)),u||(t=ct({src:t,async:!0},e),(e=pl.get(n))&&Wf(t,e),u=l.createElement("script"),be(u),ze(u,"link",t),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function yy(t,e){ra.M(t,e);var l=In;if(l&&t){var a=gn(l).hoistableScripts,n=tu(t),u=a.get(n);u||(u=l.querySelector(ti(n)),u||(t=ct({src:t,async:!0,type:"module"},e),(e=pl.get(n))&&Wf(t,e),u=l.createElement("script"),be(u),ze(u,"link",t),l.head.appendChild(u)),u={type:"script",instance:u,count:1,state:null},a.set(n,u))}}function ih(t,e,l,a){var n=(n=ye.current)?Iu(n):null;if(!n)throw Error(o(446));switch(t){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(l=Pn(l.href),e=gn(n).hoistableStyles,a=e.get(l),a||(a={type:"style",instance:null,count:0,state:null},e.set(l,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){t=Pn(l.href);var u=gn(n).hoistableStyles,c=u.get(t);if(c||(n=n.ownerDocument||n,c={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},u.set(t,c),(u=n.querySelector(Pu(t)))?u._p||(c.instance=u,c.state.loading=5):(u=pl.get(t),u||(u={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},pl.set(t,u)),gy(n,t,u,c.state))),e&&a===null)throw Error(o(528,""));return c}if(e&&a!==null)throw Error(o(529,""));return null;case"script":return e=l.async,l=l.src,typeof l=="string"&&e&&typeof e!="function"&&typeof e!="symbol"?(l=tu(l),e=gn(n).hoistableScripts,a=e.get(l),a||(a={type:"script",instance:null,count:0,state:null},e.set(l,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,t))}}function Pn(t){return'href="'+ol(t)+'"'}function Pu(t){return'link[rel="stylesheet"]['+t+"]"}function ch(t){return ct({},t,{"data-precedence":t.precedence,precedence:null})}function gy(t,e,l,a){if(e=t.querySelector('link[rel="preload"][as="style"]['+e+"]")){if(e[si]!==!0){a.loading=1;return}}else e=t.createElement("link"),e[si]=!0,e.onload=e.onerror=gr.bind(null,e),ze(e,"link",l),be(e),t.head.appendChild(e);a.preload=e,e.addEventListener("load",function(){return a.loading|=1}),e.addEventListener("error",function(){return a.loading|=2})}function tu(t){return'[src="'+ol(t)+'"]'}function ti(t){return"script[async]"+t}function sh(t,e,l){if(e.count++,e.instance===null)switch(e.type){case"style":var a=t.querySelector('style[data-href~="'+ol(l.href)+'"]');if(a)return e.instance=a,be(a),a;var n=ct({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return a=(t.ownerDocument||t).createElement("style"),be(a),ze(a,"style",n),pc(a,l.precedence,t),e.instance=a;case"stylesheet":n=Pn(l.href);var u=t.querySelector(Pu(n));if(u)return e.state.loading|=4,e.instance=u,be(u),u;a=ch(l),(n=pl.get(n))&&Ff(a,n),u=(t.ownerDocument||t).createElement("link"),be(u);var c=u;return c._p=new Promise(function(f,d){c.onload=f,c.onerror=d}),ze(u,"link",a),e.state.loading|=4,pc(u,l.precedence,t),e.instance=u;case"script":return u=tu(l.src),(n=t.querySelector(ti(u)))?(e.instance=n,be(n),n):(a=l,(n=pl.get(u))&&(a=ct({},l),Wf(a,n)),t=t.ownerDocument||t,n=t.createElement("script"),be(n),ze(n,"link",a),t.head.appendChild(n),e.instance=n);case"void":return null;default:throw Error(o(443,e.type))}else e.type==="stylesheet"&&(e.state.loading&4)===0&&(a=e.instance,e.state.loading|=4,pc(a,l.precedence,t));return e.instance}function pc(t,e,l){for(var a=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),n=a.length?a[a.length-1]:null,u=n,c=0;c title"):null)}function Sy(t,e,l){if(l===1||e.itemProp!=null)return!1;switch(t){case"meta":case"title":return!0;case"style":if(typeof e.precedence!="string"||typeof e.href!="string"||e.href==="")break;return!0;case"link":if(typeof e.rel!="string"||typeof e.href!="string"||e.href===""||e.onLoad||e.onError)break;switch(e.rel){case"stylesheet":return t=e.disabled,typeof e.precedence=="string"&&t==null;default:return!0}case"script":if(e.async&&typeof e.async!="function"&&typeof e.async!="symbol"&&!e.onLoad&&!e.onError&&e.src&&typeof e.src=="string")return!0}return!1}function rh(t,e){return t==="img"&&e.src!=null&&e.src!==""&&e.onLoad==null&&e.loading!=="lazy"}function oh(t){return!(t.type==="stylesheet"&&(t.state.loading&3)===0)}function dh(t){return(t.width||100)*(t.height||100)*(typeof devicePixelRatio=="number"?devicePixelRatio:1)*.25}function mh(t,e){typeof e.decode=="function"&&(t.imgCount++,e.complete||(t.imgBytes+=dh(e),t.suspenseyImages.push(e)),t=xy.bind(t),e.decode().then(t,t))}function py(t,e,l,a){if(l.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var n=Pn(a.href),u=e.querySelector(Pu(n));if(u){e=u._p,e!==null&&typeof e=="object"&&typeof e.then=="function"&&(t.count++,t=ei.bind(t),e.then(t,t)),l.state.loading|=4,l.instance=u,be(u);return}u=e.ownerDocument||e,a=ch(a),(n=pl.get(n))&&Ff(a,n),u=u.createElement("link"),be(u);var c=u;c._p=new Promise(function(f,d){c.onload=f,c.onerror=d}),ze(u,"link",a),l.instance=u}t.stylesheets===null&&(t.stylesheets=new Map),t.stylesheets.set(l,e),(e=l.state.preload)&&(l.state.loading&3)===0&&(t.count++,l=ei.bind(t),e.addEventListener("load",l),e.addEventListener("error",l))}}var xc=0;function by(t,e){return t.stylesheets&&t.count===0&&Tc(t,t.stylesheets),0xc?50:800)+e);return t.unsuspend=l,function(){t.unsuspend=null,clearTimeout(a),clearTimeout(n)}}:null}function hh(t){if(t.count===0&&(t.imgCount===0||!t.waitingForImages)){if(t.stylesheets)Tc(t,t.stylesheets);else if(t.unsuspend){var e=t.unsuspend;t.unsuspend=null,e()}}}function ei(){this.count--,hh(this)}function xy(){this.imgCount--,hh(this)}var jc=null;function Tc(t,e){t.stylesheets=null,t.unsuspend!==null&&(t.count++,jc=new Map,e.forEach(jy,t),jc=null,ei.call(t))}function jy(t,e){if(!(e.state.loading&4)){var l=jc.get(t);if(l)var a=l.get(null);else{l=new Map,jc.set(t,l);for(var n=t.querySelectorAll("link[data-precedence],style[data-precedence]"),u=0;u"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(r){console.error(r)}}return i(),ir.exports=wy(),ir.exports}var ky=Gy();const Qy=wh(ky),Gh=v.createContext(null);function Mt(){const i=v.useContext(Gh);if(!i)throw new Error("ConsoleContext missing");return i}const ot=encodeURIComponent,$={health:"/health",relayModels:"/relay/models",quotaMe:"/users/me/quota",userKeys:"/users/me/keys",userKey:i=>"/users/me/keys/"+ot(i),githubRepos:"/github/repos",projects:"/projects",project:i=>"/projects/"+ot(i),projectMembers:i=>"/projects/"+ot(i)+"/members",projectMember:(i,r)=>"/projects/"+ot(i)+"/members/"+ot(r),projectSkills:i=>"/projects/"+ot(i)+"/skills",projectApps:i=>"/projects/"+ot(i)+"/apps",projectMcp:i=>"/projects/"+ot(i)+"/mcp-servers",projectMcpReload:i=>"/projects/"+ot(i)+"/mcp-servers/reload",projectMcpOauth:(i,r)=>"/projects/"+ot(i)+"/mcp-servers/"+ot(r)+"/oauth-login",projectAutomations:i=>"/projects/"+ot(i)+"/automations",projectAutomationCancel:(i,r)=>"/projects/"+ot(i)+"/automations/"+ot(r)+"/cancel",projectTriage:i=>"/projects/"+ot(i)+"/triage",workers:"/workers",environments:i=>"/environments?project_id="+ot(i),environmentsCreate:"/environments",environmentArchive:i=>"/environments/"+ot(i)+"/archive",tasks:i=>"/tasks?project_id="+ot(i),tasksByParent:(i,r)=>"/tasks?project_id="+ot(i)+"&parent_task_id="+ot(r),tasksCreate:"/tasks",task:i=>"/tasks/"+ot(i),taskAction:(i,r)=>"/tasks/"+ot(i)+"/"+r,taskFork:i=>"/tasks/"+ot(i)+"/fork",taskContinue:i=>"/tasks/"+ot(i)+"/continue",taskTrace:i=>"/tasks/"+ot(i)+"/trace",taskTraceStream:i=>"/tasks/"+ot(i)+"/trace/stream",taskAgents:i=>"/tasks/"+ot(i)+"/agents",taskReviews:i=>"/tasks/"+ot(i)+"/reviews",taskReviewFindings:(i,r)=>"/tasks/"+ot(i)+"/reviews/"+ot(r)+"/findings",taskApprovals:i=>"/tasks/"+ot(i)+"/approvals",taskApprovalDecision:(i,r,m)=>"/tasks/"+ot(i)+"/approvals/"+ot(r)+"/"+m,taskFollowups:i=>"/tasks/"+ot(i)+"/followups",taskChatHistory:i=>"/tasks/"+ot(i)+"/chat-history",taskMessages:i=>"/tasks/"+ot(i)+"/messages",taskMessagesTo:i=>"/tasks/"+ot(i)+"/messages",taskThread:i=>"/tasks/"+ot(i)+"/thread",taskThreads:i=>"/tasks/"+ot(i)+"/threads",taskThreadAction:(i,r)=>"/tasks/"+ot(i)+"/thread/"+r,taskCost:i=>"/tasks/"+ot(i)+"/cost",uploads:"/uploads",adminQuotas:"/admin/quotas",adminQuotaUser:i=>"/admin/quotas?user_id="+ot(i),adminSweep:"/admin/sweep",adminBackup:"/admin/backup"},Xy={exec:"命令",file:"文件",call:"调用",tool:"工具",message:"消息",reasoning:"思考",plan:"计划","agent-start":"子代理","agent-done":"子代理"},uu=["completed","failed","interrupted","merged","merge-failed"],Vy={queued:"排队中,尚未被 worker 认领",running:"运行中,模型回合进行中",completed:"模型回合结束、改动在 worktree 里尚未合并",failed:"模型回合失败,可重试",interrupted:"已被取消/中断,可重试",merged:"控制面已标记 merged,不代表 git 主分支已合入","merge-failed":"合并落盘失败,可重试"},Yh=["low","medium","high","xhigh","max"],Ly=["viewer","contributor","maintainer","owner"],hr="codex-console-key";function bl(){try{return localStorage.getItem(hr)||""}catch{return""}}function Zy(i){localStorage.setItem(hr,i)}function Ky(){localStorage.removeItem(hr)}function De(i){return i?i.slice(0,8):""}function Ga(i){return i?new Date(i*1e3).toLocaleString():""}async function P(i,r="GET",m){const o={"Content-Type":"application/json"},_=bl();_&&(o["X-API-Key"]=_);const C={method:r,headers:o};m!==void 0&&(C.body=JSON.stringify(m));const N=await fetch(i,C);let x=null;try{x=await N.json()}catch{x=null}if(!N.ok){const w=x;let U=w&&w.error?w.error:"HTTP "+N.status;throw N.status===401&&(U+="(key 未填或无效)"),N.status===429&&(U+="(触发限流,稍后再试)"),N.status===402&&(w&&w.unpriced_token_cap!==void 0?U+="(无价 token 已满,联系管理员调整)":w&&w.error==="coordinator_quota_reserve_exceeded"?U="协调员分工预留不足:剩余美元配额不够覆盖全部分工,子任务费用记父任务创建人账,整个父任务已被挡下(未建任何子任务)":U+="(美元配额已满,联系管理员调整)"),new Error(U)}return x}async function Jy(i){const r=new FormData;r.append("paths",JSON.stringify(i.map(_=>_.path))),i.forEach((_,C)=>r.append("file"+C,_.file));const m=await fetch($.uploads,{method:"POST",headers:{"X-API-Key":bl()},body:r}),o=await m.json().catch(()=>({}));if(!m.ok)throw new Error(o&&o.error||"HTTP "+m.status);return o.upload_id}function Fy(i,r,m){const o=[],_={},C=(N,x)=>{if(N)for(let w=0;wN.name),C(r,N=>N.webkitRelativePath||N.name),C(m,N=>N.name),o}function kh(i){const r=Date.now()/1e3;let m=null;if(typeof i.last_seen=="number"?m=r-i.last_seen:typeof i.last_seen_seconds_ago=="number"&&(m=i.last_seen_seconds_ago),(m===null||m<0)&&(m=null),m===null)return{text:"未知",age:null};const o=Math.floor(m);return o<60?{text:o+" 秒前",age:m}:o<3600?{text:Math.floor(o/60)+" 分钟前",age:m}:{text:Math.floor(o/3600)+" 小时前",age:m}}function Mc(i){const r=i.message||"";return r.includes("forbidden")?"没有权限:只有项目 owner 或全局管理员可以管理成员":r.includes("already_member")?"该用户已是成员,改角色请用成员行的下拉框":r.includes("cannot demote the only owner")?"不能把唯一 owner 降为非 owner:请先把另一位成员升为 owner":r.includes("user not found")?"找不到该用户:请核对 user_id 或用户名是否正确":r.includes("member not found")?"该用户不是本项目成员":r.includes("unknown role")?"角色无效:只能是 viewer / contributor / maintainer / owner":r.includes("project not found")?"项目不存在(可能已被删除)":"成员操作失败:"+r}function rr(i){const r=i.message||"";return r.includes("forbidden")?"无全局管理员权限:服务端返回 403(CODEX_GLOBAL_ADMINS 未包含当前用户),请联系管理员":r.includes("user not found")?"找不到该用户:请核对用户 id 是否正确":"管理操作失败:"+r}function or(i){return i==null?"不限额":"$"+(i/1e6).toFixed(2)}function dr(i){const r=Xy[i.kind||""]||i.kind||"?";let m="";return i.kind==="exec"?m=(i.command||"")+"(exit="+(i.exitCode??"")+","+(i.durationMs??"")+"ms,cwd="+(i.cwd||"")+")":i.kind==="file"?m=(i.path||"")+" "+(i.change||"")+" "+(i.status||""):i.kind==="message"?m=(i.phase?"["+i.phase+"] ":"")+(i.text||"")+(i.truncated?"(链路摘要已截断至 300 字,完整回复见右侧任务结果)":""):i.kind==="reasoning"?m=i.summary||"":i.kind==="tool"?m=(i.server||"")+"/"+(i.tool||"")+" "+(i.status||""):i.kind==="call"?m=i.name||"":i.kind==="plan"?m=i.text||"":i.kind==="agent-start"?m="开始:"+(i.name||"")+(i.prompt?"("+i.prompt+")":""):i.kind==="agent-done"?m="结束:"+(i.name||"")+" "+(i.status||""):m=JSON.stringify(i).slice(0,300),"["+r+"] "+m}function Wy(){const[i,r]=v.useState(!!bl()),[m,o]=v.useState(bl()?"已保存到本浏览器(只用于调本站 API)":"未填 key,数据接口会返回 401"),[_,C]=v.useState("未加载"),[N,x]=v.useState("未加载"),[w,U]=v.useState("填 key 后判断权限…"),[G,b]=v.useState(!1),[B,tt]=v.useState(""),[at,et]=v.useState(""),[L,dt]=v.useState([]),[zt,Jt]=v.useState(""),[nt,Xt]=v.useState(""),[te,ct]=v.useState([]),[yt,re]=v.useState(null),[he,Vt]=v.useState("未加载"),[Ft,le]=v.useState(""),[Ie,vt]=v.useState([]),[Y,A]=v.useState(""),[lt,gt]=v.useState(""),[St,ve]=v.useState([]),[Ue,_e]=v.useState([]),[y,R]=v.useState([]),[W,F]=v.useState("先选项目"),[pt,mt]=v.useState(""),[_t,V]=v.useState(""),[ut,ae]=v.useState(""),[ka,xl]=v.useState(""),[Xe,Wt]=v.useState([]),[Rt,oe]=v.useState(""),[Kl,ye]=v.useState(""),[oa,Ve]=v.useState(""),[zl,Rl]=v.useState(!1),[jl,Be]=v.useState(""),[ne,ue]=v.useState(""),[sl,Jl]=v.useState([]),[da,Dl]=v.useState(!1),Zt=v.useRef("");Zt.current=zt;const Pe=v.useRef("");Pe.current=ne;const qe=v.useCallback(async()=>{try{const O=await P($.health);x("backend="+O.backend+" db_ok="+O.db_ok+" worker_ok="+O.worker_ok+" commit="+String(O.commit||"").slice(0,7))}catch(O){x("加载失败:"+O.message)}},[]),Tl=v.useCallback(async()=>{if(!bl()){C("未填 key,配额不显示");return}try{const O=await P($.quotaMe),k=((O.used_usd_micros||0)/1e6).toFixed(2),J=O.quota_usd_micros===null||O.quota_usd_micros===void 0?"美元:本月用量 $"+k+"(不限额)":"美元:本月用量 $"+k+" / $"+((O.quota_usd_micros||0)/1e6).toFixed(2)+"(剩余 $"+((O.remaining_usd_micros||0)/1e6).toFixed(2)+")",At=O.unpriced_token_cap===void 0||O.unpriced_tokens_used===void 0?"无价 token:未返回(旧服务端)":"无价 token:"+O.unpriced_tokens_used+" / "+O.unpriced_token_cap+" tokens";C(J+" | "+At)}catch(O){C("配额加载失败:"+O.message)}},[]),fl=v.useCallback(async()=>{if(!bl()){U("未填 key,管理区不可用"),b(!1);return}try{const O=await fetch($.adminQuotas,{headers:{"X-API-Key":bl()}});O.status===400?(U("已确认为全局管理员,管理操作可用"),b(!0)):O.status===403?(U("管理区仅全局管理员可用:当前 key 无全局管理员权限(服务端返回 403)"),b(!1)):O.status===401?(U("key 无效,管理区不可用(服务端返回 401)"),b(!1)):(U("管理权限判断失败(HTTP "+O.status+"),管理操作暂不可用"),b(!1))}catch(O){U("管理权限判断失败:"+O.message),b(!1)}},[]),Gt=v.useCallback(async()=>{try{const k=(await P($.projects)).projects||[];dt(k),Xt(k.length+" 个项目"),Zt.current&&k.some(J=>J.id===Zt.current)}catch(O){Xt("加载失败:"+O.message)}},[]),Ul=v.useCallback(async()=>{try{const O=await P($.githubRepos);ct(O.repos||[])}catch{}},[]),mn=v.useCallback(async()=>{try{const O=await P($.relayModels);Jl(O.models||[]),Dl(!1)}catch{Dl(!0)}},[]),Qa=v.useCallback(async()=>{try{const O=await P($.workers);if(!Array.isArray(O)&&O.workers===void 0&&O.workers_total!==void 0){re(null),Vt(O.workers_total?"在线 "+O.workers_online+" / 离线 "+O.workers_offline+"(共 "+O.workers_total+";完整 worker 清单仅全局管理员可见)":"无 worker 注册"),le("");return}const k=Array.isArray(O)?O:O.workers||[];re(k),Vt(k.length?"":"无 worker 注册"),le("")}catch(O){le("加载失败:"+O.message)}},[]),ge=v.useCallback(async O=>{const k=O!==void 0?O:Zt.current,J=Pe.current;if(!k){Wt([]),oe(""),ue("");return}try{const Et=(await P($.environments(k))).environments||[];Wt(Et),oe(Et.length+" 个环境"),(J&&Et.some(pe=>pe.id===J&&pe.status==="ready")||J&&Et.some(pe=>pe.id===J))&&ue(J);const Se=L.find(pe=>pe.id===k);Se&&Se.repo_url?(Ve("仓库:"+Se.repo_url),Rl(!1)):Se?(Ve("该项目未绑定仓库,环境无法创建——先选一个仓库保存"),Rl(!0)):(Ve(""),Rl(!1))}catch(At){ye("加载失败:"+At.message)}},[L]),Xa=v.useCallback(async O=>{const k=O!==void 0?O:Zt.current;if(!k){vt([]);return}try{const J=await P($.projectMembers(k));vt(J.members||[]),gt("")}catch(J){gt("成员加载失败:"+Mc(J))}},[]),ma=v.useCallback(async O=>{const k=O!==void 0?O:Zt.current;if(!k){ve([]),_e([]),R([]),F("先选项目");return}F("");try{const J=await P($.projectSkills(k));ve(J.skills||[])}catch(J){mt("技能加载失败:"+J.message)}try{const J=await P($.projectApps(k));_e(J.apps||[])}catch(J){mt("应用加载失败:"+J.message)}try{const J=await P($.projectMcp(k));R(J.servers||J.mcp_servers||[])}catch(J){mt("MCP 服务加载失败:"+J.message)}},[]),su=v.useCallback(O=>{if(!O.trim()){o("key 为空,未保存");return}Zy(O.trim()),r(!0),o("已保存到本浏览器(只用于调本站 API)")},[]),fu=v.useCallback(()=>{Ky(),r(!1),o("未填 key,数据接口会返回 401"),fl()},[fl]),Fl=v.useCallback(async(O,k)=>{if(!O.trim()){Xt("项目名必填");return}const J={name:O.trim()};k.trim()&&(J.repo_url=k.trim());try{await P($.projects,"POST",J),Xt("项目已建"),await Gt()}catch(At){Xt("新建失败:"+At.message)}},[Gt]),Ee=v.useCallback(async(O,k,J)=>{const At=Zt.current;if(!At){ye("先选项目");return}if(!O.trim()){ye("环境名必填");return}const Et={project_id:At,name:O.trim()};k.trim()&&(Et.branch=k.trim()),J&&(Et.executor=J);try{await P($.environmentsCreate,"POST",Et),ye("环境已建,worker 准备中(creating → ready,失败会在列表里写原因)"),await ge(At)}catch(Se){ye("新建失败:"+Se.message)}},[ge]),rl=v.useCallback(async O=>{if(window.confirm("确定归档该环境吗?归档后新任务不能再选它,进行中的任务不受影响(有进行中任务在用它时归档会被拒绝)。"))try{await P($.environmentArchive(O),"POST",{}),await ge()}catch(k){ye("归档失败:"+k.message)}},[ge]),Ne=v.useCallback(async O=>{const k=Zt.current;if(!k){Be("先选项目");return}if(!O){Be("先选一个仓库");return}try{await P($.project(k),"PATCH",{repo_url:O}),Be("仓库已保存,现在可以建环境了"),await Gt(),await ge(k)}catch(J){Be("保存失败:"+J.message)}},[Gt,ge]),ru=v.useCallback(async(O,k)=>{const J=Zt.current;if(!J){A("先选项目");return}if(!O.trim()){A("请填成员 user_id 或用户名");return}try{await P($.projectMembers(J),"POST",{user_id:O.trim(),role:k})}catch(At){if(At.message.includes("user not found"))try{await P($.projectMembers(J),"POST",{username:O.trim(),role:k})}catch(Et){A(Mc(Et));return}else{A(Mc(At));return}}A("已邀请成员"),await Xa(J)},[Xa]),ou=v.useCallback(async(O,k)=>{const J=Zt.current;if(J)try{await P($.projectMember(J,O),"PATCH",{role:k}),vt(At=>At.map(Et=>Et.user_id===O?{...Et,role:k}:Et)),A("角色已改为 "+k)}catch(At){A(Mc(At))}},[]),du=v.useCallback(async()=>{const O=Zt.current;if(!O){V("先选项目");return}try{await P($.projectMcpReload(O),"POST",{}),V("配置已重载"),await ma(O)}catch(k){V("重载失败:"+k.message)}},[ma]),H=v.useCallback(async O=>{const k=Zt.current;if(!k){ae("先选项目");return}if(!O.trim()){ae("服务名不能为空");return}try{const J=await P($.projectMcpOauth(k,O.trim()),"POST",{}),At=J.url||J.auth_url||J.login_url||J.authorization_url||"",Et=J.steps||J.instructions||"";let Se=`登录尚未完成:请在浏览器打开下面的链接或按步骤完成,完成后回到本页刷新 MCP 状态。 `;At&&(Se+=At+` `),Et&&(Se+=(Array.isArray(Et)?Et.join(` `):String(Et))+` @@ -68,7 +68,8 @@ Error generating stack: `+a.message+` `+D.result_text.slice(0,8e3)+` `),D.error_text&&(X+=`=== error === `+D.error_text.slice(0,8e3)+` -`),C(X||"(暂无 result/error 输出)")}catch{}Zt(H.id),Pe(H.id),qe(H.id),Tl(H.id),da(H),sl(H.id),fl(H.id),Gt(H.id),Ul(H.id),Dl(H.id)}},[Zt,Pe,qe,Tl,da,sl,fl,Gt,Ul,Dl]),ma=v.useCallback(async H=>{const D=ne.current;if(!D)return;const X={cancel:"确定取消该任务吗?",merge:"确定把 completed 任务标为 merged 吗?",pr:"确定为该任务提 PR 吗?(会在仓库真实建 PR)"};if(!(X[H]&&!window.confirm(X[H])))try{const K=await P($.taskAction(D.id,H),"POST",{});x(H+" 已提交:"+JSON.stringify(K).slice(0,300)),r(),await ge(D.id)}catch(K){x(H+" 失败:"+K.message)}},[ge,r]),su=v.useCallback(async()=>{const H=ne.current;if(H)try{const D=await P($.taskCost(H.id));b(JSON.stringify(D,null,2).slice(0,4e3))}catch(D){b("查成本失败:"+D.message)}},[]),fu=v.useCallback(async H=>{const D=ne.current;if(D){if(!H.trim()){dt("分支消息必填");return}if(!uu.includes(D.status)){dt("仅终态任务可分支");return}try{const X=await P($.taskFork(D.id),"POST",{message:H.trim()});dt("分支任务已建:"+X.id.slice(0,8)),r()}catch(X){dt("分支失败:"+X.message)}}},[r]),Fl=v.useCallback(async H=>{const D=ne.current;if(D)try{await P($.taskReviews(D.id),"POST",H),Vt("评审已登记(requested)"),await qe(D.id)}catch(X){Vt("登记评审需求失败:"+X.message)}},[qe]),Ee=v.useCallback(H=>{const D=ne.current;if(!D)return;const X=window.prompt("输入该条评审的 findings(将写回记录并标为 completed):");X!==null&&P($.taskReviewFindings(D.id,H),"POST",{findings:X}).then(()=>void qe(D.id)).catch(K=>Vt("写 findings 失败:"+K.message))},[qe]),rl=v.useCallback((H,D)=>{const X=ne.current;if(!X)return;const K=D==="approved"?"approve":"deny";P($.taskApprovalDecision(X.id,H,K),"POST",{}).then(()=>{mt("已记录"+(D==="approved"?"允许":"拒绝")+"(当前版本只留回执,不拦截实时行为)"),Tl(X.id)}).catch(O=>mt("决定失败:"+O.message))},[Tl]),Ne=v.useCallback(async(H,D,X)=>{const K=ne.current;if(K){if(!D.trim()){ae("目标任务 id 不能为空");return}if(!X.trim()){ae("消息正文不能为空");return}try{const O=await P($.taskMessagesTo(D.trim()),"POST",{from_task_id:K.id,body:X.trim(),mode:H});ae("已发送("+O.delivery+")"),await fl(K.id)}catch(O){ae("发送失败:"+O.message)}}},[fl]),ru=v.useCallback((H,D)=>{const X=ne.current;if(!X)return;if(!["completed","failed","interrupted"].includes(X.status)){oe("仅 completed/failed/interrupted 任务可操作线程(merged/merge-failed 不可改,服务端同样 409)");return}const K={};if(H==="rename"){if(!D.trim()){oe("新线程名不能为空");return}K.name=D.trim()}P($.taskThreadAction(X.id,H),"POST",K).then(O=>{oe(H+" 已提交:"+JSON.stringify(O).slice(0,300)),Gt(X.id),Ul(X.id)}).catch(O=>oe(H+" 失败:"+O.message))},[Gt,Ul]),ou=v.useCallback(async H=>{const D=ne.current;if(!D)return;const X=H.trim();if(!X){Ve("消息不能为空");return}try{uu.includes(D.status)&&D.status!=="merged"?(await P($.taskContinue(D.id),"POST",{message:X}),Ve("已重新排队,同一会话继续"),r(),await ge(D.id)):["queued","running"].includes(D.status)?(await P($.taskFollowups(D.id),"POST",{body:X,mode:"direct"}),Ve("已直接发送"),await Zt(D.id),await Pe(D.id)):Ve("merged/merge-failed 任务不可继续,也不可发后续消息")}catch(K){Ve("发送失败:"+K.message)}},[ge,r,Zt,Pe]),du=v.useCallback(async()=>{const H=ne.current;if(!H){_e("先选一个任务");return}try{const D=await P($.taskTrace(H.id)),X=new Blob([JSON.stringify({task_id:H.id,status:D.status,note:D.note||"",count:(D.entries||[]).length,entries:D.entries||[]},null,2)],{type:"application/json"}),K=document.createElement("a");K.href=URL.createObjectURL(X),K.download="trace-"+H.id.slice(0,8)+".json",document.body.appendChild(K),K.click(),K.remove(),setTimeout(()=>URL.revokeObjectURL(K.href),1e3),_e("已下载完整链路 "+(D.entries||[]).length+" 条")}catch(D){_e("下载失败:"+D.message)}},[]);return v.useEffect(()=>()=>ue(),[ue]),{currentTask:m,detailBody:_,actionMsg:N,actionReasons:w,costBox:G,costSummary:B,forkVisible:at,setForkVisible:et,forkMsg:L,coordChildren:zt,agents:nt,agentsNote:te,reviews:yt,reviewMsg:he,reviewError:Ft,traceEntries:Ie,traceNote:Y,traceDone:lt,traceKind:St,setTraceKind:ve,traceMsg:Ue,followups:y,approvals:W,approvalMsg:pt,peerMessages:_t,peerMsg:ut,threadText:ka,threadGateNote:Xe,threadMsg:Rt,threadList:Kl,chatMsg:oa,chatHistory:zl,showDetail:ge,refreshDetailLists:Xa,doAction:ma,taskCost:su,forkTask:fu,postReview:Fl,submitFindings:Ee,decideApproval:rl,postPeer:Ne,threadAction:ru,sendChatMessage:ou,downloadTrace:du,refreshReviews:()=>void qe(),refreshApprovals:()=>void Tl()}}function Py(i){const[r,m]=v.useState([]),[o,_]=v.useState(""),[C,N]=v.useState(null),[x,w]=v.useState(""),U=v.useCallback(async tt=>{const at=tt!==void 0?tt:i();if(!at){m([]);return}try{const et=await P($.projectAutomations(at));m(et.automations||[])}catch(et){_("自动化加载失败:"+et.message)}},[i]),G=v.useCallback(async(tt,at,et,L)=>{const dt=i();if(!dt){_("先选项目");return}if(!tt.trim()){_("自动化名称必填");return}if(!at.trim()){_("定时任务内容必填");return}const zt={name:tt.trim(),prompt:at.trim()};et.trim()&&(zt.interval_seconds=parseInt(et.trim(),10)),L.trim()&&(zt.repo_url=L.trim());try{await P($.projectAutomations(dt),"POST",zt),_("自动化已创建(登记定义,到期后由执行器认领)"),await U(dt)}catch(Jt){_("创建失败:"+Jt.message)}},[i,U]),b=v.useCallback(tt=>{const at=i();at&&P($.projectAutomationCancel(at,tt),"POST",{}).then(()=>{_("自动化已取消"),U(at)}).catch(et=>_("取消失败:"+et.message))},[i,U]),B=v.useCallback(async tt=>{const at=tt!==void 0?tt:i();if(!at){N(null);return}try{const et=await P($.projectTriage(at));N(et),w("")}catch(et){w("分诊加载失败:"+et.message)}},[i]);return{automations:r,autoMsg:o,triage:C,triageError:x,refreshAutomations:U,createAutomation:G,cancelAutomation:b,refreshTriage:B}}function tg(i,r){const m=v.useRef(i);m.current=i,v.useEffect(()=>{const o=setInterval(()=>{const _=document.activeElement;m.current(_?_.tagName==="SELECT":!1)},r);return()=>clearInterval(o)},[r])}function eg(i,r){const m=v.useRef(i);m.current=i,v.useEffect(()=>{const o=setInterval(()=>m.current(),r);return()=>clearInterval(o)},[r])}function lg(i){const r=m=>String(m).padStart(2,"0");return r(i.getHours())+":"+r(i.getMinutes())+":"+r(i.getSeconds())}function ag(){var et;const i=Wy(),r=$y(),m=v.useRef("");m.current=i.projectId;const o=v.useCallback(()=>m.current,[]),_=Py(o),C=v.useCallback(L=>{const dt=i.projects.find(zt=>zt.id===L);return dt&&dt.my_role||null},[i.projects]),N=v.useCallback(()=>{r.refreshTasks(void 0,m.current)},[r]),x=Iy(C,N),[w,U]=v.useState("--:--:--"),G=v.useCallback(L=>{i.setProjectId(L),m.current=L,r.refreshTasks(L),i.refreshEnvs(L),i.refreshMembers(L),i.refreshSkills(L),_.refreshAutomations(L),_.refreshTriage(L)},[i,r,_]),b=(et=i.projects[0])==null?void 0:et.id;v.useEffect(()=>{!i.projectId&&b&&G(b)},[i.projectId,b,G]);const B=v.useCallback(L=>{i.saveKeyInput(L),L.trim()&&(i.refreshHealth(),i.refreshProjects(),i.refreshWorkers(),m.current&&(r.refreshTasks(m.current),i.refreshEnvs(m.current),i.refreshMembers(m.current)),i.loadRelayModels(),i.loadQuota(),i.loadGithubRepos(),i.probeAdmin())},[i,r]),tt=v.useCallback(L=>{if(U(lg(new Date)),!bl()){i.refreshHealth();return}r.refreshTasks(void 0,m.current),i.refreshHealth(),i.loadQuota(),i.refreshWorkers(),i.refreshMembers(),i.refreshSkills(),_.refreshAutomations(),_.refreshTriage(),x.refreshDetailLists(),L||(i.refreshProjects(),i.refreshEnvs())},[i,r,_,x]),at=v.useCallback(()=>{bl()&&(i.loadRelayModels(),i.loadGithubRepos())},[i]);return v.useEffect(()=>{i.refreshHealth(),i.refreshProjects(),i.refreshWorkers(),i.loadQuota(),i.loadGithubRepos(),bl()&&i.loadRelayModels(),i.probeAdmin()},[]),{keySaved:i.keySaved,keyState:i.keyState,saveKeyInput:B,clearKeyInput:i.clearKeyInput,quotaText:i.quotaText,healthText:i.healthText,refreshHealth:i.refreshHealth,adminGate:i.adminGate,adminBody:i.adminBody,adminResult:i.adminResult,adminUserId:i.adminUserId,setAdminUserId:i.setAdminUserId,adminQuota:i.adminQuota,adminSweep:i.adminSweep,adminBackup:i.adminBackup,projects:i.projects,projectId:i.projectId,projectMsg:i.projectMsg,selectProject:G,refreshProjects:i.refreshProjects,createProject:i.createProject,githubRepos:i.githubRepos,workers:i.workers,workersSummary:i.workersSummary,workersError:i.workersError,refreshWorkers:i.refreshWorkers,members:i.members,memberMsg:i.memberMsg,memberError:i.memberError,refreshMembers:()=>void i.refreshMembers(),inviteMember:i.inviteMember,changeMemberRole:i.changeMemberRole,skills:i.skills,apps:i.apps,mcpServers:i.mcpServers,skillMsg:i.skillMsg,skillError:i.skillError,mcpMsg:i.mcpMsg,mcpOauthMsg:i.mcpOauthMsg,mcpOauthBox:i.mcpOauthBox,refreshSkills:()=>void i.refreshSkills(),reloadMcp:i.reloadMcp,mcpOauth:i.mcpOauth,envs:i.envs,envCount:i.envCount,envMsg:i.envMsg,envRepoLine:i.envRepoLine,envRepoBar:i.envRepoBar,envRepoMsg:i.envRepoMsg,envSelect:i.envSelect,setEnvSelect:i.setEnvSelect,refreshEnvs:()=>void i.refreshEnvs(),createEnv:i.createEnv,archiveEnv:i.archiveEnv,saveEnvRepo:i.saveEnvRepo,models:i.models,modelCustomVisible:i.modelCustomVisible,tasks:r.tasks,taskCountText:r.taskCountText,taskError:r.taskError,refreshTasks:()=>void r.refreshTasks(void 0,m.current),statusFilter:r.statusFilter,setStatusFilter:r.setStatusFilter,executorFilter:r.executorFilter,setExecutorFilter:r.setExecutorFilter,searchText:r.searchText,setSearchText:r.setSearchText,filteredTasks:r.filteredTasks,currentTask:x.currentTask,detailBody:x.detailBody,actionMsg:x.actionMsg,actionReasons:x.actionReasons,showDetail:L=>void x.showDetail(L),doAction:x.doAction,taskCost:x.taskCost,costBox:x.costBox,costSummary:x.costSummary,forkVisible:x.forkVisible,setForkVisible:x.setForkVisible,forkTask:x.forkTask,forkMsg:x.forkMsg,coordChildren:x.coordChildren,coordText:"",agents:x.agents,agentsNote:x.agentsNote,reviews:x.reviews,reviewMsg:x.reviewMsg,reviewError:x.reviewError,refreshReviews:x.refreshReviews,postReview:x.postReview,submitFindings:x.submitFindings,traceEntries:x.traceEntries,traceNote:x.traceNote,traceDone:x.traceDone,traceKind:x.traceKind,setTraceKind:x.setTraceKind,downloadTrace:x.downloadTrace,traceMsg:x.traceMsg,sendChatMessage:x.sendChatMessage,chatMsg:x.chatMsg,chatHistory:x.chatHistory,followups:x.followups,approvals:x.approvals,approvalMsg:x.approvalMsg,refreshApprovals:x.refreshApprovals,decideApproval:x.decideApproval,peerMessages:x.peerMessages,peerMsg:x.peerMsg,postPeer:x.postPeer,automations:_.automations,autoMsg:_.autoMsg,refreshAutomations:()=>void _.refreshAutomations(),createAutomation:_.createAutomation,cancelAutomation:_.cancelAutomation,triage:_.triage,triageError:_.triageError,refreshTriage:()=>void _.refreshTriage(),threadText:x.threadText,threadGateNote:x.threadGateNote,threadMsg:x.threadMsg,threadList:x.threadList,threadAction:x.threadAction,dispatch:async(L,dt)=>{const zt=await r.dispatch(L,dt);return r.refreshTasks(m.current),zt},dispatchMsg:"",refreshAll:tt,refreshSlow:at,refreshStamp:w}}function nu({label:i,value:r,sub:m}){return s.jsxs("div",{className:"dash-card data-card",children:[s.jsx("div",{className:"dash-card-label",children:i}),s.jsx("div",{className:"dash-card-value",children:r}),s.jsx("div",{className:"muted",children:m})]})}function ng(){const i=Mt(),r=i.healthText==="未加载"?"未加载":i.healthText.includes("worker_ok=true")?"正常":i.healthText.includes("worker_ok=false")?"异常":i.healthText.includes("加载失败")?"加载失败":"未知",m=i.quotaText.match(/剩余 \$([0-9.]+)/),o=i.quotaText.includes("加载失败")?"加载失败":i.quotaText.includes("未填 key")||i.quotaText==="未加载"?"未加载":m?"$"+m[1]:"配额",_=["running","completed","failed","queued","merged","interrupted"].map(b=>i.tasks.filter(B=>B.status===b).length).map((b,B)=>["running","completed","failed","queued","merged","interrupted"][B]+" "+b).join(" | "),C=i.projects.find(b=>b.id===i.projectId),N=i.taskError?{value:"加载失败",sub:i.taskError}:i.projectId?{value:String(i.tasks.length),sub:i.taskCountText+" | "+_+(C?" | "+C.name:"")}:{value:"先选项目",sub:i.projectMsg||"项目加载后自动选第一个"};let x;if(i.workersError)x={value:"加载失败",sub:i.workersError};else if(i.workers===null)x={value:i.workersSummary||"未加载",sub:"完整 worker 清单仅全局管理员可见"};else{const b=i.workers.filter(B=>{if(B.alive!==void 0&&B.alive!==null)return!!B.alive;const tt=kh(B).age;return tt!==null&&tt<=120}).length;x={value:b+" 在线 / "+i.workers.length,sub:i.workers.length-b+" 离线"}}const w=i.projectMsg.includes("加载失败")?{value:"加载失败",sub:i.projectMsg}:{value:i.projects.length+" 个",sub:C?"当前项目:"+C.name:"未选项目(加载后自动选第一个)"},U=[i.envMsg,i.memberError,i.skillError].filter(b=>b&&b.includes("失败")),G=i.projectId?U.length?{value:"部分加载失败",sub:U.join(" | ")}:{value:i.envs.length+" 个环境",sub:i.members.length+" 成员 | "+i.skills.length+" 技能 | "+i.apps.length+" 应用 | "+i.mcpServers.length+" MCP"}:{value:"先选项目",sub:"选项目后显示环境 / 成员 / 技能计数"};return s.jsxs("section",{className:"dash-cards","aria-label":"数据卡片",children:[s.jsx(nu,{label:"健康",value:r,sub:i.healthText}),s.jsx(nu,{label:"配额",value:o,sub:i.quotaText}),s.jsx(nu,{label:"任务",value:N.value,sub:N.sub}),s.jsx(nu,{label:"Workers",value:x.value,sub:x.sub}),s.jsx(nu,{label:"项目",value:w.value,sub:w.sub}),s.jsx(nu,{label:"项目数据",value:G.value,sub:G.sub})]})}function Qe({id:i,className:r,title:m,children:o}){return s.jsxs("section",{id:i,className:"card"+(r?" "+r:""),children:[m?s.jsx("h2",{children:m}):null,o]})}function Ut({children:i}){return s.jsx("div",{className:"bar",children:i})}function Ml({items:i,empty:r}){return i.length?s.jsx("ul",{className:"data-list",children:i.map((m,o)=>s.jsx("li",{children:m},o))}):s.jsx("div",{className:"muted",children:r||"(暂无)"})}function cu({children:i}){return s.jsx("ul",{className:"data-list",children:i})}function ug(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(!1),[x,w]=v.useState(!1),[U,G]=v.useState(!1),[b,B]=v.useState("docker"),[tt,at]=v.useState(""),[et,L]=v.useState(""),[dt,zt]=v.useState(""),[Jt,nt]=v.useState(""),[Xt,te]=v.useState(""),[ct,yt]=v.useState(""),[re,he]=v.useState(""),Vt=v.useRef(null),Ft=v.useRef(null),le=v.useRef(null),[Ie,vt]=v.useState("");async function Y(){var Ue,_e,y;if(vt(""),!i.projectId){vt("先选项目");return}if(!r.trim()){vt("prompt 必填");return}const A={project_id:i.projectId,prompt:r.trim()};i.envSelect&&(A.environment_id=i.envSelect),b&&(A.executor=b);const lt=et.trim()||tt;lt&&(A.model=lt),dt&&(A.effort=dt);const gt=ct.trim()||Xt;if(gt&&(A.child_model=gt),re&&(A.child_effort=re),Jt&&(A.approval=Jt),U){if(Jt==="full"){vt("计划模式不能与完全访问同用");return}if(C||x){vt("计划模式不能与 goal 模式同用");return}A.plan=1}x?(A.goal_mode=1,A.no_time_limit=1):C&&(A.goal_mode=1);const St=o.trim();if(St){try{A.coordinator_parts=JSON.parse(St)}catch{vt("协调员子任务 JSON 解析失败");return}if(!Array.isArray(A.coordinator_parts)){vt("协调员子任务必须是数组");return}if(C||x||U){vt("协调员任务不能与 goal/计划模式同用:协调员任务本身不跑模型回合,请取消 goal/计划勾选,或清空协调员 JSON");return}}const ve=Fy(((Ue=Vt.current)==null?void 0:Ue.files)||null,((_e=Ft.current)==null?void 0:_e.files)||null,((y=le.current)==null?void 0:y.files)||null);try{const R=await i.dispatch(A,ve);vt(R),m(""),_(""),Vt.current&&(Vt.current.value=""),Ft.current&&(Ft.current.value=""),le.current&&(le.current.value="")}catch(R){vt("提交失败:"+((R==null?void 0:R.message)||String(R)))}}return s.jsxs(Qe,{id:"nav-newtask",className:"composer",title:"新建任务",children:[s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"环境",value:i.envSelect,onChange:A=>i.setEnvSelect(A.target.value),children:[s.jsx("option",{value:"",children:"环境:不指定(走项目仓库)"}),i.envs.map(A=>s.jsxs("option",{value:A.id,disabled:A.status!=="ready",children:[A.name,"(",A.status,")"]},A.id))]}),s.jsxs("select",{"aria-label":"执行器",value:b,onChange:A=>B(A.target.value),children:[s.jsx("option",{value:"docker",children:"docker(默认,多用户下隔离最强)"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"cloud",children:"cloud"})]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:C,onChange:A=>N(A.target.checked)})," goal 模式"]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:x,onChange:A=>w(A.target.checked)})," goal 模式无敌版"]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:U,onChange:A=>G(A.target.checked)})," 计划模式(只读)"]})]}),s.jsx("textarea",{className:"prompt stacked",placeholder:"任务 prompt(必填)",value:r,onChange:A=>m(A.target.value)}),s.jsx("textarea",{className:"coord stacked",placeholder:"协调员子任务 JSON(可选),留空为普通任务",value:o,onChange:A=>_(A.target.value)}),s.jsxs("div",{className:"muted",children:["协调员格式:[","{",'"name":"后端","prompt":"做后端"',"}",",","{",'"name":"前端","prompt":"做前端"',"}","];提交后 worker 并行建子任务、等齐、合流汇总。不能与 goal/计划模式同用。协调员与 goal/计划互斥:勾了 goal 或计划模式时不要填协调员 JSON,提交前会校验并拦截。子任务费用记父任务创建人账;父任务创建时按分工数预留配额,余额不足时整个父任务被挡下。"]}),s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"模型",value:tt,onChange:A=>at(A.target.value),children:[s.jsx("option",{value:"",children:"模型:默认(跟随配置)"}),i.models.map(A=>s.jsx("option",{value:A,children:A},A))]}),i.modelCustomVisible?s.jsx("input",{type:"text",placeholder:"手动输入模型(中转列表取不到时用)",value:et,onChange:A=>L(A.target.value)}):null,s.jsxs("select",{"aria-label":"推理强度",value:dt,onChange:A=>zt(A.target.value),children:[s.jsx("option",{value:"",children:"推理强度:默认(跟随配置)"}),Yh.map(A=>s.jsx("option",{value:A,children:A},A))]}),s.jsxs("select",{"aria-label":"权限",value:Jt,onChange:A=>nt(A.target.value),children:[s.jsx("option",{value:"",children:"权限:默认(跟随配置)"}),s.jsx("option",{value:"ask",children:"请求批准"}),s.jsx("option",{value:"auto",children:"帮我批准"}),s.jsx("option",{value:"full",children:"完全访问"})]})]}),s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"子任务模型",value:Xt,onChange:A=>te(A.target.value),children:[s.jsx("option",{value:"",children:"子任务模型:跟随本任务模型"}),i.models.map(A=>s.jsx("option",{value:A,children:A},A))]}),s.jsx("input",{type:"text",placeholder:"子任务模型手动输入(中转列表里没有时填,如 gpt-6-luna;留空=跟随本任务模型)",value:ct,onChange:A=>yt(A.target.value)}),s.jsxs("select",{"aria-label":"子任务强度",value:re,onChange:A=>he(A.target.value),children:[s.jsx("option",{value:"",children:"子任务强度:跟随本任务强度"}),Yh.map(A=>s.jsx("option",{value:A,children:A},A))]})]}),s.jsx("div",{className:"muted",children:"子任务模型/强度是派生默认:本任务用 marker task-create 或协调员分工派生的子任务,未显式写模型/强度时用它;块/分工里显式写了则覆盖它。也可以不在这里填、直接在 prompt 里写“子任务用 gpt-6-luna max”,建任务时服务端会解析成同一对字段(任务详情里可核对)。"}),C?s.jsx("div",{className:"muted",children:"goal 模式:输入框内容即目标,不需要专用 prompt 与验收命令;不限轮次,模型确认达成后在回复末尾输出“目标已达成”即结束,未达成会一直运行,可用取消停止。"}):null,x?s.jsx("div",{className:"muted",children:"goal 模式无敌版:goal 模式 + 任务不限时(去掉 worker/docker 总超时;单轮 600 秒护栏还在,不限的是任务总时长与总轮次)。服务端默认的自动续跑与断点镜像同时生效。"}):null,s.jsxs(Ut,{children:[s.jsx("span",{className:"muted",children:"附件(放进任务工作区,图片与普通文件不区分):"}),s.jsx("input",{ref:Vt,type:"file",multiple:!0,title:"文件"}),s.jsx("input",{ref:Ft,type:"file",multiple:!0,title:"文件夹",webkitdirectory:""}),s.jsx("input",{ref:le,type:"file",accept:"image/*",multiple:!0,title:"图片"})]}),s.jsxs(Ut,{children:[s.jsx("button",{className:"seal",onClick:Y,children:"提交任务"}),s.jsx("span",{className:"muted",children:Ie||i.dispatchMsg})]})]})}function Qh(i){const r=(i.prompt||"").trim();return r?[...r][0]:i.id?[...i.id][0]:"?"}function zc(i){const r=Math.max(0,Math.floor(i));if(r<60)return r+"秒";if(r<3600){const _=Math.floor(r/60),C=r%60;return C?_+"分"+C+"秒":_+"分"}if(r<86400){const _=Math.floor(r/3600),C=Math.floor(r%3600/60);return C?_+"小时"+C+"分":_+"小时"}const m=Math.floor(r/86400),o=Math.floor(r%86400/3600);return o?m+"天"+o+"小时":m+"天"}function iu(i){if(i==null)return null;const r=Number(i);return Number.isFinite(r)?r:null}function Xh(i){const r=Date.now()/1e3,m=iu(i.started_at),o=iu(i.finished_at),_=iu(i.created_at);return m!==null&&o!==null&&o>=m?[zc(o-m),"总耗时:开始→结束(末次认领的执行时长)"]:m!==null&&i.status==="running"?["进行中 "+zc(r-m),"总耗时:进行中,已用时长从开始算起,随刷新更新"]:_!==null&&o!==null&&o>=_?[zc(o-_),"总耗时:创建→完成(含排队等待;无开始时间时的兜底口径)"]:_!==null&&(i.status==="queued"||i.status==="running")?[(i.status==="queued"?"排队中 ":"进行中 ")+zc(r-_),"总耗时:从创建算起的已用时长(无开始时间时的兜底口径)"]:["—","总耗时:无可用时间戳"]}function ig(i){if(i==null||!Number.isFinite(Number(i)))return"—";const r=Number(i)/1e6;return"$"+(r>0&&r<.01?r.toFixed(4):r.toFixed(2))}function Vh(i){const r=iu(i.total_tokens);if(r!==null)return[r.toLocaleString()+" token","token:服务端 total_tokens"];const m=iu(i.actual_tokens),o=iu(i.estimated_tokens);return m!==null||o!==null?[((m||0)+(o||0)).toLocaleString()+" token","token:actual + estimated 分项加总"]:["token —","token:本任务对象未带 token 字段;单任务真数在详情的成本里可查,不逐个调成本接口、不编造"]}function cg({onNew:i}){const r=Mt();return s.jsxs("div",{children:[s.jsxs("div",{className:"search-box",children:[s.jsxs("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round","aria-hidden":"true",children:[s.jsx("circle",{cx:"11",cy:"11",r:"7"}),s.jsx("path",{d:"M21 21l-4.3-4.3"})]}),s.jsx("input",{type:"text",placeholder:"搜索","aria-label":"搜索任务",value:r.searchText,onChange:m=>r.setSearchText(m.target.value)})]}),s.jsx("div",{className:"bar",children:s.jsxs("select",{"aria-label":"项目",value:r.projectId,onChange:m=>r.selectProject(m.target.value),children:[r.projects.length===0?s.jsx("option",{value:"",children:"(先加载项目)"}):null,r.projects.map(m=>s.jsxs("option",{value:m.id,children:[m.name," (",De(m.id),")"]},m.id))]})}),s.jsxs("div",{className:"list-section-head",children:[s.jsx("span",{children:"主要聊天"}),s.jsx("button",{type:"button","aria-label":"派发新任务",title:"派发新任务",onClick:i,children:"+"})]}),s.jsxs("div",{className:"bar",children:[s.jsxs("select",{"aria-label":"状态筛选",value:r.statusFilter,onChange:m=>r.setStatusFilter(m.target.value),children:[s.jsx("option",{value:"",children:"状态:全部"}),["queued","running","completed","failed","interrupted","merged","merge-failed"].map(m=>s.jsx("option",{value:m,children:m},m))]}),s.jsxs("select",{"aria-label":"执行器筛选",value:r.executorFilter,onChange:m=>r.setExecutorFilter(m.target.value),children:[s.jsx("option",{value:"",children:"执行器:全部"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"docker",children:"docker"}),s.jsx("option",{value:"cloud",children:"cloud"})]})]}),s.jsxs("div",{className:"bar",children:[s.jsx("button",{onClick:r.refreshTasks,children:"刷新"}),s.jsx("span",{className:"muted",children:r.taskCountText})]}),r.taskError?s.jsx("div",{className:"err",children:r.taskError}):r.projectId?r.filteredTasks.length===0?s.jsx("div",{className:"muted",children:r.tasks.length?"没有符合筛选条件的任务":"该项目暂无任务"}):s.jsx("ul",{className:"issue-list",children:r.filteredTasks.slice().reverse().map(m=>{var w;const[o,_]=Xh(m),[C,N]=Vh(m),x=Qh(m);return s.jsxs("li",{className:"issue-item"+(((w=r.currentTask)==null?void 0:w.id)===m.id?" selected":""),onClick:()=>r.showDetail(m.id),children:[s.jsx("span",{className:"issue-state st-"+m.status,"aria-hidden":"true"}),s.jsx("span",{className:"issue-first",title:"任务首字:"+x,"aria-hidden":"true",children:x}),s.jsxs("span",{style:{flex:1,minWidth:0},children:[s.jsxs("div",{className:"issue-title",children:[m.plan?"[计划] ":"",m.forked_from?"[分支] ":"",m.coordinator_parts?"[协调] ":"",m.parent_task_id?"[协调子任务] ":"",String(m.prompt||De(m.id)).slice(0,60)]}),s.jsxs("div",{className:"issue-meta",children:[De(m.id)," · ",s.jsx("span",{className:"st-"+m.status,children:m.status})," · ",m.executor||"",m.updated_at?" · "+new Date(m.updated_at*1e3).toLocaleString():""," · ",s.jsxs("span",{title:_,children:["耗时 ",o]})," · ",s.jsx("span",{title:N,children:C})]})]})]},m.id)})}):s.jsx("div",{className:"muted",children:"先选项目"})]})}function sg(i){const r=v.useRef(null),[m,o]=v.useState(!0),_=v.useRef(!0),C=()=>{const N=r.current;if(!N)return;const x=N.scrollHeight-N.scrollTop-N.clientHeight<80;_.current=x,o(x)};return v.useEffect(()=>{_.current&&r.current&&(r.current.scrollTop=r.current.scrollHeight)},[i]),{ref:r,following:m,onScroll:C}}function fg({msg:i}){if(i.role==="status")return s.jsx("div",{className:"chat-status",children:i.text});const r=i.label||(i.role==="user"?"用户":i.role==="assistant"?"助手":"工具");return s.jsxs("div",{className:"gh-comment "+i.role,children:[s.jsx("div",{className:"gh-comment-header",children:s.jsx("span",{className:"gh-comment-author",children:r})}),s.jsx("div",{className:"gh-comment-body",children:i.text})]})}function Lh({messages:i,empty:r}){const{ref:m,following:o,onScroll:_}=sg(i.length);return s.jsxs("div",{className:"chat-list",ref:m,onScroll:_,children:[i.length===0?s.jsx("div",{className:"muted",children:r||"(暂无消息)"}):i.map(C=>s.jsx(fg,{msg:C},C.id)),!o&&i.length>0?s.jsx("button",{className:"chat-follow",onClick:()=>{m.current&&(m.current.scrollTop=m.current.scrollHeight)},children:"回到最新 ↓"}):null]})}function rg({onSend:i,disabled:r,placeholder:m}){const[o,_]=v.useState(""),C=()=>{const N=o.trim();!N||r||(i(N),_(""))};return s.jsxs("div",{className:"gh-comment-box",children:[s.jsx("textarea",{"aria-label":"会话输入",rows:3,placeholder:m||"消息",value:o,disabled:r,onChange:N=>_(N.target.value),onKeyDown:N=>{N.key==="Enter"&&!N.shiftKey&&(N.preventDefault(),C())}}),s.jsx("div",{className:"gh-comment-footer",children:s.jsx("button",{type:"button",className:"primary","aria-label":"发送",disabled:r||!o.trim(),onClick:C,children:"发送"})})]})}function Zh(i,r){const m=i.id||"trace-"+r;if(i.kind==="message")return{id:m,role:"assistant",text:(i.phase?"["+i.phase+"] ":"")+(i.text||""),label:"助手"};if(i.kind==="exec"||i.kind==="file"||i.kind==="tool"||i.kind==="call"){const o=i.kind==="exec"?"命令":i.kind==="file"?"文件":i.kind==="tool"?"工具":"调用";return{id:m,role:"tool",text:dr(i),label:o}}return i.kind==="plan"?{id:m,role:"status",text:i.text||""}:i.kind==="reasoning"?{id:m,role:"status",text:"思考:"+(i.summary||"")}:i.kind==="agent-start"?{id:m,role:"status",text:"子代理开始:"+(i.name||"")+(i.prompt?"("+i.prompt+")":"")}:i.kind==="agent-done"?{id:m,role:"status",text:"子代理结束:"+(i.name||"")+" "+(i.status||"")}:{id:m,role:"status",text:dr(i)}}function og(){const i=Mt(),r=v.useMemo(()=>{const m=i.currentTask,o=m&&m.prompt?[{id:"task-prompt",role:"user",text:m.prompt}]:[],C=(i.traceKind?i.traceEntries.filter(x=>x.kind===i.traceKind):i.traceEntries).map((x,w)=>Zh(x,w)),N=i.traceDone?[{id:"trace-done",role:"status",text:"链路已结束("+i.traceDone+")"}]:[];return[...o,...C,...N]},[i.currentTask,i.traceEntries,i.traceKind,i.traceDone]);return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"muted",children:"实时链路"}),s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"链路类型",value:i.traceKind,onChange:m=>i.setTraceKind(m.target.value),children:[s.jsx("option",{value:"",children:"链路类型:全部"}),["exec","file","call","tool","message","reasoning","plan","agent-start","agent-done"].map(m=>s.jsx("option",{value:m,children:m==="exec"?"命令":m==="file"?"文件":m==="call"?"调用":m==="tool"?"工具":m==="message"?"消息":m==="reasoning"?"思考":m==="plan"?"计划":"子代理"},m))]}),s.jsx("button",{onClick:i.downloadTrace,children:"下载完整链路"}),s.jsx("span",{className:"muted",children:i.traceMsg})]}),i.traceNote?s.jsx("div",{children:s.jsx("span",{className:"err",children:i.traceNote})}):null,s.jsx("div",{className:"chat-column",children:s.jsx(Lh,{messages:r,empty:"(暂无链路条目)"})}),s.jsx("div",{className:"muted",children:"对话时间线:首条是本任务 prompt(用户);助手回复来自 message 条目,命令/文件/工具/调用是工具评论框,计划/思考/子代理开始结束是时间线上的状态文字。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。"})]})}function dg(){const i=Mt(),r=i.currentTask,m=v.useMemo(()=>{if(!r)return[];if(i.chatHistory)return i.chatHistory.messages.map(b=>({id:b.id,role:b.role,text:b.text,label:b.label}));const w=r.prompt?[{id:"task-prompt",role:"user",text:r.prompt}]:[],U=i.traceEntries.filter(b=>b.kind==="message").map((b,B)=>Zh(b,B)),G=i.followups.map((b,B)=>({id:"followup-"+B,role:"user",text:String(b.body||""),label:"后续消息"}));return[...w,...U,...G]},[r,i.chatHistory,i.traceEntries,i.followups]);if(!r)return s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示继续会话"});const o=uu.includes(r.status),_=["queued","running"].includes(r.status),C=o||_,N=o?"终态任务:发送走继续接口(同一会话再跑一轮)":_?"运行中/排队中:发送走后续消息直接发送(跑完当前轮后优先执行)":"merged/merge-failed 任务不可继续,也不可发后续消息",x=i.chatHistory?i.chatHistory.legacy_continue_count??null:null;return s.jsxs("div",{className:"chat-column",children:[x!==null&&x>0?s.jsxs("div",{className:"muted",children:["此前有 ",x," 条继续消息发生在持久化之前,未入库,上面历史不完整;部署后新发的继续消息会正常显示。"]}):null,i.chatHistory&&i.chatHistory.trace_note?s.jsx("div",{className:"muted",children:i.chatHistory.trace_note}):null,s.jsx(Lh,{messages:m,empty:"(暂无会话消息)"}),s.jsx(rg,{disabled:!C,placeholder:"消息",onSend:w=>void i.sendChatMessage(w)}),s.jsxs("div",{className:"muted",children:[N,"。",i.chatMsg]})]})}function mg(){return Mt().currentTask?s.jsxs("div",{className:"conversation",children:[s.jsx(og,{}),s.jsx("div",{className:"conv-divider"}),s.jsx(dg,{})]}):s.jsx("div",{className:"conversation",children:s.jsx("div",{className:"muted",children:"在任务列表里点一条任务,对话和详情就切到该任务;也可以在上面派发一个新任务。"})})}function hg(){const i=Mt(),r=i.currentTask,[m,o]=v.useState("");if(!r)return null;const _=uu.includes(r.status),C=["failed","interrupted","merge-failed"].includes(r.status);return s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("button",{disabled:!C,title:C?"":"仅 failed/interrupted/merge-failed 可重试",onClick:()=>i.doAction("retry"),children:"重试"}),s.jsx("button",{className:"danger",disabled:_,title:_?"终态任务不可取消":"",onClick:()=>i.doAction("cancel"),children:"取消"}),s.jsx("button",{disabled:r.status!=="completed",title:r.status!=="completed"?"仅 completed 可合并":"",onClick:()=>i.doAction("merge"),children:"合并(completed → merged)"}),s.jsx("button",{disabled:r.status!=="merged",title:r.status!=="merged"?"仅 merged 可提 PR":"",onClick:()=>i.doAction("pr"),children:"提 PR(须 merged)"}),_?s.jsx("button",{onClick:()=>i.setForkVisible(!0),children:"分支"}):null,s.jsx("button",{onClick:i.taskCost,children:"查成本"}),s.jsxs("span",{className:"muted",children:[i.actionMsg," ",i.actionReasons]})]}),i.forkVisible?s.jsxs("div",{children:[s.jsx("input",{type:"text",placeholder:"分支首轮消息(必填,带历史的新会话)",style:{width:"100%",boxSizing:"border-box",margin:"6px 0"},value:m,onChange:N=>o(N.target.value)}),s.jsxs(Ut,{children:[s.jsx("button",{className:"seal",onClick:async()=>{await i.forkTask(m),o("")},children:"创建分支任务"}),s.jsx("span",{className:"muted",children:i.forkMsg})]})]}):null]})}function vg(){const i=Mt(),[r,m]=v.useState("uncommittedChanges"),[o,_]=v.useState(""),[C,N]=v.useState(""),[x,w]=v.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("h3",{children:"评审队列"}),s.jsxs("select",{"aria-label":"评审目标",value:r,onChange:U=>m(U.target.value),children:[s.jsx("option",{value:"uncommittedChanges",children:"未提交改动(工作区)"}),s.jsx("option",{value:"baseBranch",children:"与分支的差异"}),s.jsx("option",{value:"commit",children:"指定提交"}),s.jsx("option",{value:"custom",children:"自定义评审指令"})]}),s.jsx("input",{className:"stacked",placeholder:"与分支的差异用:分支名(如 main)",style:{width:"100%"},value:o,onChange:U=>_(U.target.value)}),s.jsx("input",{className:"stacked",placeholder:"指定提交用:提交 sha",style:{width:"100%"},value:C,onChange:U=>N(U.target.value)}),s.jsx("textarea",{placeholder:"自定义评审指令用:评审指令正文",value:x,onChange:U=>w(U.target.value)}),s.jsxs(Ut,{children:[s.jsx("button",{className:"primary",onClick:()=>void i.postReview({target_type:r,branch:o.trim()||void 0,sha:C.trim()||void 0,instructions:x.trim()||void 0}),children:"登记评审需求"}),s.jsx("button",{onClick:i.refreshReviews,children:"刷新队列"}),s.jsx("span",{className:"muted",children:i.reviewMsg})]}),s.jsx("div",{className:"muted",children:"本基线只登记评审需求(requested),不自动跑评审;评审是否执行、结果如何,以评审队列里的记录为准。"}),i.reviewError?s.jsx("div",{className:"muted",children:i.reviewError}):i.reviews.length===0?s.jsx("div",{className:"muted",children:"点任务行查看详情后,点“刷新队列”查看评审记录"}):s.jsx(cu,{children:i.reviews.map(U=>{let G=U.target_type||"";return U.branch&&(G+=":"+U.branch),U.sha&&(G+=":"+String(U.sha).slice(0,12)),U.instructions&&(G+=":"+String(U.instructions).slice(0,80)),s.jsxs("li",{children:[s.jsxs("span",{className:"row-main",children:[s.jsx("b",{children:"评审"})," ",De(U.id)," | ",G," | ",s.jsx("span",{className:"st-"+(U.status||""),children:U.status}),U.created_at?" | "+Ga(U.created_at):"",s.jsx("br",{}),U.findings?String(U.findings).slice(0,1e3):s.jsx("span",{className:"muted",children:"(暂无 findings:评审尚未执行或尚未写回)"})]}),s.jsx("button",{onClick:()=>i.submitFindings(U.id),children:"写 findings"})]},U.id)})})]})}function yg(){const i=Mt();return i.currentTask?i.currentTask.coordinator_parts?i.coordChildren.length===0?s.jsx("div",{className:"muted",children:"(子任务尚未创建)"}):s.jsx(cu,{children:i.coordChildren.map(r=>s.jsx("li",{children:s.jsxs("span",{className:"row-main",children:["分工 ",s.jsx("b",{children:r.coordinator_part||""})," | 状态 ",s.jsx("span",{className:"st-"+r.status,children:r.status})," | ",De(r.id)," | ",String(r.prompt||"").slice(0,60)]})},r.id))}):s.jsx("div",{className:"muted",children:"(非协调员任务)"}):s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示协调员的子任务"})}function gg(){const i=Mt();if(!i.currentTask)return s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示子代理链路"});if(i.agents.length===0)return s.jsxs("div",{className:"muted",children:["(暂无子代理)",i.agentsNote?s.jsx("span",{className:"err",children:i.agentsNote}):null]});const r={main:"主任务",delegate:"委派子任务",model:"模型子代理"},m={running:"进行中",completed:"已完成",failed:"失败",interrupted:"已中断",unknown:"未知"};return s.jsx(cu,{children:i.agents.map((o,_)=>s.jsx("li",{children:s.jsxs("span",{className:"row-main",children:[s.jsxs("b",{children:[r[o.kind||""]||o.kind||"",":"]}),o.name||""," ",s.jsx("span",{className:"st-"+(o.status||""),children:m[o.status||""]||o.status||"?"})," | 过程调用 "+(o.calls?o.calls.length:0)+" 条",o.updated_ts?" | 最近活动 "+Ga(o.updated_ts/1e3):"",o.prompt?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsxs("span",{className:"muted",children:["任务:",o.prompt]})]}):null,o.calls&&o.calls.length?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),o.calls.slice(-50).map((C,N)=>s.jsx("div",{children:dr(C)},N))]}):s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsx("span",{className:"muted",children:"(暂无过程调用)"})]})]})},_))})}function Sg(){const i=Mt();return s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.refreshApprovals,children:"刷新审批队列"}),s.jsx("span",{className:"muted",children:i.approvalMsg})]}),s.jsx("div",{className:"muted",children:"待审批项需人工点记录允许或记录拒绝;超时默认拒绝。当前版本只留回执,不拦截实时行为(实时请求的事前拦截待 host 接入后生效,在此之前实时行为不变)。"}),s.jsx(Ml,{empty:"(暂无审批项)",items:i.approvals.map(r=>s.jsxs("span",{className:"row-main",children:["[",r.kind,"|",r.status,"] ",r.summary,["approved","denied","expired"].includes(r.status||"")?"|回执:"+(r.decision||r.status)+" by "+String(r.decided_by||"").slice(0,8)+" "+Ga(r.decided_at):"",r.status==="pending"?s.jsxs(s.Fragment,{children:[" ",s.jsx("button",{onClick:()=>i.decideApproval(r.id,"approved"),children:"记录允许"})," ",s.jsx("button",{onClick:()=>i.decideApproval(r.id,"denied"),children:"记录拒绝"})]}):null]},r.id))})]})}function pg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("input",{placeholder:"目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)",style:{width:"100%"},value:r,onChange:C=>m(C.target.value)}),s.jsx("textarea",{placeholder:"消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)",value:o,onChange:C=>_(C.target.value)}),s.jsxs(Ut,{children:[s.jsx("button",{onClick:async()=>{await i.postPeer("queued",r,o),_("")},children:"排队发给对方"}),s.jsx("button",{className:"primary",onClick:async()=>{await i.postPeer("direct",r,o),_("")},children:"直接发送"}),s.jsx("span",{className:"muted",children:i.peerMsg})]}),s.jsx(Ml,{empty:"(本任务尚未发出任务间消息)",items:i.peerMessages.map((C,N)=>s.jsxs("span",{className:"row-main",children:["[发给 ",String(C.task_id).slice(0,8),"|",C.mode,"|",C.status,"] ",String(C.body||"").slice(0,120)]},N))})]})}function bg(){const i=Mt(),[r,m]=v.useState(""),o=i.currentTask?["completed","failed","interrupted"].includes(i.currentTask.status):!1;return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"muted",children:i.threadText||"点任务行查看详情后,这里显示线程元数据"}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"新线程名",value:r,onChange:_=>m(_.target.value)}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("rename",r),children:"重命名"}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("archive",""),children:"归档"}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("unarchive",""),children:"取消归档"}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("compact",""),children:"压缩"}),s.jsx("span",{className:"muted",children:i.threadGateNote}),s.jsx("span",{className:"muted",children:i.threadMsg})]}),s.jsx(Ml,{empty:"暂无其他线程",items:i.threadList.map((_,C)=>s.jsxs("span",{className:"row-main",children:[_.name||_.thread_name||_.id||""," [",_.id||"","]",_.archived?" [已归档]":"",_.cwd?" "+_.cwd:""]},C))}),s.jsx("div",{className:"muted",children:"限制:Docker/异机任务线程操作一律 409;merged/merge-failed 不可改;turn/steer 与 review/start 不在本批。"})]})}function xg(){const i=Mt(),r=i.currentTask;if(!r)return s.jsx(Qe,{id:"nav-detail",title:"任务详情",children:s.jsx("div",{className:"muted",children:"点任务行查看详情"})});const[m,o]=Xh(r),[_,C]=Vh(r),N=Qh(r);return s.jsxs(Qe,{id:"nav-detail",title:"任务详情",children:[s.jsxs("div",{children:["状态 ",s.jsx("b",{className:"st-"+r.status,children:r.status}),"(",Vy[r.status]||"未知状态",")",s.jsx("br",{}),s.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[s.jsx("span",{className:"issue-first",title:"任务首字:"+N,"aria-hidden":"true",children:N}),s.jsxs("span",{title:o,children:["耗时 ",m]}),s.jsx("span",{children:" · "}),s.jsx("span",{title:C,children:_})]}),s.jsx("br",{}),i.costSummary===void 0?s.jsx("span",{className:"muted",children:"成本加载中…"}):i.costSummary===null?s.jsx("span",{className:"muted",children:"成本明细加载失败(“查成本”按钮仍可手动拉取原始 JSON)"}):s.jsxs("span",{title:"成本明细:GET /tasks/{id}/cost 聚合;美元只计有价行,无价 token 单列;缓存是输入 token 的子集,不另计",children:["成本 ",ig(i.costSummary.usd_micros)," | token ",(i.costSummary.total_tokens??0).toLocaleString(),"(实际 ",(i.costSummary.actual_tokens??0).toLocaleString()," / 估算 ",(i.costSummary.estimated_tokens??0).toLocaleString(),",缓存 ",(i.costSummary.cached_input_tokens??0).toLocaleString(),",无价 ",(i.costSummary.unpriced_actual_tokens??0).toLocaleString(),")| 轮数 ",i.costSummary.turns??0," | fallback ",i.costSummary.fallback_count??0]}),s.jsx("br",{}),"任务 ",r.id," | turn ",De(r.turn_id)," | root turn ",De(r.root_turn_id),s.jsx("br",{}),"executor ",r.executor||""," | 主机 ",r.worktree_host||"",s.jsx("br",{}),"模型 ",r.model||"默认"," | 强度 ",r.effort||"默认",r.child_model||r.child_effort?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"子任务默认 ",(r.child_model||"跟随本任务")+" / "+(r.child_effort||"跟随本任务")]}):null,s.jsx("br",{}),"权限 ",r.approval||"默认"," | 项目 ",De(r.project_id),s.jsx("br",{}),"更新 ",Ga(r.updated_at),r.plan?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"计划模式(只读)"]}):null,r.forked_from?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"分支自 ",De(r.forked_from)]}):null,r.goal_mode?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),r.no_time_limit?"goal 模式无敌版(不限时)":"goal 模式(不限轮次,模型宣告完成)"]}):r.verify_command?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"goal 模式(旧语义,验收命令)"]}):null,r.coordinator_parts?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"协调员:",r.coordinator_parts.length," 个子任务(",r.coordinator_parts.map(x=>x.name).join("、"),")"]}):null,r.parent_task_id?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"协调子任务,父任务 ",De(r.parent_task_id),r.coordinator_part?"("+r.coordinator_part+")":""]}):null,r.attachments&&r.attachments.length?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"附件:",r.attachments.join("、")]}):null,r.pr_url?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsxs("a",{href:r.pr_url,target:"_blank",rel:"noopener noreferrer",children:["PR #",r.pr_number]})]}):null,s.jsx("br",{}),"prompt:",r.prompt||""]}),s.jsx(hg,{}),s.jsx("pre",{children:i.detailBody||"(暂无 result/error 输出)"}),i.costBox?s.jsx("pre",{children:i.costBox}):null,s.jsx("h3",{children:"协调子任务"}),s.jsx(yg,{}),s.jsx("h3",{children:"子代理链路"}),s.jsx(gg,{}),s.jsx("h3",{children:"评审队列"}),s.jsx(vg,{}),s.jsx("h3",{children:"运行时审批队列"}),s.jsx(Sg,{}),s.jsx("h3",{children:"给其他任务发消息"}),s.jsx(pg,{}),s.jsx("h3",{children:"线程"}),s.jsx(bg,{})]})}function jg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState([]),[x,w]=v.useState(null),[U,G]=v.useState(!1),[b,B]=v.useState(""),[tt,at]=v.useState(""),et=v.useCallback(async()=>{if(!i.keySaved){N([]);return}try{const nt=await P($.userKeys);N(nt.keys||[]),at("")}catch(nt){at(nt instanceof Error?nt.message:"加载 key 列表失败")}},[i.keySaved]);v.useEffect(()=>{et()},[et]);const L=async()=>{B(""),at(""),G(!1);try{const nt=await P($.userKeys,"POST",{label:o.trim()||"api-key"});w(nt),_(""),B("新 key 已生成,只显示一次:复制后请妥善保存。"),await et()}catch(nt){at(nt instanceof Error?nt.message:"生成 key 失败")}},dt=async()=>{if(x)try{await navigator.clipboard.writeText(x.api_key),G(!0)}catch{at("复制失败:请手动选中上方 key 文本复制")}},zt=()=>{x&&(i.saveKeyInput(x.api_key),w(null),B("已存为当前浏览器 key(原有 key 未被撤销,需要时可单独撤销)。"))},Jt=async nt=>{const Xt=(()=>{try{return bl().slice(-4)}catch{return""}})(),te=nt.id==="legacy"?"(主 key:撤销后当前浏览器保存的 key 也可能随之失效,需重新登录拿新 key)":nt.hint&&nt.hint===Xt?"(这就是本浏览器当前在用的 key,撤销后本页会立刻未连接)":"";if(window.confirm(`撤销 key「${nt.label}」(后 4 位 ${nt.hint||"无"})吗?${te}撤销不可恢复。`)){B(""),at("");try{await P($.userKey(nt.id),"DELETE"),B(`已撤销 key「${nt.label}」。`),await et()}catch(ct){at(ct instanceof Error?ct.message:"撤销失败")}}};return s.jsxs(Qe,{id:"nav-key",title:"API Key",children:[s.jsxs(Ut,{children:[s.jsx("input",{type:"password",placeholder:"粘贴你的 X-API-Key(与调 API 用的同一个)",autoComplete:"off",value:r,onChange:nt=>m(nt.target.value)}),s.jsx("button",{className:"primary",onClick:()=>{i.saveKeyInput(r),m("")},children:"保存到本浏览器"}),s.jsx("button",{onClick:i.clearKeyInput,children:"清除"}),s.jsx("span",{className:"muted",children:i.keyState})]}),s.jsx("div",{children:s.jsx("span",{className:"muted",children:i.quotaText})}),!i.keySaved&&s.jsx("div",{children:s.jsx("span",{className:"muted",children:"先粘贴并保存已有 key,再生成或管理 key(生成接口本身也要用已有 key 鉴权)。"})}),i.keySaved&&s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("input",{placeholder:"新 key 备注(可选,默认 api-key,如 harness2-temp)",autoComplete:"off",value:o,onChange:nt=>_(nt.target.value)}),s.jsx("button",{className:"primary",onClick:()=>void L(),children:"生成新 key"}),s.jsx("button",{onClick:()=>void et(),children:"刷新列表"})]}),x&&s.jsxs("div",{children:[s.jsx("div",{children:s.jsxs("span",{className:"muted",children:["新 key(",x.label,",后 4 位 ",x.hint,"):只显示一次,关闭后无法再查看。"]})}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",readOnly:!0,value:x.api_key,onFocus:nt=>nt.target.select()}),s.jsx("button",{className:"primary",onClick:()=>void dt(),children:U?"已复制":"复制"}),s.jsx("button",{onClick:zt,children:"存为当前浏览器 key"}),s.jsx("button",{onClick:()=>w(null),children:"关闭(不再显示)"})]})]}),b&&s.jsx("div",{children:s.jsx("span",{className:"muted",children:b})}),tt&&s.jsx("div",{children:s.jsx("span",{children:tt})}),s.jsxs("div",{children:[C.length===0&&s.jsx("span",{className:"muted",children:"暂无 key(或列表加载失败,见上方报错)。"}),C.map(nt=>s.jsxs("div",{children:[s.jsx("span",{children:nt.label})," ",s.jsxs("span",{className:"muted",children:["后 4 位 ",nt.hint||"无"," · 创建 ",Ga(nt.created_at)," · 最近使用 ",nt.last_used_at?Ga(nt.last_used_at):"未使用过"]})," ",nt.revoked_at?s.jsxs("span",{className:"muted",children:["已撤销(",Ga(nt.revoked_at),")"]}):s.jsx("button",{onClick:()=>void Jt(nt),children:"撤销"})]},nt.id))]})]})]})}function Tg(){const i=Mt();return s.jsxs(Qe,{id:"adminCard",title:s.jsxs(s.Fragment,{children:["管理区 ",s.jsx("span",{className:"muted",children:"(仅全局管理员)"})]}),children:[s.jsx("div",{className:"muted",children:i.adminGate}),i.adminBody?s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"要查配额的用户 id",value:i.adminUserId,onChange:r=>i.setAdminUserId(r.target.value)}),s.jsx("button",{onClick:i.adminQuota,children:"查该用户配额"})]}),s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.adminSweep,children:"手动触发 sweep(清理陈旧 running 任务)"}),s.jsx("button",{onClick:i.adminBackup,children:"手动触发备份"})]}),s.jsx("div",{className:"muted",children:i.adminResult})]}):null]})}function _g(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return s.jsxs(Qe,{id:"nav-projects",title:"项目",children:[s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"项目",value:i.projectId,onChange:x=>i.selectProject(x.target.value),children:[i.projects.length===0?s.jsx("option",{value:"",children:"(先加载项目)"}):null,i.projects.map(x=>s.jsxs("option",{value:x.id,children:[x.name," (",De(x.id),")"]},x.id))]}),s.jsx("button",{onClick:i.refreshProjects,children:"刷新"})]}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"新项目名",value:r,onChange:x=>m(x.target.value)}),s.jsxs("select",{"aria-label":"从 GitHub 仓库选",value:o,onChange:x=>{_(x.target.value),x.target.value&&N(x.target.value)},children:[s.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选,或手动输入)"}),i.githubRepos.map(x=>s.jsx("option",{value:x.clone_url,children:x.repo_full_name},x.clone_url))]}),s.jsx("input",{type:"text",placeholder:"repo_url(可选)",value:C,onChange:x=>N(x.target.value)}),s.jsx("button",{onClick:async()=>{await i.createProject(r,C),m(""),N(""),_("")},children:"新建项目"})]}),s.jsx("span",{className:"muted",children:i.projectMsg})]})}function Eg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState("contributor"),C=i.projects.find(N=>N.id===i.projectId);return s.jsxs(Qe,{title:"项目成员",children:[C?s.jsxs("div",{className:"muted",children:[C.name," | ",C.id," | 仓库 ",C.repo_url||"未绑定"," | 我的角色 ",C.my_role||"未知"]}):s.jsx("div",{className:"muted",children:"先选项目"}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"成员 user_id 或用户名",value:r,onChange:N=>m(N.target.value)}),s.jsxs("select",{"aria-label":"邀请角色",value:o,onChange:N=>_(N.target.value),children:[s.jsx("option",{value:"viewer",children:"viewer(只读)"}),s.jsx("option",{value:"contributor",children:"contributor(可建任务)"}),s.jsx("option",{value:"maintainer",children:"maintainer(可批合并)"}),s.jsx("option",{value:"owner",children:"owner(可管项目)"})]}),s.jsx("button",{onClick:async()=>{await i.inviteMember(r,o),m("")},children:"邀请成员"}),s.jsx("button",{onClick:i.refreshMembers,children:"刷新成员"})]}),i.memberError?s.jsx("div",{className:"muted",children:i.memberError}):i.members.length===0?s.jsx("div",{className:"muted",children:"先选项目"}):s.jsx(cu,{children:i.members.map(N=>{const x=(N.username||"")+(N.username?"("+String(N.user_id).slice(0,8)+")":String(N.user_id).slice(0,8));return s.jsxs("li",{children:[s.jsx("span",{className:"row-main",children:x}),s.jsx("select",{"aria-label":"成员角色",value:N.role||"viewer",onChange:w=>void i.changeMemberRole(N.user_id,w.target.value),children:Ly.map(w=>s.jsx("option",{value:w,children:w},w))})]},N.user_id)})}),s.jsx("span",{className:"muted",children:i.memberMsg})]})}function Ng(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return s.jsxs(Qe,{id:"nav-env",title:s.jsxs(s.Fragment,{children:["环境 ",s.jsx("span",{className:"muted",children:"(选、建、管:当前项目的基准检出)"})]}),children:[s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.refreshEnvs,children:"刷新"}),s.jsx("span",{className:"muted",children:i.envCount})]}),i.envs.length===0?s.jsx("div",{className:"muted",children:"先选项目"}):s.jsx(cu,{children:i.envs.map(x=>s.jsxs("li",{children:[s.jsxs("span",{className:"row-main",children:[x.name,"(",De(x.id),") / 分支 ",x.branch||"默认分支"," / 执行器 ",x.executor||"不限"," / 状态 ",x.status,x.status==="failed"&&x.error_text?" / 失败原因:"+x.error_text:""]}),x.status==="archived"?null:s.jsx("button",{onClick:()=>void i.archiveEnv(x.id),children:"归档"})]},x.id))}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"新环境名",value:r,onChange:x=>m(x.target.value)}),s.jsx("input",{type:"text",placeholder:"分支(可选,空=默认分支)",value:o,onChange:x=>_(x.target.value)}),s.jsxs("select",{"aria-label":"新环境执行器",value:C,onChange:x=>N(x.target.value),children:[s.jsx("option",{value:"",children:"执行器:不限"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"docker",children:"docker"})]}),s.jsx("button",{onClick:async()=>{await i.createEnv(r,o,C),m(""),_("")},children:"新建环境"})]}),s.jsx("span",{className:"muted",children:i.envMsg})]})}function Cg(){const i=Mt(),[r,m]=v.useState("");return s.jsxs(Qe,{title:"仓库与环境上下文",children:[s.jsx("div",{className:"muted",children:i.envRepoLine||"先选项目"}),s.jsx("div",{className:"muted",children:i.envCount}),i.envRepoBar?s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"补仓库",value:r,onChange:o=>m(o.target.value),children:[s.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选)"}),i.githubRepos.map(o=>s.jsx("option",{value:o.clone_url,children:o.repo_full_name},o.clone_url))]}),s.jsx("button",{onClick:()=>void i.saveEnvRepo(r),children:"保存仓库"})]}):null,s.jsx("span",{className:"muted",children:i.envRepoMsg})]})}function Ag(){const i=Mt();return s.jsxs(Qe,{id:"nav-workers",title:"Workers",children:[s.jsx(Ut,{children:s.jsx("button",{onClick:i.refreshWorkers,children:"刷新"})}),i.workersError?s.jsx("div",{className:"muted",children:i.workersError}):i.workers===null?s.jsx("div",{className:"muted",children:i.workersSummary||"未加载"}):i.workers.length===0?s.jsx("div",{className:"muted",children:"无 worker 注册"}):s.jsx(cu,{children:i.workers.map((r,m)=>{const o=r.running===void 0||r.running===null?"?":r.running,_=r.capacity===void 0||r.capacity===null?"?":r.capacity,C=kh(r),N=r.alive!==void 0&&r.alive!==null?!!r.alive:C.age!==null&&C.age<=120,x=N?" / 在线":" / 离线(占用为上次上报值)";return s.jsx("li",{className:N?"is-online":"is-offline",children:s.jsxs("span",{className:"row-main",children:[r.worker_id||r.id||"?"," / ",r.executor||""," / 占用 ",o,"/",_,x," / 最后心跳 ",C.text]})},m)})})]})}function Og(){const i=Mt();return s.jsxs(Qe,{title:"健康与配额",children:[s.jsxs(Ut,{children:[s.jsx("span",{className:"muted",children:i.healthText}),s.jsx("button",{onClick:i.refreshHealth,children:"刷新"})]}),s.jsx("div",{children:s.jsx("span",{className:"muted",children:i.quotaText})}),s.jsx("div",{className:"muted",children:i.workersSummary})]})}function Mg(){const i=Mt();return s.jsxs(Qe,{id:"nav-skills",title:"技能与 MCP",children:[s.jsx("div",{className:"muted",children:"反映宿主租户 home,容器内 home 可能不同;重载只在 schema 枚举里,当前 pin 的二进制拒绝时原样 502;OAuth 只发起登录,不代表登录完成。"}),s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.refreshSkills,children:"刷新"}),s.jsx("span",{className:"muted",children:i.skillMsg})]}),s.jsx("h3",{children:"技能"}),i.skillError?s.jsx("div",{className:"muted",children:i.skillError}):s.jsx(Ml,{empty:"暂无技能",items:i.skills.map((r,m)=>s.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:"",r.detail?" - "+r.detail:""]},m))}),s.jsx("h3",{children:"应用"}),s.jsx(Ml,{empty:"暂无应用",items:i.apps.map((r,m)=>s.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:""]},m))}),s.jsx("h3",{children:"MCP 服务"}),s.jsx(Ml,{empty:"暂无 MCP 服务",items:i.mcpServers.map((r,m)=>{const o=r.detail||r.details||r.state||"";return s.jsxs("span",{className:"row-main",children:[r.name||r.id||""," | 状态 ",r.status||"",o?" | "+o:""]},m)})})]})}function zg(){const i=Mt(),[r,m]=v.useState("");return s.jsxs(Qe,{title:"MCP 操作",children:[s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.reloadMcp,children:"重载配置"}),s.jsx("span",{className:"muted",children:i.mcpMsg})]}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"MCP 服务名",value:r,onChange:o=>m(o.target.value)}),s.jsx("button",{onClick:()=>void i.mcpOauth(r),children:"发起 OAuth 登录"}),s.jsx("span",{className:"muted",children:i.mcpOauthMsg})]}),i.mcpOauthBox?s.jsx("pre",{children:i.mcpOauthBox}):null]})}function Rg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(""),[x,w]=v.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("input",{placeholder:"自动化名称(同项目内启用中的名称唯一)",style:{width:"100%"},value:r,onChange:U=>m(U.target.value)}),s.jsx("textarea",{placeholder:"定时任务内容(创建只登记定义与到期状态;执行由后续执行器经 claim 抢单后建任务,不另起调度器)",value:o,onChange:U=>_(U.target.value)}),s.jsxs(Ut,{children:[s.jsx("input",{placeholder:"间隔秒数(默认 86400,最小 60)",style:{width:"40%"},value:C,onChange:U=>N(U.target.value)}),s.jsx("input",{placeholder:"仓库(可选)",style:{width:"40%"},value:x,onChange:U=>w(U.target.value)}),s.jsx("button",{className:"primary",onClick:async()=>{await i.createAutomation(r,o,C,x),m(""),_(""),N(""),w("")},children:"创建自动化"}),s.jsx("button",{onClick:i.refreshAutomations,children:"刷新自动化"}),s.jsx("span",{className:"muted",children:i.autoMsg})]}),s.jsx(Ml,{empty:"(暂无自动化)",items:i.automations.map(U=>s.jsxs("span",{className:"row-main",children:["[",U.status,U.due?"|到期":"","] ",U.name,"|每 ",U.interval_seconds," 秒|下次 ",Ga(U.next_run_at),U.status==="active"?s.jsxs(s.Fragment,{children:[" ",s.jsx("button",{onClick:()=>i.cancelAutomation(U.id),children:"取消"})]}):null]},U.id))})]})}function Dg(){var m,o,_,C;const i=Mt(),r=i.triage;return i.triageError?s.jsx("div",{className:"muted",children:i.triageError}):r?s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["到期自动化(",((m=r.counts)==null?void 0:m.automations_due)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.automations_due||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:[N.name,"|每 ",N.interval_seconds," 秒"]},x))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["失败/中断任务(",((o=r.counts)==null?void 0:o.failed_tasks)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.failed_tasks||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:[De(N.id),"|",N.status,"|",String(N.prompt||"").slice(0,80)]},x))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["待处理后续消息(",((_=r.counts)==null?void 0:_.pending_followups)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.pending_followups||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:["任务 ",De(N.task_id),"|",String(N.body||"").slice(0,80)]},x))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["最近自动化产出(",((C=r.counts)==null?void 0:C.recent_runs)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.recent_runs||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:[De(N.automation_id),"|",N.status,N.task_id?"|任务 "+De(N.task_id):"",N.task_status?"|"+N.task_status:""]},x))})]})]}):s.jsx("div",{className:"muted",children:"(先选项目)"})}function Ug(){return s.jsx(Qe,{id:"nav-automations",title:"自动化",children:s.jsx(Rg,{})})}function Hg(){const i=Mt();return s.jsxs(Qe,{id:"nav-triage",title:"分诊收件箱",children:[s.jsx(Ut,{children:s.jsx("button",{onClick:i.refreshTriage,children:"刷新分诊"})}),s.jsx(Dg,{})]})}const Bg=[["#sec-dispatch","派发"],["#sec-tasks","任务"],["#sec-conv","对话"],["#sec-projects","项目"],["#sec-env","环境"],["#sec-workers","Workers"],["#sec-skills","技能"],["#sec-automations","自动化"],["#sec-triage","分诊"],["#sec-admin","管理区"],["#sec-key","API Key"]];function qg(){return s.jsxs("header",{className:"dash-topbar",children:[s.jsxs("div",{className:"dash-topbar-row",children:[s.jsx("span",{className:"dash-brand",children:"Codex 命令台"}),s.jsx(Yg,{}),s.jsx("span",{className:"muted dash-hide-sm",children:s.jsx(wg,{})}),s.jsx("span",{className:"muted dash-hide-sm",children:s.jsx(Gg,{})}),s.jsx("span",{className:"muted dash-stamp",children:s.jsx(kg,{})})]}),s.jsx("nav",{className:"dash-nav","aria-label":"页面导航",children:Bg.map(([i,r])=>s.jsx("a",{href:i,children:r},i))})]})}function Yg(){const i=Mt();return s.jsx("span",{className:i.keySaved?"dash-status ok":"dash-status off",children:i.keySaved?"● 已连接":"○ 未连接"})}function wg(){return s.jsx(s.Fragment,{children:Mt().healthText})}function Gg(){return s.jsx(s.Fragment,{children:Mt().quotaText})}function kg(){return s.jsxs(s.Fragment,{children:["自动刷新 · 每 10 秒 · 已刷新 ",Mt().refreshStamp]})}function Qg(){const i=ag();tg(m=>i.refreshAll(m),1e4),eg(()=>i.refreshSlow(),6e4);const r=()=>{var m;(m=document.getElementById("sec-dispatch"))==null||m.scrollIntoView({behavior:"smooth"})};return s.jsxs(Gh.Provider,{value:i,children:[s.jsx(qg,{}),s.jsxs("main",{className:"dash-page",children:[s.jsx(ng,{}),s.jsxs("div",{className:"dash-col dash-col-left",children:[s.jsxs("section",{id:"sec-tasks",className:"dash-section card",children:[s.jsx("h2",{children:"任务列表"}),s.jsx(cg,{onNew:r})]}),s.jsxs("section",{id:"sec-projects",className:"dash-section",children:[s.jsx(_g,{}),s.jsx(Eg,{})]})]}),s.jsxs("div",{className:"dash-col dash-col-mid",children:[s.jsx("section",{id:"sec-dispatch",className:"dash-section",children:s.jsx(ug,{})}),s.jsxs("section",{id:"sec-conv",className:"dash-section",children:[s.jsxs("div",{className:"card",children:[s.jsx("h2",{children:"对话"}),s.jsx(mg,{})]}),s.jsx(xg,{})]})]}),s.jsxs("div",{className:"dash-col dash-col-right",children:[s.jsxs("section",{id:"sec-env",className:"dash-section",children:[s.jsx(Ng,{}),s.jsx(Cg,{})]}),s.jsxs("section",{id:"sec-workers",className:"dash-section",children:[s.jsx(Ag,{}),s.jsx(Og,{})]}),s.jsxs("section",{id:"sec-skills",className:"dash-section",children:[s.jsx(Mg,{}),s.jsx(zg,{})]}),s.jsx("section",{id:"sec-automations",className:"dash-section",children:s.jsx(Ug,{})}),s.jsx("section",{id:"sec-triage",className:"dash-section",children:s.jsx(Hg,{})}),s.jsx("section",{id:"sec-admin",className:"dash-section",children:s.jsx(Tg,{})}),s.jsx("section",{id:"sec-key",className:"dash-section",children:s.jsx(jg,{})})]})]})]})}Qy.createRoot(document.getElementById("root")).render(s.jsx(Uy.StrictMode,{children:s.jsx(Qg,{})})); +`),C(X||"(暂无 result/error 输出)")}catch{}Zt(H.id),Pe(H.id),qe(H.id),Tl(H.id),da(H),sl(H.id),fl(H.id),Gt(H.id),Ul(H.id),Dl(H.id)}},[Zt,Pe,qe,Tl,da,sl,fl,Gt,Ul,Dl]),ma=v.useCallback(async H=>{const D=ne.current;if(!D)return;const X={cancel:"确定取消该任务吗?",merge:"确定把 completed 任务标为 merged 吗?",pr:"确定为该任务提 PR 吗?(会在仓库真实建 PR)"};if(!(X[H]&&!window.confirm(X[H])))try{const K=await P($.taskAction(D.id,H),"POST",{});x(H+" 已提交:"+JSON.stringify(K).slice(0,300)),r(),await ge(D.id)}catch(K){x(H+" 失败:"+K.message)}},[ge,r]),su=v.useCallback(async()=>{const H=ne.current;if(H)try{const D=await P($.taskCost(H.id));b(JSON.stringify(D,null,2).slice(0,4e3))}catch(D){b("查成本失败:"+D.message)}},[]),fu=v.useCallback(async H=>{const D=ne.current;if(D){if(!H.trim()){dt("分支消息必填");return}if(!uu.includes(D.status)){dt("仅终态任务可分支");return}try{const X=await P($.taskFork(D.id),"POST",{message:H.trim()});dt("分支任务已建:"+X.id.slice(0,8)),r()}catch(X){dt("分支失败:"+X.message)}}},[r]),Fl=v.useCallback(async H=>{const D=ne.current;if(D)try{await P($.taskReviews(D.id),"POST",H),Vt("评审已登记(requested)"),await qe(D.id)}catch(X){Vt("登记评审需求失败:"+X.message)}},[qe]),Ee=v.useCallback(H=>{const D=ne.current;if(!D)return;const X=window.prompt("输入该条评审的 findings(将写回记录并标为 completed):");X!==null&&P($.taskReviewFindings(D.id,H),"POST",{findings:X}).then(()=>void qe(D.id)).catch(K=>Vt("写 findings 失败:"+K.message))},[qe]),rl=v.useCallback((H,D)=>{const X=ne.current;if(!X)return;const K=D==="approved"?"approve":"deny";P($.taskApprovalDecision(X.id,H,K),"POST",{}).then(()=>{mt("已记录"+(D==="approved"?"允许":"拒绝")+"(当前版本只留回执,不拦截实时行为)"),Tl(X.id)}).catch(O=>mt("决定失败:"+O.message))},[Tl]),Ne=v.useCallback(async(H,D,X)=>{const K=ne.current;if(K){if(!D.trim()){ae("目标任务 id 不能为空");return}if(!X.trim()){ae("消息正文不能为空");return}try{const O=await P($.taskMessagesTo(D.trim()),"POST",{from_task_id:K.id,body:X.trim(),mode:H});ae("已发送("+O.delivery+")"),await fl(K.id)}catch(O){ae("发送失败:"+O.message)}}},[fl]),ru=v.useCallback((H,D)=>{const X=ne.current;if(!X)return;if(!["completed","failed","interrupted"].includes(X.status)){oe("仅 completed/failed/interrupted 任务可操作线程(merged/merge-failed 不可改,服务端同样 409)");return}const K={};if(H==="rename"){if(!D.trim()){oe("新线程名不能为空");return}K.name=D.trim()}P($.taskThreadAction(X.id,H),"POST",K).then(O=>{oe(H+" 已提交:"+JSON.stringify(O).slice(0,300)),Gt(X.id),Ul(X.id)}).catch(O=>oe(H+" 失败:"+O.message))},[Gt,Ul]),ou=v.useCallback(async H=>{const D=ne.current;if(!D)return;const X=H.trim();if(!X){Ve("消息不能为空");return}try{uu.includes(D.status)&&D.status!=="merged"?(await P($.taskContinue(D.id),"POST",{message:X}),Ve("已重新排队,同一会话继续"),r(),await ge(D.id)):["queued","running"].includes(D.status)?(await P($.taskFollowups(D.id),"POST",{body:X,mode:"direct"}),Ve("已直接发送"),await Zt(D.id),await Pe(D.id)):Ve("merged/merge-failed 任务不可继续,也不可发后续消息")}catch(K){Ve("发送失败:"+K.message)}},[ge,r,Zt,Pe]),du=v.useCallback(async()=>{const H=ne.current;if(!H){_e("先选一个任务");return}try{const D=await P($.taskTrace(H.id)),X=new Blob([JSON.stringify({task_id:H.id,status:D.status,note:D.note||"",count:(D.entries||[]).length,entries:D.entries||[]},null,2)],{type:"application/json"}),K=document.createElement("a");K.href=URL.createObjectURL(X),K.download="trace-"+H.id.slice(0,8)+".json",document.body.appendChild(K),K.click(),K.remove(),setTimeout(()=>URL.revokeObjectURL(K.href),1e3),_e("已下载完整链路 "+(D.entries||[]).length+" 条")}catch(D){_e("下载失败:"+D.message)}},[]);return v.useEffect(()=>()=>ue(),[ue]),{currentTask:m,detailBody:_,actionMsg:N,actionReasons:w,costBox:G,costSummary:B,forkVisible:at,setForkVisible:et,forkMsg:L,coordChildren:zt,agents:nt,agentsNote:te,reviews:yt,reviewMsg:he,reviewError:Ft,traceEntries:Ie,traceNote:Y,traceDone:lt,traceKind:St,setTraceKind:ve,traceMsg:Ue,followups:y,approvals:W,approvalMsg:pt,peerMessages:_t,peerMsg:ut,threadText:ka,threadGateNote:Xe,threadMsg:Rt,threadList:Kl,chatMsg:oa,chatHistory:zl,showDetail:ge,refreshDetailLists:Xa,doAction:ma,taskCost:su,forkTask:fu,postReview:Fl,submitFindings:Ee,decideApproval:rl,postPeer:Ne,threadAction:ru,sendChatMessage:ou,downloadTrace:du,refreshReviews:()=>void qe(),refreshApprovals:()=>void Tl()}}function Py(i){const[r,m]=v.useState([]),[o,_]=v.useState(""),[C,N]=v.useState(null),[x,w]=v.useState(""),U=v.useCallback(async tt=>{const at=tt!==void 0?tt:i();if(!at){m([]);return}try{const et=await P($.projectAutomations(at));m(et.automations||[])}catch(et){_("自动化加载失败:"+et.message)}},[i]),G=v.useCallback(async(tt,at,et,L)=>{const dt=i();if(!dt){_("先选项目");return}if(!tt.trim()){_("自动化名称必填");return}if(!at.trim()){_("定时任务内容必填");return}const zt={name:tt.trim(),prompt:at.trim()};et.trim()&&(zt.interval_seconds=parseInt(et.trim(),10)),L.trim()&&(zt.repo_url=L.trim());try{await P($.projectAutomations(dt),"POST",zt),_("自动化已创建(登记定义,到期后由执行器认领)"),await U(dt)}catch(Jt){_("创建失败:"+Jt.message)}},[i,U]),b=v.useCallback(tt=>{const at=i();at&&P($.projectAutomationCancel(at,tt),"POST",{}).then(()=>{_("自动化已取消"),U(at)}).catch(et=>_("取消失败:"+et.message))},[i,U]),B=v.useCallback(async tt=>{const at=tt!==void 0?tt:i();if(!at){N(null);return}try{const et=await P($.projectTriage(at));N(et),w("")}catch(et){w("分诊加载失败:"+et.message)}},[i]);return{automations:r,autoMsg:o,triage:C,triageError:x,refreshAutomations:U,createAutomation:G,cancelAutomation:b,refreshTriage:B}}function tg(i,r){const m=v.useRef(i);m.current=i,v.useEffect(()=>{const o=setInterval(()=>{const _=document.activeElement;m.current(_?_.tagName==="SELECT":!1)},r);return()=>clearInterval(o)},[r])}function eg(i,r){const m=v.useRef(i);m.current=i,v.useEffect(()=>{const o=setInterval(()=>m.current(),r);return()=>clearInterval(o)},[r])}function lg(i){const r=m=>String(m).padStart(2,"0");return r(i.getHours())+":"+r(i.getMinutes())+":"+r(i.getSeconds())}function ag(){var et;const i=Wy(),r=$y(),m=v.useRef("");m.current=i.projectId;const o=v.useCallback(()=>m.current,[]),_=Py(o),C=v.useCallback(L=>{const dt=i.projects.find(zt=>zt.id===L);return dt&&dt.my_role||null},[i.projects]),N=v.useCallback(()=>{r.refreshTasks(void 0,m.current)},[r]),x=Iy(C,N),[w,U]=v.useState("--:--:--"),G=v.useCallback(L=>{i.setProjectId(L),m.current=L,r.refreshTasks(L),i.refreshEnvs(L),i.refreshMembers(L),i.refreshSkills(L),_.refreshAutomations(L),_.refreshTriage(L)},[i,r,_]),b=(et=i.projects[0])==null?void 0:et.id;v.useEffect(()=>{!i.projectId&&b&&G(b)},[i.projectId,b,G]);const B=v.useCallback(L=>{i.saveKeyInput(L),L.trim()&&(i.refreshHealth(),i.refreshProjects(),i.refreshWorkers(),m.current&&(r.refreshTasks(m.current),i.refreshEnvs(m.current),i.refreshMembers(m.current)),i.loadRelayModels(),i.loadQuota(),i.loadGithubRepos(),i.probeAdmin())},[i,r]),tt=v.useCallback(L=>{if(U(lg(new Date)),!bl()){i.refreshHealth();return}r.refreshTasks(void 0,m.current),i.refreshHealth(),i.loadQuota(),i.refreshWorkers(),i.refreshMembers(),i.refreshSkills(),_.refreshAutomations(),_.refreshTriage(),x.refreshDetailLists(),L||(i.refreshProjects(),i.refreshEnvs())},[i,r,_,x]),at=v.useCallback(()=>{bl()&&(i.loadRelayModels(),i.loadGithubRepos())},[i]);return v.useEffect(()=>{i.refreshHealth(),i.refreshProjects(),i.refreshWorkers(),i.loadQuota(),i.loadGithubRepos(),bl()&&i.loadRelayModels(),i.probeAdmin()},[]),{keySaved:i.keySaved,keyState:i.keyState,saveKeyInput:B,clearKeyInput:i.clearKeyInput,quotaText:i.quotaText,healthText:i.healthText,refreshHealth:i.refreshHealth,adminGate:i.adminGate,adminBody:i.adminBody,adminResult:i.adminResult,adminUserId:i.adminUserId,setAdminUserId:i.setAdminUserId,adminQuota:i.adminQuota,adminSweep:i.adminSweep,adminBackup:i.adminBackup,projects:i.projects,projectId:i.projectId,projectMsg:i.projectMsg,selectProject:G,refreshProjects:i.refreshProjects,createProject:i.createProject,githubRepos:i.githubRepos,workers:i.workers,workersSummary:i.workersSummary,workersError:i.workersError,refreshWorkers:i.refreshWorkers,members:i.members,memberMsg:i.memberMsg,memberError:i.memberError,refreshMembers:()=>void i.refreshMembers(),inviteMember:i.inviteMember,changeMemberRole:i.changeMemberRole,skills:i.skills,apps:i.apps,mcpServers:i.mcpServers,skillMsg:i.skillMsg,skillError:i.skillError,mcpMsg:i.mcpMsg,mcpOauthMsg:i.mcpOauthMsg,mcpOauthBox:i.mcpOauthBox,refreshSkills:()=>void i.refreshSkills(),reloadMcp:i.reloadMcp,mcpOauth:i.mcpOauth,envs:i.envs,envCount:i.envCount,envMsg:i.envMsg,envRepoLine:i.envRepoLine,envRepoBar:i.envRepoBar,envRepoMsg:i.envRepoMsg,envSelect:i.envSelect,setEnvSelect:i.setEnvSelect,refreshEnvs:()=>void i.refreshEnvs(),createEnv:i.createEnv,archiveEnv:i.archiveEnv,saveEnvRepo:i.saveEnvRepo,models:i.models,modelCustomVisible:i.modelCustomVisible,tasks:r.tasks,taskCountText:r.taskCountText,taskError:r.taskError,refreshTasks:()=>void r.refreshTasks(void 0,m.current),statusFilter:r.statusFilter,setStatusFilter:r.setStatusFilter,executorFilter:r.executorFilter,setExecutorFilter:r.setExecutorFilter,searchText:r.searchText,setSearchText:r.setSearchText,filteredTasks:r.filteredTasks,currentTask:x.currentTask,detailBody:x.detailBody,actionMsg:x.actionMsg,actionReasons:x.actionReasons,showDetail:L=>void x.showDetail(L),doAction:x.doAction,taskCost:x.taskCost,costBox:x.costBox,costSummary:x.costSummary,forkVisible:x.forkVisible,setForkVisible:x.setForkVisible,forkTask:x.forkTask,forkMsg:x.forkMsg,coordChildren:x.coordChildren,coordText:"",agents:x.agents,agentsNote:x.agentsNote,reviews:x.reviews,reviewMsg:x.reviewMsg,reviewError:x.reviewError,refreshReviews:x.refreshReviews,postReview:x.postReview,submitFindings:x.submitFindings,traceEntries:x.traceEntries,traceNote:x.traceNote,traceDone:x.traceDone,traceKind:x.traceKind,setTraceKind:x.setTraceKind,downloadTrace:x.downloadTrace,traceMsg:x.traceMsg,sendChatMessage:x.sendChatMessage,chatMsg:x.chatMsg,chatHistory:x.chatHistory,followups:x.followups,approvals:x.approvals,approvalMsg:x.approvalMsg,refreshApprovals:x.refreshApprovals,decideApproval:x.decideApproval,peerMessages:x.peerMessages,peerMsg:x.peerMsg,postPeer:x.postPeer,automations:_.automations,autoMsg:_.autoMsg,refreshAutomations:()=>void _.refreshAutomations(),createAutomation:_.createAutomation,cancelAutomation:_.cancelAutomation,triage:_.triage,triageError:_.triageError,refreshTriage:()=>void _.refreshTriage(),threadText:x.threadText,threadGateNote:x.threadGateNote,threadMsg:x.threadMsg,threadList:x.threadList,threadAction:x.threadAction,dispatch:async(L,dt)=>{const zt=await r.dispatch(L,dt);return r.refreshTasks(m.current),zt},dispatchMsg:"",refreshAll:tt,refreshSlow:at,refreshStamp:w}}function nu({label:i,value:r,sub:m}){return s.jsxs("div",{className:"dash-card data-card",children:[s.jsx("div",{className:"dash-card-label",children:i}),s.jsx("div",{className:"dash-card-value",children:r}),s.jsx("div",{className:"muted",children:m})]})}function ng(){const i=Mt(),r=i.healthText==="未加载"?"未加载":i.healthText.includes("worker_ok=true")?"正常":i.healthText.includes("worker_ok=false")?"异常":i.healthText.includes("加载失败")?"加载失败":"未知",m=i.quotaText.match(/剩余 \$([0-9.]+)/),o=i.quotaText.includes("加载失败")?"加载失败":i.quotaText.includes("未填 key")||i.quotaText==="未加载"?"未加载":m?"$"+m[1]:"配额",_=["running","completed","failed","queued","merged","interrupted"].map(b=>i.tasks.filter(B=>B.status===b).length).map((b,B)=>["running","completed","failed","queued","merged","interrupted"][B]+" "+b).join(" | "),C=i.projects.find(b=>b.id===i.projectId),N=i.taskError?{value:"加载失败",sub:i.taskError}:i.projectId?{value:String(i.tasks.length),sub:i.taskCountText+" | "+_+(C?" | "+C.name:"")}:{value:"先选项目",sub:i.projectMsg||"项目加载后自动选第一个"};let x;if(i.workersError)x={value:"加载失败",sub:i.workersError};else if(i.workers===null)x={value:i.workersSummary||"未加载",sub:"完整 worker 清单仅全局管理员可见"};else{const b=i.workers.filter(B=>{if(B.alive!==void 0&&B.alive!==null)return!!B.alive;const tt=kh(B).age;return tt!==null&&tt<=120}).length;x={value:b+" 在线 / "+i.workers.length,sub:i.workers.length-b+" 离线"}}const w=i.projectMsg.includes("加载失败")?{value:"加载失败",sub:i.projectMsg}:{value:i.projects.length+" 个",sub:C?"当前项目:"+C.name:"未选项目(加载后自动选第一个)"},U=[i.envMsg,i.memberError,i.skillError].filter(b=>b&&b.includes("失败")),G=i.projectId?U.length?{value:"部分加载失败",sub:U.join(" | ")}:{value:i.envs.length+" 个环境",sub:i.members.length+" 成员 | "+i.skills.length+" 技能 | "+i.apps.length+" 应用 | "+i.mcpServers.length+" MCP"}:{value:"先选项目",sub:"选项目后显示环境 / 成员 / 技能计数"};return s.jsxs("section",{className:"dash-cards","aria-label":"数据卡片",children:[s.jsx(nu,{label:"健康",value:r,sub:i.healthText}),s.jsx(nu,{label:"配额",value:o,sub:i.quotaText}),s.jsx(nu,{label:"任务",value:N.value,sub:N.sub}),s.jsx(nu,{label:"Workers",value:x.value,sub:x.sub}),s.jsx(nu,{label:"项目",value:w.value,sub:w.sub}),s.jsx(nu,{label:"项目数据",value:G.value,sub:G.sub})]})}function Qe({id:i,className:r,title:m,children:o}){return s.jsxs("section",{id:i,className:"card"+(r?" "+r:""),children:[m?s.jsx("h2",{children:m}):null,o]})}function Ut({children:i}){return s.jsx("div",{className:"bar",children:i})}function Ml({items:i,empty:r}){return i.length?s.jsx("ul",{className:"data-list",children:i.map((m,o)=>s.jsx("li",{children:m},o))}):s.jsx("div",{className:"muted",children:r||"(暂无)"})}function cu({children:i}){return s.jsx("ul",{className:"data-list",children:i})}function ug(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(!1),[x,w]=v.useState(!1),[U,G]=v.useState(!1),[b,B]=v.useState("docker"),[tt,at]=v.useState(""),[et,L]=v.useState(""),[dt,zt]=v.useState(""),[Jt,nt]=v.useState(""),[Xt,te]=v.useState(""),[ct,yt]=v.useState(""),[re,he]=v.useState(""),Vt=v.useRef(null),Ft=v.useRef(null),le=v.useRef(null),[Ie,vt]=v.useState("");async function Y(){var Ue,_e,y;if(vt(""),!i.projectId){vt("先选项目");return}if(!r.trim()){vt("prompt 必填");return}const A={project_id:i.projectId,prompt:r.trim()};i.envSelect&&(A.environment_id=i.envSelect),b&&(A.executor=b);const lt=et.trim()||tt;lt&&(A.model=lt),dt&&(A.effort=dt);const gt=ct.trim()||Xt;if(gt&&(A.child_model=gt),re&&(A.child_effort=re),Jt&&(A.approval=Jt),U){if(Jt==="full"){vt("计划模式不能与完全访问同用");return}if(C||x){vt("计划模式不能与 goal 模式同用");return}A.plan=1}x?(A.goal_mode=1,A.no_time_limit=1):C&&(A.goal_mode=1);const St=o.trim();if(St){try{A.coordinator_parts=JSON.parse(St)}catch{vt("协调员子任务 JSON 解析失败");return}if(!Array.isArray(A.coordinator_parts)){vt("协调员子任务必须是数组");return}if(C||x||U){vt("协调员任务不能与 goal/计划模式同用:协调员任务本身不跑模型回合,请取消 goal/计划勾选,或清空协调员 JSON");return}}const ve=Fy(((Ue=Vt.current)==null?void 0:Ue.files)||null,((_e=Ft.current)==null?void 0:_e.files)||null,((y=le.current)==null?void 0:y.files)||null);try{const R=await i.dispatch(A,ve);vt(R),m(""),_(""),Vt.current&&(Vt.current.value=""),Ft.current&&(Ft.current.value=""),le.current&&(le.current.value="")}catch(R){vt("提交失败:"+((R==null?void 0:R.message)||String(R)))}}return s.jsxs(Qe,{id:"nav-newtask",className:"composer",title:"新建任务",children:[s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"环境",value:i.envSelect,onChange:A=>i.setEnvSelect(A.target.value),children:[s.jsx("option",{value:"",children:"环境:不指定(走项目仓库)"}),i.envs.map(A=>s.jsxs("option",{value:A.id,disabled:A.status!=="ready",children:[A.name,"(",A.status,")"]},A.id))]}),s.jsxs("select",{"aria-label":"执行器",value:b,onChange:A=>B(A.target.value),children:[s.jsx("option",{value:"docker",children:"docker(默认,多用户下隔离最强)"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"cloud",children:"cloud"})]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:C,onChange:A=>N(A.target.checked)})," goal 模式"]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:x,onChange:A=>w(A.target.checked)})," goal 模式无敌版"]}),s.jsxs("label",{children:[s.jsx("input",{type:"checkbox",checked:U,onChange:A=>G(A.target.checked)})," 计划模式(只读)"]})]}),s.jsx("textarea",{className:"prompt stacked",placeholder:"任务 prompt(必填)",value:r,onChange:A=>m(A.target.value)}),s.jsx("textarea",{className:"coord stacked",placeholder:"协调员子任务 JSON(可选),留空为普通任务",value:o,onChange:A=>_(A.target.value)}),s.jsxs("div",{className:"muted",children:["协调员格式:[","{",'"name":"后端","prompt":"做后端"',"}",",","{",'"name":"前端","prompt":"做前端"',"}","];提交后 worker 并行建子任务、等齐、合流汇总。不能与 goal/计划模式同用。协调员与 goal/计划互斥:勾了 goal 或计划模式时不要填协调员 JSON,提交前会校验并拦截。子任务费用记父任务创建人账;父任务创建时按分工数预留配额,余额不足时整个父任务被挡下。"]}),s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"模型",value:tt,onChange:A=>at(A.target.value),children:[s.jsx("option",{value:"",children:"模型:默认(跟随配置)"}),i.models.map(A=>s.jsx("option",{value:A,children:A},A))]}),i.modelCustomVisible?s.jsx("input",{type:"text",placeholder:"手动输入模型(中转列表取不到时用)",value:et,onChange:A=>L(A.target.value)}):null,s.jsxs("select",{"aria-label":"推理强度",value:dt,onChange:A=>zt(A.target.value),children:[s.jsx("option",{value:"",children:"推理强度:默认(跟随配置)"}),Yh.map(A=>s.jsx("option",{value:A,children:A},A))]}),s.jsxs("select",{"aria-label":"权限",value:Jt,onChange:A=>nt(A.target.value),children:[s.jsx("option",{value:"",children:"权限:默认(跟随配置)"}),s.jsx("option",{value:"ask",children:"请求批准"}),s.jsx("option",{value:"auto",children:"帮我批准"}),s.jsx("option",{value:"full",children:"完全访问"})]})]}),s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"子任务模型",value:Xt,onChange:A=>te(A.target.value),children:[s.jsx("option",{value:"",children:"子任务模型:跟随本任务模型"}),i.models.map(A=>s.jsx("option",{value:A,children:A},A))]}),s.jsx("input",{type:"text",placeholder:"子任务模型手动输入(中转列表里没有时填,如 gpt-6-luna;留空=跟随本任务模型)",value:ct,onChange:A=>yt(A.target.value)}),s.jsxs("select",{"aria-label":"子任务强度",value:re,onChange:A=>he(A.target.value),children:[s.jsx("option",{value:"",children:"子任务强度:跟随本任务强度"}),Yh.map(A=>s.jsx("option",{value:A,children:A},A))]})]}),s.jsx("div",{className:"muted",children:"子任务模型/强度是派生默认:本任务用 marker task-create 或协调员分工派生的子任务,未显式写模型/强度时用它;块/分工里显式写了则覆盖它。也可以不在这里填、直接在 prompt 里写“子任务用 gpt-6-luna max”,建任务时服务端会解析成同一对字段(任务详情里可核对)。"}),C?s.jsx("div",{className:"muted",children:"goal 模式:输入框内容即目标,不需要专用 prompt 与验收命令;不限轮次,模型确认达成后在回复末尾输出“目标已达成”即结束,未达成会一直运行,可用取消停止。"}):null,x?s.jsx("div",{className:"muted",children:"goal 模式无敌版:goal 模式 + 任务不限时(去掉 worker/docker 总超时;单轮 600 秒护栏还在,不限的是任务总时长与总轮次)。服务端默认的自动续跑与断点镜像同时生效。"}):null,s.jsxs(Ut,{children:[s.jsx("span",{className:"muted",children:"附件(放进任务工作区,图片与普通文件不区分):"}),s.jsx("input",{ref:Vt,type:"file",multiple:!0,title:"文件"}),s.jsx("input",{ref:Ft,type:"file",multiple:!0,title:"文件夹",webkitdirectory:""}),s.jsx("input",{ref:le,type:"file",accept:"image/*",multiple:!0,title:"图片"})]}),s.jsxs(Ut,{children:[s.jsx("button",{className:"seal",onClick:Y,children:"提交任务"}),s.jsx("span",{className:"muted",children:Ie||i.dispatchMsg})]})]})}function Qh(i){const r=(i.prompt||"").trim();return r?[...r][0]:i.id?[...i.id][0]:"?"}function zc(i){const r=Math.max(0,Math.floor(i));if(r<60)return r+"秒";if(r<3600){const _=Math.floor(r/60),C=r%60;return C?_+"分"+C+"秒":_+"分"}if(r<86400){const _=Math.floor(r/3600),C=Math.floor(r%3600/60);return C?_+"小时"+C+"分":_+"小时"}const m=Math.floor(r/86400),o=Math.floor(r%86400/3600);return o?m+"天"+o+"小时":m+"天"}function iu(i){if(i==null)return null;const r=Number(i);return Number.isFinite(r)?r:null}function Xh(i){const r=Date.now()/1e3,m=iu(i.started_at),o=iu(i.finished_at),_=iu(i.created_at);return m!==null&&o!==null&&o>=m?[zc(o-m),"总耗时:开始→结束(末次认领的执行时长)"]:m!==null&&i.status==="running"?["进行中 "+zc(r-m),"总耗时:进行中,已用时长从开始算起,随刷新更新"]:_!==null&&o!==null&&o>=_?[zc(o-_),"总耗时:创建→完成(含排队等待;无开始时间时的兜底口径)"]:_!==null&&(i.status==="queued"||i.status==="running")?[(i.status==="queued"?"排队中 ":"进行中 ")+zc(r-_),"总耗时:从创建算起的已用时长(无开始时间时的兜底口径)"]:["—","总耗时:无可用时间戳"]}function ig(i){if(i==null||!Number.isFinite(Number(i)))return"—";const r=Number(i)/1e6;return"$"+(r>0&&r<.01?r.toFixed(4):r.toFixed(2))}function Vh(i){const r=iu(i.total_tokens);if(r!==null)return[r.toLocaleString()+" token","token:服务端 total_tokens"];const m=iu(i.actual_tokens),o=iu(i.estimated_tokens);return m!==null||o!==null?[((m||0)+(o||0)).toLocaleString()+" token","token:actual + estimated 分项加总"]:["token —","token:本任务对象未带 token 字段;单任务真数在详情的成本里可查,不逐个调成本接口、不编造"]}function cg({onNew:i}){const r=Mt();return s.jsxs("div",{children:[s.jsxs("div",{className:"search-box",children:[s.jsxs("svg",{viewBox:"0 0 24 24",width:"18",height:"18",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round","aria-hidden":"true",children:[s.jsx("circle",{cx:"11",cy:"11",r:"7"}),s.jsx("path",{d:"M21 21l-4.3-4.3"})]}),s.jsx("input",{type:"text",placeholder:"搜索","aria-label":"搜索任务",value:r.searchText,onChange:m=>r.setSearchText(m.target.value)})]}),s.jsx("div",{className:"bar",children:s.jsxs("select",{"aria-label":"项目",value:r.projectId,onChange:m=>r.selectProject(m.target.value),children:[r.projects.length===0?s.jsx("option",{value:"",children:"(先加载项目)"}):null,r.projects.map(m=>s.jsxs("option",{value:m.id,children:[m.name," (",De(m.id),")"]},m.id))]})}),s.jsxs("div",{className:"list-section-head",children:[s.jsx("span",{children:"主要聊天"}),s.jsx("button",{type:"button","aria-label":"派发新任务",title:"派发新任务",onClick:i,children:"+"})]}),s.jsxs("div",{className:"bar",children:[s.jsxs("select",{"aria-label":"状态筛选",value:r.statusFilter,onChange:m=>r.setStatusFilter(m.target.value),children:[s.jsx("option",{value:"",children:"状态:全部"}),["queued","running","completed","failed","interrupted","merged","merge-failed"].map(m=>s.jsx("option",{value:m,children:m},m))]}),s.jsxs("select",{"aria-label":"执行器筛选",value:r.executorFilter,onChange:m=>r.setExecutorFilter(m.target.value),children:[s.jsx("option",{value:"",children:"执行器:全部"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"docker",children:"docker"}),s.jsx("option",{value:"cloud",children:"cloud"})]})]}),s.jsxs("div",{className:"bar",children:[s.jsx("button",{onClick:r.refreshTasks,children:"刷新"}),s.jsx("span",{className:"muted",children:r.taskCountText})]}),r.taskError?s.jsx("div",{className:"err",children:r.taskError}):r.projectId?r.filteredTasks.length===0?s.jsx("div",{className:"muted",children:r.tasks.length?"没有符合筛选条件的任务":"该项目暂无任务"}):s.jsx("ul",{className:"issue-list",children:r.filteredTasks.slice().reverse().map(m=>{var w;const[o,_]=Xh(m),[C,N]=Vh(m),x=Qh(m);return s.jsxs("li",{className:"issue-item"+(((w=r.currentTask)==null?void 0:w.id)===m.id?" selected":""),onClick:()=>r.showDetail(m.id),children:[s.jsx("span",{className:"issue-state st-"+m.status,"aria-hidden":"true"}),s.jsx("span",{className:"issue-first",title:"任务首字:"+x,"aria-hidden":"true",children:x}),s.jsxs("span",{style:{flex:1,minWidth:0},children:[s.jsxs("div",{className:"issue-title",children:[m.plan?"[计划] ":"",m.forked_from?"[分支] ":"",m.coordinator_parts?"[协调] ":"",m.parent_task_id?"[协调子任务] ":"",String(m.prompt||De(m.id)).slice(0,60)]}),s.jsxs("div",{className:"issue-meta",children:[De(m.id)," · ",s.jsx("span",{className:"st-"+m.status,children:m.status})," · ",m.executor||"",m.updated_at?" · "+new Date(m.updated_at*1e3).toLocaleString():""," · ",s.jsxs("span",{title:_,children:["耗时 ",o]})," · ",s.jsx("span",{title:N,children:C})]})]})]},m.id)})}):s.jsx("div",{className:"muted",children:"先选项目"})]})}function sg(i){const r=v.useRef(null),[m,o]=v.useState(!0),_=v.useRef(!0),C=()=>{const N=r.current;if(!N)return;const x=N.scrollHeight-N.scrollTop-N.clientHeight<80;_.current=x,o(x)};return v.useEffect(()=>{_.current&&r.current&&(r.current.scrollTop=r.current.scrollHeight)},[i]),{ref:r,following:m,onScroll:C}}function fg({msg:i}){if(i.role==="status")return s.jsx("div",{className:"chat-status",children:i.text});const r=i.label||(i.role==="user"?"用户":i.role==="assistant"?"助手":"工具");return s.jsxs("div",{className:"gh-comment "+i.role,children:[s.jsx("div",{className:"gh-comment-header",children:s.jsx("span",{className:"gh-comment-author",children:r})}),s.jsx("div",{className:"gh-comment-body",children:i.text})]})}function Lh({messages:i,empty:r}){const{ref:m,following:o,onScroll:_}=sg(i.length);return s.jsxs("div",{className:"chat-list",ref:m,onScroll:_,children:[i.length===0?s.jsx("div",{className:"muted",children:r||"(暂无消息)"}):i.map(C=>s.jsx(fg,{msg:C},C.id)),!o&&i.length>0?s.jsx("button",{className:"chat-follow",onClick:()=>{m.current&&(m.current.scrollTop=m.current.scrollHeight)},children:"回到最新 ↓"}):null]})}function rg({onSend:i,disabled:r,placeholder:m}){const[o,_]=v.useState(""),C=()=>{const N=o.trim();!N||r||(i(N),_(""))};return s.jsxs("div",{className:"gh-comment-box",children:[s.jsx("textarea",{"aria-label":"会话输入",rows:3,placeholder:m||"消息",value:o,disabled:r,onChange:N=>_(N.target.value),onKeyDown:N=>{N.key==="Enter"&&!N.shiftKey&&(N.preventDefault(),C())}}),s.jsx("div",{className:"gh-comment-footer",children:s.jsx("button",{type:"button",className:"primary","aria-label":"发送",disabled:r||!o.trim(),onClick:C,children:"发送"})})]})}function Zh(i,r){const m=i.id||"trace-"+r;if(i.kind==="message"){const o=(i.phase?"["+i.phase+"] ":"")+(i.text||"");return{id:m,role:"assistant",text:i.truncated?o+` +(链路摘要已截断至 300 字,完整回复见右侧任务结果)`:o,label:"助手"}}if(i.kind==="exec"||i.kind==="file"||i.kind==="tool"||i.kind==="call"){const o=i.kind==="exec"?"命令":i.kind==="file"?"文件":i.kind==="tool"?"工具":"调用";return{id:m,role:"tool",text:dr(i),label:o}}return i.kind==="plan"?{id:m,role:"status",text:i.text||""}:i.kind==="reasoning"?{id:m,role:"status",text:"思考:"+(i.summary||"")}:i.kind==="agent-start"?{id:m,role:"status",text:"子代理开始:"+(i.name||"")+(i.prompt?"("+i.prompt+")":"")}:i.kind==="agent-done"?{id:m,role:"status",text:"子代理结束:"+(i.name||"")+" "+(i.status||"")}:{id:m,role:"status",text:dr(i)}}function og(){const i=Mt(),r=v.useMemo(()=>{const m=i.currentTask,o=m&&m.prompt?[{id:"task-prompt",role:"user",text:m.prompt}]:[],C=(i.traceKind?i.traceEntries.filter(x=>x.kind===i.traceKind):i.traceEntries).map((x,w)=>Zh(x,w)),N=i.traceDone?[{id:"trace-done",role:"status",text:"链路已结束("+i.traceDone+")"}]:[];return[...o,...C,...N]},[i.currentTask,i.traceEntries,i.traceKind,i.traceDone]);return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"muted",children:"实时链路"}),s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"链路类型",value:i.traceKind,onChange:m=>i.setTraceKind(m.target.value),children:[s.jsx("option",{value:"",children:"链路类型:全部"}),["exec","file","call","tool","message","reasoning","plan","agent-start","agent-done"].map(m=>s.jsx("option",{value:m,children:m==="exec"?"命令":m==="file"?"文件":m==="call"?"调用":m==="tool"?"工具":m==="message"?"消息":m==="reasoning"?"思考":m==="plan"?"计划":"子代理"},m))]}),s.jsx("button",{onClick:i.downloadTrace,children:"下载完整链路"}),s.jsx("span",{className:"muted",children:i.traceMsg})]}),i.traceNote?s.jsx("div",{children:s.jsx("span",{className:"err",children:i.traceNote})}):null,s.jsx("div",{className:"chat-column",children:s.jsx(Lh,{messages:r,empty:"(暂无链路条目)"})}),s.jsx("div",{className:"muted",children:"对话时间线:首条是本任务 prompt(用户);助手回复来自 message 条目,命令/文件/工具/调用是工具评论框,计划/思考/子代理开始结束是时间线上的状态文字。流式进行中时新条目实时追加;你在底部时自动跟随,往上翻时暂停跟随,点“回到最新”恢复。"})]})}function dg(){const i=Mt(),r=i.currentTask,m=v.useMemo(()=>{if(!r)return[];if(i.chatHistory)return i.chatHistory.messages.map(b=>({id:b.id,role:b.role,text:b.text,label:b.label}));const w=r.prompt?[{id:"task-prompt",role:"user",text:r.prompt}]:[],U=i.traceEntries.filter(b=>b.kind==="message").map((b,B)=>Zh(b,B)),G=i.followups.map((b,B)=>({id:"followup-"+B,role:"user",text:String(b.body||""),label:"后续消息"}));return[...w,...U,...G]},[r,i.chatHistory,i.traceEntries,i.followups]);if(!r)return s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示继续会话"});const o=uu.includes(r.status),_=["queued","running"].includes(r.status),C=o||_,N=o?"终态任务:发送走继续接口(同一会话再跑一轮)":_?"运行中/排队中:发送走后续消息直接发送(跑完当前轮后优先执行)":"merged/merge-failed 任务不可继续,也不可发后续消息",x=i.chatHistory?i.chatHistory.legacy_continue_count??null:null;return s.jsxs("div",{className:"chat-column",children:[x!==null&&x>0?s.jsxs("div",{className:"muted",children:["此前有 ",x," 条继续消息发生在持久化之前,未入库,上面历史不完整;部署后新发的继续消息会正常显示。"]}):null,i.chatHistory&&i.chatHistory.trace_note?s.jsx("div",{className:"muted",children:i.chatHistory.trace_note}):null,s.jsx(Lh,{messages:m,empty:"(暂无会话消息)"}),s.jsx(rg,{disabled:!C,placeholder:"消息",onSend:w=>void i.sendChatMessage(w)}),s.jsxs("div",{className:"muted",children:[N,"。",i.chatMsg]})]})}function mg(){return Mt().currentTask?s.jsxs("div",{className:"conversation",children:[s.jsx(og,{}),s.jsx("div",{className:"conv-divider"}),s.jsx(dg,{})]}):s.jsx("div",{className:"conversation",children:s.jsx("div",{className:"muted",children:"在任务列表里点一条任务,对话和详情就切到该任务;也可以在上面派发一个新任务。"})})}function hg(){const i=Mt(),r=i.currentTask,[m,o]=v.useState("");if(!r)return null;const _=uu.includes(r.status),C=["failed","interrupted","merge-failed"].includes(r.status);return s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("button",{disabled:!C,title:C?"":"仅 failed/interrupted/merge-failed 可重试",onClick:()=>i.doAction("retry"),children:"重试"}),s.jsx("button",{className:"danger",disabled:_,title:_?"终态任务不可取消":"",onClick:()=>i.doAction("cancel"),children:"取消"}),s.jsx("button",{disabled:r.status!=="completed",title:r.status!=="completed"?"仅 completed 可合并":"",onClick:()=>i.doAction("merge"),children:"合并(completed → merged)"}),s.jsx("button",{disabled:r.status!=="merged",title:r.status!=="merged"?"仅 merged 可提 PR":"",onClick:()=>i.doAction("pr"),children:"提 PR(须 merged)"}),_?s.jsx("button",{onClick:()=>i.setForkVisible(!0),children:"分支"}):null,s.jsx("button",{onClick:i.taskCost,children:"查成本"}),s.jsxs("span",{className:"muted",children:[i.actionMsg," ",i.actionReasons]})]}),i.forkVisible?s.jsxs("div",{children:[s.jsx("input",{type:"text",placeholder:"分支首轮消息(必填,带历史的新会话)",style:{width:"100%",boxSizing:"border-box",margin:"6px 0"},value:m,onChange:N=>o(N.target.value)}),s.jsxs(Ut,{children:[s.jsx("button",{className:"seal",onClick:async()=>{await i.forkTask(m),o("")},children:"创建分支任务"}),s.jsx("span",{className:"muted",children:i.forkMsg})]})]}):null]})}function vg(){const i=Mt(),[r,m]=v.useState("uncommittedChanges"),[o,_]=v.useState(""),[C,N]=v.useState(""),[x,w]=v.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("h3",{children:"评审队列"}),s.jsxs("select",{"aria-label":"评审目标",value:r,onChange:U=>m(U.target.value),children:[s.jsx("option",{value:"uncommittedChanges",children:"未提交改动(工作区)"}),s.jsx("option",{value:"baseBranch",children:"与分支的差异"}),s.jsx("option",{value:"commit",children:"指定提交"}),s.jsx("option",{value:"custom",children:"自定义评审指令"})]}),s.jsx("input",{className:"stacked",placeholder:"与分支的差异用:分支名(如 main)",style:{width:"100%"},value:o,onChange:U=>_(U.target.value)}),s.jsx("input",{className:"stacked",placeholder:"指定提交用:提交 sha",style:{width:"100%"},value:C,onChange:U=>N(U.target.value)}),s.jsx("textarea",{placeholder:"自定义评审指令用:评审指令正文",value:x,onChange:U=>w(U.target.value)}),s.jsxs(Ut,{children:[s.jsx("button",{className:"primary",onClick:()=>void i.postReview({target_type:r,branch:o.trim()||void 0,sha:C.trim()||void 0,instructions:x.trim()||void 0}),children:"登记评审需求"}),s.jsx("button",{onClick:i.refreshReviews,children:"刷新队列"}),s.jsx("span",{className:"muted",children:i.reviewMsg})]}),s.jsx("div",{className:"muted",children:"本基线只登记评审需求(requested),不自动跑评审;评审是否执行、结果如何,以评审队列里的记录为准。"}),i.reviewError?s.jsx("div",{className:"muted",children:i.reviewError}):i.reviews.length===0?s.jsx("div",{className:"muted",children:"点任务行查看详情后,点“刷新队列”查看评审记录"}):s.jsx(cu,{children:i.reviews.map(U=>{let G=U.target_type||"";return U.branch&&(G+=":"+U.branch),U.sha&&(G+=":"+String(U.sha).slice(0,12)),U.instructions&&(G+=":"+String(U.instructions).slice(0,80)),s.jsxs("li",{children:[s.jsxs("span",{className:"row-main",children:[s.jsx("b",{children:"评审"})," ",De(U.id)," | ",G," | ",s.jsx("span",{className:"st-"+(U.status||""),children:U.status}),U.created_at?" | "+Ga(U.created_at):"",s.jsx("br",{}),U.findings?String(U.findings).slice(0,1e3):s.jsx("span",{className:"muted",children:"(暂无 findings:评审尚未执行或尚未写回)"})]}),s.jsx("button",{onClick:()=>i.submitFindings(U.id),children:"写 findings"})]},U.id)})})]})}function yg(){const i=Mt();return i.currentTask?i.currentTask.coordinator_parts?i.coordChildren.length===0?s.jsx("div",{className:"muted",children:"(子任务尚未创建)"}):s.jsx(cu,{children:i.coordChildren.map(r=>s.jsx("li",{children:s.jsxs("span",{className:"row-main",children:["分工 ",s.jsx("b",{children:r.coordinator_part||""})," | 状态 ",s.jsx("span",{className:"st-"+r.status,children:r.status})," | ",De(r.id)," | ",String(r.prompt||"").slice(0,60)]})},r.id))}):s.jsx("div",{className:"muted",children:"(非协调员任务)"}):s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示协调员的子任务"})}function gg(){const i=Mt();if(!i.currentTask)return s.jsx("div",{className:"muted",children:"点任务行查看详情后,这里显示子代理链路"});if(i.agents.length===0)return s.jsxs("div",{className:"muted",children:["(暂无子代理)",i.agentsNote?s.jsx("span",{className:"err",children:i.agentsNote}):null]});const r={main:"主任务",delegate:"委派子任务",model:"模型子代理"},m={running:"进行中",completed:"已完成",failed:"失败",interrupted:"已中断",unknown:"未知"};return s.jsx(cu,{children:i.agents.map((o,_)=>s.jsx("li",{children:s.jsxs("span",{className:"row-main",children:[s.jsxs("b",{children:[r[o.kind||""]||o.kind||"",":"]}),o.name||""," ",s.jsx("span",{className:"st-"+(o.status||""),children:m[o.status||""]||o.status||"?"})," | 过程调用 "+(o.calls?o.calls.length:0)+" 条",o.updated_ts?" | 最近活动 "+Ga(o.updated_ts/1e3):"",o.prompt?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsxs("span",{className:"muted",children:["任务:",o.prompt]})]}):null,o.calls&&o.calls.length?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),o.calls.slice(-50).map((C,N)=>s.jsx("div",{children:dr(C)},N))]}):s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsx("span",{className:"muted",children:"(暂无过程调用)"})]})]})},_))})}function Sg(){const i=Mt();return s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.refreshApprovals,children:"刷新审批队列"}),s.jsx("span",{className:"muted",children:i.approvalMsg})]}),s.jsx("div",{className:"muted",children:"待审批项需人工点记录允许或记录拒绝;超时默认拒绝。当前版本只留回执,不拦截实时行为(实时请求的事前拦截待 host 接入后生效,在此之前实时行为不变)。"}),s.jsx(Ml,{empty:"(暂无审批项)",items:i.approvals.map(r=>s.jsxs("span",{className:"row-main",children:["[",r.kind,"|",r.status,"] ",r.summary,["approved","denied","expired"].includes(r.status||"")?"|回执:"+(r.decision||r.status)+" by "+String(r.decided_by||"").slice(0,8)+" "+Ga(r.decided_at):"",r.status==="pending"?s.jsxs(s.Fragment,{children:[" ",s.jsx("button",{onClick:()=>i.decideApproval(r.id,"approved"),children:"记录允许"})," ",s.jsx("button",{onClick:()=>i.decideApproval(r.id,"denied"),children:"记录拒绝"})]}):null]},r.id))})]})}function pg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("input",{placeholder:"目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)",style:{width:"100%"},value:r,onChange:C=>m(C.target.value)}),s.jsx("textarea",{placeholder:"消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)",value:o,onChange:C=>_(C.target.value)}),s.jsxs(Ut,{children:[s.jsx("button",{onClick:async()=>{await i.postPeer("queued",r,o),_("")},children:"排队发给对方"}),s.jsx("button",{className:"primary",onClick:async()=>{await i.postPeer("direct",r,o),_("")},children:"直接发送"}),s.jsx("span",{className:"muted",children:i.peerMsg})]}),s.jsx(Ml,{empty:"(本任务尚未发出任务间消息)",items:i.peerMessages.map((C,N)=>s.jsxs("span",{className:"row-main",children:["[发给 ",String(C.task_id).slice(0,8),"|",C.mode,"|",C.status,"] ",String(C.body||"").slice(0,120)]},N))})]})}function bg(){const i=Mt(),[r,m]=v.useState(""),o=i.currentTask?["completed","failed","interrupted"].includes(i.currentTask.status):!1;return s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"muted",children:i.threadText||"点任务行查看详情后,这里显示线程元数据"}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"新线程名",value:r,onChange:_=>m(_.target.value)}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("rename",r),children:"重命名"}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("archive",""),children:"归档"}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("unarchive",""),children:"取消归档"}),s.jsx("button",{disabled:!o,onClick:()=>i.threadAction("compact",""),children:"压缩"}),s.jsx("span",{className:"muted",children:i.threadGateNote}),s.jsx("span",{className:"muted",children:i.threadMsg})]}),s.jsx(Ml,{empty:"暂无其他线程",items:i.threadList.map((_,C)=>s.jsxs("span",{className:"row-main",children:[_.name||_.thread_name||_.id||""," [",_.id||"","]",_.archived?" [已归档]":"",_.cwd?" "+_.cwd:""]},C))}),s.jsx("div",{className:"muted",children:"限制:Docker/异机任务线程操作一律 409;merged/merge-failed 不可改;turn/steer 与 review/start 不在本批。"})]})}function xg(){const i=Mt(),r=i.currentTask;if(!r)return s.jsx(Qe,{id:"nav-detail",title:"任务详情",children:s.jsx("div",{className:"muted",children:"点任务行查看详情"})});const[m,o]=Xh(r),[_,C]=Vh(r),N=Qh(r);return s.jsxs(Qe,{id:"nav-detail",title:"任务详情",children:[s.jsxs("div",{children:["状态 ",s.jsx("b",{className:"st-"+r.status,children:r.status}),"(",Vy[r.status]||"未知状态",")",s.jsx("br",{}),s.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[s.jsx("span",{className:"issue-first",title:"任务首字:"+N,"aria-hidden":"true",children:N}),s.jsxs("span",{title:o,children:["耗时 ",m]}),s.jsx("span",{children:" · "}),s.jsx("span",{title:C,children:_})]}),s.jsx("br",{}),i.costSummary===void 0?s.jsx("span",{className:"muted",children:"成本加载中…"}):i.costSummary===null?s.jsx("span",{className:"muted",children:"成本明细加载失败(“查成本”按钮仍可手动拉取原始 JSON)"}):s.jsxs("span",{title:"成本明细:GET /tasks/{id}/cost 聚合;美元只计有价行,无价 token 单列;缓存是输入 token 的子集,不另计",children:["成本 ",ig(i.costSummary.usd_micros)," | token ",(i.costSummary.total_tokens??0).toLocaleString(),"(实际 ",(i.costSummary.actual_tokens??0).toLocaleString()," / 估算 ",(i.costSummary.estimated_tokens??0).toLocaleString(),",缓存 ",(i.costSummary.cached_input_tokens??0).toLocaleString(),",无价 ",(i.costSummary.unpriced_actual_tokens??0).toLocaleString(),")| 轮数 ",i.costSummary.turns??0," | fallback ",i.costSummary.fallback_count??0]}),s.jsx("br",{}),"任务 ",r.id," | turn ",De(r.turn_id)," | root turn ",De(r.root_turn_id),s.jsx("br",{}),"executor ",r.executor||""," | 主机 ",r.worktree_host||"",s.jsx("br",{}),"模型 ",r.model||"默认"," | 强度 ",r.effort||"默认",r.child_model||r.child_effort?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"子任务默认 ",(r.child_model||"跟随本任务")+" / "+(r.child_effort||"跟随本任务")]}):null,s.jsx("br",{}),"权限 ",r.approval||"默认"," | 项目 ",De(r.project_id),s.jsx("br",{}),"更新 ",Ga(r.updated_at),r.plan?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"计划模式(只读)"]}):null,r.forked_from?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"分支自 ",De(r.forked_from)]}):null,r.goal_mode?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),r.no_time_limit?"goal 模式无敌版(不限时)":"goal 模式(不限轮次,模型宣告完成)"]}):r.verify_command?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"goal 模式(旧语义,验收命令)"]}):null,r.coordinator_parts?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"协调员:",r.coordinator_parts.length," 个子任务(",r.coordinator_parts.map(x=>x.name).join("、"),")"]}):null,r.parent_task_id?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"协调子任务,父任务 ",De(r.parent_task_id),r.coordinator_part?"("+r.coordinator_part+")":""]}):null,r.attachments&&r.attachments.length?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),"附件:",r.attachments.join("、")]}):null,r.pr_url?s.jsxs(s.Fragment,{children:[s.jsx("br",{}),s.jsxs("a",{href:r.pr_url,target:"_blank",rel:"noopener noreferrer",children:["PR #",r.pr_number]})]}):null,s.jsx("br",{}),"prompt:",r.prompt||""]}),s.jsx(hg,{}),s.jsx("pre",{children:i.detailBody||"(暂无 result/error 输出)"}),i.costBox?s.jsx("pre",{children:i.costBox}):null,s.jsx("h3",{children:"协调子任务"}),s.jsx(yg,{}),s.jsx("h3",{children:"子代理链路"}),s.jsx(gg,{}),s.jsx("h3",{children:"评审队列"}),s.jsx(vg,{}),s.jsx("h3",{children:"运行时审批队列"}),s.jsx(Sg,{}),s.jsx("h3",{children:"给其他任务发消息"}),s.jsx(pg,{}),s.jsx("h3",{children:"线程"}),s.jsx(bg,{})]})}function jg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState([]),[x,w]=v.useState(null),[U,G]=v.useState(!1),[b,B]=v.useState(""),[tt,at]=v.useState(""),et=v.useCallback(async()=>{if(!i.keySaved){N([]);return}try{const nt=await P($.userKeys);N(nt.keys||[]),at("")}catch(nt){at(nt instanceof Error?nt.message:"加载 key 列表失败")}},[i.keySaved]);v.useEffect(()=>{et()},[et]);const L=async()=>{B(""),at(""),G(!1);try{const nt=await P($.userKeys,"POST",{label:o.trim()||"api-key"});w(nt),_(""),B("新 key 已生成,只显示一次:复制后请妥善保存。"),await et()}catch(nt){at(nt instanceof Error?nt.message:"生成 key 失败")}},dt=async()=>{if(x)try{await navigator.clipboard.writeText(x.api_key),G(!0)}catch{at("复制失败:请手动选中上方 key 文本复制")}},zt=()=>{x&&(i.saveKeyInput(x.api_key),w(null),B("已存为当前浏览器 key(原有 key 未被撤销,需要时可单独撤销)。"))},Jt=async nt=>{const Xt=(()=>{try{return bl().slice(-4)}catch{return""}})(),te=nt.id==="legacy"?"(主 key:撤销后当前浏览器保存的 key 也可能随之失效,需重新登录拿新 key)":nt.hint&&nt.hint===Xt?"(这就是本浏览器当前在用的 key,撤销后本页会立刻未连接)":"";if(window.confirm(`撤销 key「${nt.label}」(后 4 位 ${nt.hint||"无"})吗?${te}撤销不可恢复。`)){B(""),at("");try{await P($.userKey(nt.id),"DELETE"),B(`已撤销 key「${nt.label}」。`),await et()}catch(ct){at(ct instanceof Error?ct.message:"撤销失败")}}};return s.jsxs(Qe,{id:"nav-key",title:"API Key",children:[s.jsxs(Ut,{children:[s.jsx("input",{type:"password",placeholder:"粘贴你的 X-API-Key(与调 API 用的同一个)",autoComplete:"off",value:r,onChange:nt=>m(nt.target.value)}),s.jsx("button",{className:"primary",onClick:()=>{i.saveKeyInput(r),m("")},children:"保存到本浏览器"}),s.jsx("button",{onClick:i.clearKeyInput,children:"清除"}),s.jsx("span",{className:"muted",children:i.keyState})]}),s.jsx("div",{children:s.jsx("span",{className:"muted",children:i.quotaText})}),!i.keySaved&&s.jsx("div",{children:s.jsx("span",{className:"muted",children:"先粘贴并保存已有 key,再生成或管理 key(生成接口本身也要用已有 key 鉴权)。"})}),i.keySaved&&s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("input",{placeholder:"新 key 备注(可选,默认 api-key,如 harness2-temp)",autoComplete:"off",value:o,onChange:nt=>_(nt.target.value)}),s.jsx("button",{className:"primary",onClick:()=>void L(),children:"生成新 key"}),s.jsx("button",{onClick:()=>void et(),children:"刷新列表"})]}),x&&s.jsxs("div",{children:[s.jsx("div",{children:s.jsxs("span",{className:"muted",children:["新 key(",x.label,",后 4 位 ",x.hint,"):只显示一次,关闭后无法再查看。"]})}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",readOnly:!0,value:x.api_key,onFocus:nt=>nt.target.select()}),s.jsx("button",{className:"primary",onClick:()=>void dt(),children:U?"已复制":"复制"}),s.jsx("button",{onClick:zt,children:"存为当前浏览器 key"}),s.jsx("button",{onClick:()=>w(null),children:"关闭(不再显示)"})]})]}),b&&s.jsx("div",{children:s.jsx("span",{className:"muted",children:b})}),tt&&s.jsx("div",{children:s.jsx("span",{children:tt})}),s.jsxs("div",{children:[C.length===0&&s.jsx("span",{className:"muted",children:"暂无 key(或列表加载失败,见上方报错)。"}),C.map(nt=>s.jsxs("div",{children:[s.jsx("span",{children:nt.label})," ",s.jsxs("span",{className:"muted",children:["后 4 位 ",nt.hint||"无"," · 创建 ",Ga(nt.created_at)," · 最近使用 ",nt.last_used_at?Ga(nt.last_used_at):"未使用过"]})," ",nt.revoked_at?s.jsxs("span",{className:"muted",children:["已撤销(",Ga(nt.revoked_at),")"]}):s.jsx("button",{onClick:()=>void Jt(nt),children:"撤销"})]},nt.id))]})]})]})}function Tg(){const i=Mt();return s.jsxs(Qe,{id:"adminCard",title:s.jsxs(s.Fragment,{children:["管理区 ",s.jsx("span",{className:"muted",children:"(仅全局管理员)"})]}),children:[s.jsx("div",{className:"muted",children:i.adminGate}),i.adminBody?s.jsxs(s.Fragment,{children:[s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"要查配额的用户 id",value:i.adminUserId,onChange:r=>i.setAdminUserId(r.target.value)}),s.jsx("button",{onClick:i.adminQuota,children:"查该用户配额"})]}),s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.adminSweep,children:"手动触发 sweep(清理陈旧 running 任务)"}),s.jsx("button",{onClick:i.adminBackup,children:"手动触发备份"})]}),s.jsx("div",{className:"muted",children:i.adminResult})]}):null]})}function _g(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return s.jsxs(Qe,{id:"nav-projects",title:"项目",children:[s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"项目",value:i.projectId,onChange:x=>i.selectProject(x.target.value),children:[i.projects.length===0?s.jsx("option",{value:"",children:"(先加载项目)"}):null,i.projects.map(x=>s.jsxs("option",{value:x.id,children:[x.name," (",De(x.id),")"]},x.id))]}),s.jsx("button",{onClick:i.refreshProjects,children:"刷新"})]}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"新项目名",value:r,onChange:x=>m(x.target.value)}),s.jsxs("select",{"aria-label":"从 GitHub 仓库选",value:o,onChange:x=>{_(x.target.value),x.target.value&&N(x.target.value)},children:[s.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选,或手动输入)"}),i.githubRepos.map(x=>s.jsx("option",{value:x.clone_url,children:x.repo_full_name},x.clone_url))]}),s.jsx("input",{type:"text",placeholder:"repo_url(可选)",value:C,onChange:x=>N(x.target.value)}),s.jsx("button",{onClick:async()=>{await i.createProject(r,C),m(""),N(""),_("")},children:"新建项目"})]}),s.jsx("span",{className:"muted",children:i.projectMsg})]})}function Eg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState("contributor"),C=i.projects.find(N=>N.id===i.projectId);return s.jsxs(Qe,{title:"项目成员",children:[C?s.jsxs("div",{className:"muted",children:[C.name," | ",C.id," | 仓库 ",C.repo_url||"未绑定"," | 我的角色 ",C.my_role||"未知"]}):s.jsx("div",{className:"muted",children:"先选项目"}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"成员 user_id 或用户名",value:r,onChange:N=>m(N.target.value)}),s.jsxs("select",{"aria-label":"邀请角色",value:o,onChange:N=>_(N.target.value),children:[s.jsx("option",{value:"viewer",children:"viewer(只读)"}),s.jsx("option",{value:"contributor",children:"contributor(可建任务)"}),s.jsx("option",{value:"maintainer",children:"maintainer(可批合并)"}),s.jsx("option",{value:"owner",children:"owner(可管项目)"})]}),s.jsx("button",{onClick:async()=>{await i.inviteMember(r,o),m("")},children:"邀请成员"}),s.jsx("button",{onClick:i.refreshMembers,children:"刷新成员"})]}),i.memberError?s.jsx("div",{className:"muted",children:i.memberError}):i.members.length===0?s.jsx("div",{className:"muted",children:"先选项目"}):s.jsx(cu,{children:i.members.map(N=>{const x=(N.username||"")+(N.username?"("+String(N.user_id).slice(0,8)+")":String(N.user_id).slice(0,8));return s.jsxs("li",{children:[s.jsx("span",{className:"row-main",children:x}),s.jsx("select",{"aria-label":"成员角色",value:N.role||"viewer",onChange:w=>void i.changeMemberRole(N.user_id,w.target.value),children:Ly.map(w=>s.jsx("option",{value:w,children:w},w))})]},N.user_id)})}),s.jsx("span",{className:"muted",children:i.memberMsg})]})}function Ng(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState("");return s.jsxs(Qe,{id:"nav-env",title:s.jsxs(s.Fragment,{children:["环境 ",s.jsx("span",{className:"muted",children:"(选、建、管:当前项目的基准检出)"})]}),children:[s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.refreshEnvs,children:"刷新"}),s.jsx("span",{className:"muted",children:i.envCount})]}),i.envs.length===0?s.jsx("div",{className:"muted",children:"先选项目"}):s.jsx(cu,{children:i.envs.map(x=>s.jsxs("li",{children:[s.jsxs("span",{className:"row-main",children:[x.name,"(",De(x.id),") / 分支 ",x.branch||"默认分支"," / 执行器 ",x.executor||"不限"," / 状态 ",x.status,x.status==="failed"&&x.error_text?" / 失败原因:"+x.error_text:""]}),x.status==="archived"?null:s.jsx("button",{onClick:()=>void i.archiveEnv(x.id),children:"归档"})]},x.id))}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"新环境名",value:r,onChange:x=>m(x.target.value)}),s.jsx("input",{type:"text",placeholder:"分支(可选,空=默认分支)",value:o,onChange:x=>_(x.target.value)}),s.jsxs("select",{"aria-label":"新环境执行器",value:C,onChange:x=>N(x.target.value),children:[s.jsx("option",{value:"",children:"执行器:不限"}),s.jsx("option",{value:"local",children:"local"}),s.jsx("option",{value:"docker",children:"docker"})]}),s.jsx("button",{onClick:async()=>{await i.createEnv(r,o,C),m(""),_("")},children:"新建环境"})]}),s.jsx("span",{className:"muted",children:i.envMsg})]})}function Cg(){const i=Mt(),[r,m]=v.useState("");return s.jsxs(Qe,{title:"仓库与环境上下文",children:[s.jsx("div",{className:"muted",children:i.envRepoLine||"先选项目"}),s.jsx("div",{className:"muted",children:i.envCount}),i.envRepoBar?s.jsxs(Ut,{children:[s.jsxs("select",{"aria-label":"补仓库",value:r,onChange:o=>m(o.target.value),children:[s.jsx("option",{value:"",children:"(从 GitHub App 安装仓库里选)"}),i.githubRepos.map(o=>s.jsx("option",{value:o.clone_url,children:o.repo_full_name},o.clone_url))]}),s.jsx("button",{onClick:()=>void i.saveEnvRepo(r),children:"保存仓库"})]}):null,s.jsx("span",{className:"muted",children:i.envRepoMsg})]})}function Ag(){const i=Mt();return s.jsxs(Qe,{id:"nav-workers",title:"Workers",children:[s.jsx(Ut,{children:s.jsx("button",{onClick:i.refreshWorkers,children:"刷新"})}),i.workersError?s.jsx("div",{className:"muted",children:i.workersError}):i.workers===null?s.jsx("div",{className:"muted",children:i.workersSummary||"未加载"}):i.workers.length===0?s.jsx("div",{className:"muted",children:"无 worker 注册"}):s.jsx(cu,{children:i.workers.map((r,m)=>{const o=r.running===void 0||r.running===null?"?":r.running,_=r.capacity===void 0||r.capacity===null?"?":r.capacity,C=kh(r),N=r.alive!==void 0&&r.alive!==null?!!r.alive:C.age!==null&&C.age<=120,x=N?" / 在线":" / 离线(占用为上次上报值)";return s.jsx("li",{className:N?"is-online":"is-offline",children:s.jsxs("span",{className:"row-main",children:[r.worker_id||r.id||"?"," / ",r.executor||""," / 占用 ",o,"/",_,x," / 最后心跳 ",C.text]})},m)})})]})}function Og(){const i=Mt();return s.jsxs(Qe,{title:"健康与配额",children:[s.jsxs(Ut,{children:[s.jsx("span",{className:"muted",children:i.healthText}),s.jsx("button",{onClick:i.refreshHealth,children:"刷新"})]}),s.jsx("div",{children:s.jsx("span",{className:"muted",children:i.quotaText})}),s.jsx("div",{className:"muted",children:i.workersSummary})]})}function Mg(){const i=Mt();return s.jsxs(Qe,{id:"nav-skills",title:"技能与 MCP",children:[s.jsx("div",{className:"muted",children:"反映宿主租户 home,容器内 home 可能不同;重载只在 schema 枚举里,当前 pin 的二进制拒绝时原样 502;OAuth 只发起登录,不代表登录完成。"}),s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.refreshSkills,children:"刷新"}),s.jsx("span",{className:"muted",children:i.skillMsg})]}),s.jsx("h3",{children:"技能"}),i.skillError?s.jsx("div",{className:"muted",children:i.skillError}):s.jsx(Ml,{empty:"暂无技能",items:i.skills.map((r,m)=>s.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:"",r.detail?" - "+r.detail:""]},m))}),s.jsx("h3",{children:"应用"}),s.jsx(Ml,{empty:"暂无应用",items:i.apps.map((r,m)=>s.jsxs("span",{className:"row-main",children:[r.name||r.id||"",r.description?" - "+r.description:""]},m))}),s.jsx("h3",{children:"MCP 服务"}),s.jsx(Ml,{empty:"暂无 MCP 服务",items:i.mcpServers.map((r,m)=>{const o=r.detail||r.details||r.state||"";return s.jsxs("span",{className:"row-main",children:[r.name||r.id||""," | 状态 ",r.status||"",o?" | "+o:""]},m)})})]})}function zg(){const i=Mt(),[r,m]=v.useState("");return s.jsxs(Qe,{title:"MCP 操作",children:[s.jsxs(Ut,{children:[s.jsx("button",{onClick:i.reloadMcp,children:"重载配置"}),s.jsx("span",{className:"muted",children:i.mcpMsg})]}),s.jsxs(Ut,{children:[s.jsx("input",{type:"text",placeholder:"MCP 服务名",value:r,onChange:o=>m(o.target.value)}),s.jsx("button",{onClick:()=>void i.mcpOauth(r),children:"发起 OAuth 登录"}),s.jsx("span",{className:"muted",children:i.mcpOauthMsg})]}),i.mcpOauthBox?s.jsx("pre",{children:i.mcpOauthBox}):null]})}function Rg(){const i=Mt(),[r,m]=v.useState(""),[o,_]=v.useState(""),[C,N]=v.useState(""),[x,w]=v.useState("");return s.jsxs(s.Fragment,{children:[s.jsx("input",{placeholder:"自动化名称(同项目内启用中的名称唯一)",style:{width:"100%"},value:r,onChange:U=>m(U.target.value)}),s.jsx("textarea",{placeholder:"定时任务内容(创建只登记定义与到期状态;执行由后续执行器经 claim 抢单后建任务,不另起调度器)",value:o,onChange:U=>_(U.target.value)}),s.jsxs(Ut,{children:[s.jsx("input",{placeholder:"间隔秒数(默认 86400,最小 60)",style:{width:"40%"},value:C,onChange:U=>N(U.target.value)}),s.jsx("input",{placeholder:"仓库(可选)",style:{width:"40%"},value:x,onChange:U=>w(U.target.value)}),s.jsx("button",{className:"primary",onClick:async()=>{await i.createAutomation(r,o,C,x),m(""),_(""),N(""),w("")},children:"创建自动化"}),s.jsx("button",{onClick:i.refreshAutomations,children:"刷新自动化"}),s.jsx("span",{className:"muted",children:i.autoMsg})]}),s.jsx(Ml,{empty:"(暂无自动化)",items:i.automations.map(U=>s.jsxs("span",{className:"row-main",children:["[",U.status,U.due?"|到期":"","] ",U.name,"|每 ",U.interval_seconds," 秒|下次 ",Ga(U.next_run_at),U.status==="active"?s.jsxs(s.Fragment,{children:[" ",s.jsx("button",{onClick:()=>i.cancelAutomation(U.id),children:"取消"})]}):null]},U.id))})]})}function Dg(){var m,o,_,C;const i=Mt(),r=i.triage;return i.triageError?s.jsx("div",{className:"muted",children:i.triageError}):r?s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["到期自动化(",((m=r.counts)==null?void 0:m.automations_due)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.automations_due||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:[N.name,"|每 ",N.interval_seconds," 秒"]},x))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["失败/中断任务(",((o=r.counts)==null?void 0:o.failed_tasks)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.failed_tasks||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:[De(N.id),"|",N.status,"|",String(N.prompt||"").slice(0,80)]},x))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["待处理后续消息(",((_=r.counts)==null?void 0:_.pending_followups)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.pending_followups||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:["任务 ",De(N.task_id),"|",String(N.body||"").slice(0,80)]},x))})]}),s.jsxs("div",{className:"data-group",children:[s.jsxs("b",{children:["最近自动化产出(",((C=r.counts)==null?void 0:C.recent_runs)||0,")"]}),s.jsx(Ml,{empty:"(无)",items:(r.recent_runs||[]).map((N,x)=>s.jsxs("span",{className:"row-main",children:[De(N.automation_id),"|",N.status,N.task_id?"|任务 "+De(N.task_id):"",N.task_status?"|"+N.task_status:""]},x))})]})]}):s.jsx("div",{className:"muted",children:"(先选项目)"})}function Ug(){return s.jsx(Qe,{id:"nav-automations",title:"自动化",children:s.jsx(Rg,{})})}function Hg(){const i=Mt();return s.jsxs(Qe,{id:"nav-triage",title:"分诊收件箱",children:[s.jsx(Ut,{children:s.jsx("button",{onClick:i.refreshTriage,children:"刷新分诊"})}),s.jsx(Dg,{})]})}const Bg=[["#sec-dispatch","派发"],["#sec-tasks","任务"],["#sec-conv","对话"],["#sec-projects","项目"],["#sec-env","环境"],["#sec-workers","Workers"],["#sec-skills","技能"],["#sec-automations","自动化"],["#sec-triage","分诊"],["#sec-admin","管理区"],["#sec-key","API Key"]];function qg(){return s.jsxs("header",{className:"dash-topbar",children:[s.jsxs("div",{className:"dash-topbar-row",children:[s.jsx("span",{className:"dash-brand",children:"Codex 命令台"}),s.jsx(Yg,{}),s.jsx("span",{className:"muted dash-hide-sm",children:s.jsx(wg,{})}),s.jsx("span",{className:"muted dash-hide-sm",children:s.jsx(Gg,{})}),s.jsx("span",{className:"muted dash-stamp",children:s.jsx(kg,{})})]}),s.jsx("nav",{className:"dash-nav","aria-label":"页面导航",children:Bg.map(([i,r])=>s.jsx("a",{href:i,children:r},i))})]})}function Yg(){const i=Mt();return s.jsx("span",{className:i.keySaved?"dash-status ok":"dash-status off",children:i.keySaved?"● 已连接":"○ 未连接"})}function wg(){return s.jsx(s.Fragment,{children:Mt().healthText})}function Gg(){return s.jsx(s.Fragment,{children:Mt().quotaText})}function kg(){return s.jsxs(s.Fragment,{children:["自动刷新 · 每 10 秒 · 已刷新 ",Mt().refreshStamp]})}function Qg(){const i=ag();tg(m=>i.refreshAll(m),1e4),eg(()=>i.refreshSlow(),6e4);const r=()=>{var m;(m=document.getElementById("sec-dispatch"))==null||m.scrollIntoView({behavior:"smooth"})};return s.jsxs(Gh.Provider,{value:i,children:[s.jsx(qg,{}),s.jsxs("main",{className:"dash-page",children:[s.jsx(ng,{}),s.jsxs("div",{className:"dash-col dash-col-left",children:[s.jsxs("section",{id:"sec-tasks",className:"dash-section card",children:[s.jsx("h2",{children:"任务列表"}),s.jsx(cg,{onNew:r})]}),s.jsxs("section",{id:"sec-projects",className:"dash-section",children:[s.jsx(_g,{}),s.jsx(Eg,{})]})]}),s.jsxs("div",{className:"dash-col dash-col-mid",children:[s.jsx("section",{id:"sec-dispatch",className:"dash-section",children:s.jsx(ug,{})}),s.jsxs("section",{id:"sec-conv",className:"dash-section",children:[s.jsxs("div",{className:"card",children:[s.jsx("h2",{children:"对话"}),s.jsx(mg,{})]}),s.jsx(xg,{})]})]}),s.jsxs("div",{className:"dash-col dash-col-right",children:[s.jsxs("section",{id:"sec-env",className:"dash-section",children:[s.jsx(Ng,{}),s.jsx(Cg,{})]}),s.jsxs("section",{id:"sec-workers",className:"dash-section",children:[s.jsx(Ag,{}),s.jsx(Og,{})]}),s.jsxs("section",{id:"sec-skills",className:"dash-section",children:[s.jsx(Mg,{}),s.jsx(zg,{})]}),s.jsx("section",{id:"sec-automations",className:"dash-section",children:s.jsx(Ug,{})}),s.jsx("section",{id:"sec-triage",className:"dash-section",children:s.jsx(Hg,{})}),s.jsx("section",{id:"sec-admin",className:"dash-section",children:s.jsx(Tg,{})}),s.jsx("section",{id:"sec-key",className:"dash-section",children:s.jsx(jg,{})})]})]})]})}Qy.createRoot(document.getElementById("root")).render(s.jsx(Uy.StrictMode,{children:s.jsx(Qg,{})})); diff --git a/host.py b/host.py index 320b605..d58a2f4 100644 --- a/host.py +++ b/host.py @@ -241,6 +241,9 @@ def _summarize_trace_item(method, params): 只取过程事实,不取大文本:命令截 500 字、消息截 300 字、 思考摘要截 200 字;fileChange 一项一变化拆多条。 + 消息被截断时条目带 truncated=True(控制台据此标注“链路 + 摘要已截断”,不得把截断后的文本当成模型的完整回复; + 完整回复在任务的 result_text 里,不在链路条目里)。 返回 [] 表示该通知不进链路(userMessage 等)。 ts 取通知的 completedAtMs/startedAtMs(毫秒 epoch), 没有时为 None,服务端展示时按无时间处理。 @@ -278,8 +281,11 @@ def _summarize_trace_item(method, params): text = item.get("text") or "" if not text: return [] - return [{"kind": "message", "id": item_id, "ts": ts, "thread": thread, - "phase": item.get("phase") or "", "text": text[:300]}] + entry = {"kind": "message", "id": item_id, "ts": ts, "thread": thread, + "phase": item.get("phase") or "", "text": text[:300]} + if len(text) > 300: + entry["truncated"] = True + return [entry] if item_type == "reasoning": summary = item.get("summary") or item.get("content") or [] text = " ".join(s for s in summary if isinstance(s, str)).strip() diff --git a/tests/test_host_trace.py b/tests/test_host_trace.py index 300157b..671764c 100644 --- a/tests/test_host_trace.py +++ b/tests/test_host_trace.py @@ -69,6 +69,23 @@ class SummarizeTraceItemTestCase(unittest.TestCase): self.assertEqual(len(entries), 1) self.assertEqual(entries[0]["kind"], kind) + def test_message_truncation_is_flagged(self): + # 2026-10-29 实弹:468 字 final_answer 在链路里只剩前 + # 300 字、断在“fu”后,控制台照原样当助手回复展示, + # 用户误以为模型没写完。截断本身是设计(防链路文件 + # 写爆),但必须带标记,短消息不带标记。 + long_entries = _summarize_trace_item( + "item/completed", + {"item": {"type": "agentMessage", "id": "m-long", + "phase": "final_answer", "text": "x" * 468}}) + self.assertEqual(len(long_entries[0]["text"]), 300) + self.assertTrue(long_entries[0].get("truncated")) + short_entries = _summarize_trace_item( + "item/completed", + {"item": {"type": "agentMessage", "id": "m-short", + "phase": "final_answer", "text": "done"}}) + self.assertNotIn("truncated", short_entries[0]) + def test_skipped_notifications(self): self.assertEqual(_summarize_trace_item( "item/completed", {"item": {"type": "userMessage", "id": "u1",