@coralai/sps-cli 0.50.21 → 0.50.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -513,4 +513,4 @@ ${g.join(`
|
|
|
513
513
|
https://github.com/highlightjs/highlight.js/issues/2277`),$t=ue,ct=Ne),He===void 0&&(He=!0);const dn={code:ct,language:$t};Or("before:highlight",dn);const Gn=dn.result?dn.result:ea(dn.language,dn.code,He);return Gn.code=dn.code,Or("after:highlight",Gn),Gn}function ea(ue,Ne,He,ct){const $t=Object.create(null);function dn(he,Se){return he.keywords[Se]}function Gn(){if(!je.keywords){Gt.addText(ut);return}let he=0;je.keywordPatternRe.lastIndex=0;let Se=je.keywordPatternRe.exec(ut),Be="";for(;Se;){Be+=ut.substring(he,Se.index);const Ve=rn.case_insensitive?Se[0].toLowerCase():Se[0],Rt=dn(je,Ve);if(Rt){const[oi,Wl]=Rt;if(Gt.addText(Be),Be="",$t[Ve]=($t[Ve]||0)+1,$t[Ve]<=xs&&(Da+=Wl),oi.startsWith("_"))Be+=Se[0];else{const jc=rn.classNameAliases[oi]||oi;Qn(Se[0],jc)}}else Be+=Se[0];he=je.keywordPatternRe.lastIndex,Se=je.keywordPatternRe.exec(ut)}Be+=ut.substring(he),Gt.addText(Be)}function An(){if(ut==="")return;let he=null;if(typeof je.subLanguage=="string"){if(!ie[je.subLanguage]){Gt.addText(ut);return}he=ea(je.subLanguage,ut,!0,Mc[je.subLanguage]),Mc[je.subLanguage]=he._top}else he=Es(ut,je.subLanguage.length?je.subLanguage:null);je.relevance>0&&(Da+=he.relevance),Gt.__addSublanguage(he._emitter,he.language)}function Et(){je.subLanguage!=null?An():Gn(),ut=""}function Qn(he,Se){he!==""&&(Gt.startScope(Se),Gt.addText(he),Gt.endScope())}function Oc(he,Se){let Be=1;const Ve=Se.length-1;for(;Be<=Ve;){if(!he._emit[Be]){Be++;continue}const Rt=rn.classNameAliases[he[Be]]||he[Be],oi=Se[Be];Rt?Qn(oi,Rt):(ut=oi,Gn(),ut=""),Be++}}function ws(he,Se){return he.scope&&typeof he.scope=="string"&&Gt.openNode(rn.classNameAliases[he.scope]||he.scope),he.beginScope&&(he.beginScope._wrap?(Qn(ut,rn.classNameAliases[he.beginScope._wrap]||he.beginScope._wrap),ut=""):he.beginScope._multi&&(Oc(he.beginScope,Se),ut="")),je=Object.create(he,{parent:{value:je}}),je}function Vl(he,Se,Be){let Ve=T(he.endRe,Be);if(Ve){if(he["on:end"]){const Rt=new t(he);he["on:end"](Se,Rt),Rt.isMatchIgnored&&(Ve=!1)}if(Ve){for(;he.endsParent&&he.parent;)he=he.parent;return he}}if(he.endsWithParent)return Vl(he.parent,Se,Be)}function _s(he){return je.matcher.regexIndex===0?(ut+=he[0],1):(La=!0,0)}function ed(he){const Se=he[0],Be=he.rule,Ve=new t(Be),Rt=[Be.__beforeBegin,Be["on:begin"]];for(const oi of Rt)if(oi&&(oi(he,Ve),Ve.isMatchIgnored))return _s(Se);return Be.skip?ut+=Se:(Be.excludeBegin&&(ut+=Se),Et(),!Be.returnBegin&&!Be.excludeBegin&&(ut=Se)),ws(Be,he),Be.returnBegin?0:Se.length}function On(he){const Se=he[0],Be=Ne.substring(he.index),Ve=Vl(je,he,Be);if(!Ve)return Tr;const Rt=je;je.endScope&&je.endScope._wrap?(Et(),Qn(Se,je.endScope._wrap)):je.endScope&&je.endScope._multi?(Et(),Oc(je.endScope,he)):Rt.skip?ut+=Se:(Rt.returnEnd||Rt.excludeEnd||(ut+=Se),Et(),Rt.excludeEnd&&(ut=Se));do je.scope&&Gt.closeNode(),!je.skip&&!je.subLanguage&&(Da+=je.relevance),je=je.parent;while(je!==Ve.parent);return Ve.starts&&ws(Ve.starts,he),Rt.returnEnd?0:Se.length}function Xl(){const he=[];for(let Se=je;Se!==rn;Se=Se.parent)Se.scope&&he.unshift(Se.scope);he.forEach(Se=>Gt.openNode(Se))}let Rr={};function ks(he,Se){const Be=Se&&Se[0];if(ut+=he,Be==null)return Et(),0;if(Rr.type==="begin"&&Se.type==="end"&&Rr.index===Se.index&&Be===""){if(ut+=Ne.slice(Se.index,Se.index+1),!wt){const Ve=new Error(`0 width match regex (${ue})`);throw Ve.languageName=ue,Ve.badRule=Rr.rule,Ve}return 1}if(Rr=Se,Se.type==="begin")return ed(Se);if(Se.type==="illegal"&&!He){const Ve=new Error('Illegal lexeme "'+Be+'" for mode "'+(je.scope||"<unnamed>")+'"');throw Ve.mode=je,Ve}else if(Se.type==="end"){const Ve=On(Se);if(Ve!==Tr)return Ve}if(Se.type==="illegal"&&Be==="")return ut+=`
|
|
514
514
|
`,1;if(Zl>1e5&&Zl>Se.index*3)throw new Error("potential infinite loop, way more iterations than matches");return ut+=Be,Be.length}const rn=En(ue);if(!rn)throw Ot(bt.replace("{}",ue)),new Error('Unknown language: "'+ue+'"');const Rc=an(rn);let Ns="",je=ct||Rc;const Mc={},Gt=new ye.__emitter(ye);Xl();let ut="",Da=0,ia=0,Zl=0,La=!1;try{if(rn.__emitTokens)rn.__emitTokens(Ne,Gt);else{for(je.matcher.considerAll();;){Zl++,La?La=!1:je.matcher.considerAll(),je.matcher.lastIndex=ia;const he=je.matcher.exec(Ne);if(!he)break;const Se=Ne.substring(ia,he.index),Be=ks(Se,he);ia=he.index+Be}ks(Ne.substring(ia))}return Gt.finalize(),Ns=Gt.toHTML(),{language:ue,value:Ns,relevance:Da,illegal:!1,_emitter:Gt,_top:je}}catch(he){if(he.message&&he.message.includes("Illegal"))return{language:ue,value:vn(Ne),illegal:!0,relevance:0,_illegalBy:{message:he.message,index:ia,context:Ne.slice(ia-100,ia+100),mode:he.mode,resultSoFar:Ns},_emitter:Gt};if(wt)return{language:ue,value:vn(Ne),illegal:!1,relevance:0,errorRaised:he,_emitter:Gt,_top:je};throw he}}function vs(ue){const Ne={value:vn(ue),illegal:!1,relevance:0,_top:Ee,_emitter:new ye.__emitter(ye)};return Ne._emitter.addText(ue),Ne}function Es(ue,Ne){Ne=Ne||ye.languages||Object.keys(ie);const He=vs(ue),ct=Ne.filter(En).filter(Ma).map(Et=>ea(Et,ue,!1));ct.unshift(He);const $t=ct.sort((Et,Qn)=>{if(Et.relevance!==Qn.relevance)return Qn.relevance-Et.relevance;if(Et.language&&Qn.language){if(En(Et.language).supersetOf===Qn.language)return 1;if(En(Qn.language).supersetOf===Et.language)return-1}return 0}),[dn,Gn]=$t,An=dn;return An.secondBest=Gn,An}function Bi(ue,Ne,He){const ct=Ne&&ge[Ne]||He;ue.classList.add("hljs"),ue.classList.add(`language-${ct}`)}function Ft(ue){let Ne=null;const He=Ut(ue);if(De(He))return;if(Or("before:highlightElement",{el:ue,language:He}),ue.dataset.highlighted){console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",ue);return}if(ue.children.length>0&&(ye.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."),console.warn("https://github.com/highlightjs/highlight.js/wiki/security"),console.warn("The element with unescaped HTML:"),console.warn(ue)),ye.throwUnescapedHTML))throw new zi("One of your code blocks includes unescaped HTML.",ue.innerHTML);Ne=ue;const ct=Ne.textContent,$t=He?Nt(ct,{language:He,ignoreIllegals:!0}):Es(ct);ue.innerHTML=$t.value,ue.dataset.highlighted="yes",Bi(ue,He,$t.language),ue.result={language:$t.language,re:$t.relevance,relevance:$t.relevance},$t.secondBest&&(ue.secondBest={language:$t.secondBest.language,relevance:$t.secondBest.relevance}),Or("after:highlightElement",{el:ue,result:$t,text:ct})}function fn(ue){ye=Nc(ye,ue)}const Ra=()=>{Ss(),te("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")};function Ql(){Ss(),te("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.")}let Tc=!1;function Ss(){function ue(){Ss()}if(document.readyState==="loading"){Tc||window.addEventListener("DOMContentLoaded",ue,!1),Tc=!0;return}document.querySelectorAll(ye.cssSelector).forEach(Ft)}function Cc(ue,Ne){let He=null;try{He=Ne(B)}catch(ct){if(Ot("Language definition for '{}' could not be registered.".replace("{}",ue)),wt)Ot(ct);else throw ct;He=Ee}He.name||(He.name=ue),ie[ue]=He,He.rawDefinition=Ne.bind(null,B),He.aliases&&ta(He.aliases,{languageName:ue})}function Ar(ue){delete ie[ue];for(const Ne of Object.keys(ge))ge[Ne]===ue&&delete ge[Ne]}function Yl(){return Object.keys(ie)}function En(ue){return ue=(ue||"").toLowerCase(),ie[ue]||ie[ge[ue]]}function ta(ue,{languageName:Ne}){typeof ue=="string"&&(ue=[ue]),ue.forEach(He=>{ge[He.toLowerCase()]=Ne})}function Ma(ue){const Ne=En(ue);return Ne&&!Ne.disableAutodetect}function ja(ue){ue["before:highlightBlock"]&&!ue["before:highlightElement"]&&(ue["before:highlightElement"]=Ne=>{ue["before:highlightBlock"](Object.assign({block:Ne.el},Ne))}),ue["after:highlightBlock"]&&!ue["after:highlightElement"]&&(ue["after:highlightElement"]=Ne=>{ue["after:highlightBlock"](Object.assign({block:Ne.el},Ne))})}function Kt(ue){ja(ue),Le.push(ue)}function Ac(ue){const Ne=Le.indexOf(ue);Ne!==-1&&Le.splice(Ne,1)}function Or(ue,Ne){const He=ue;Le.forEach(function(ct){ct[He]&&ct[He](Ne)})}function na(ue){return te("10.7.0","highlightBlock will be removed entirely in v12.0"),te("10.7.0","Please use highlightElement now."),Ft(ue)}Object.assign(B,{highlight:Nt,highlightAuto:Es,highlightAll:Ss,highlightElement:Ft,highlightBlock:na,configure:fn,initHighlighting:Ra,initHighlightingOnLoad:Ql,registerLanguage:Cc,unregisterLanguage:Ar,listLanguages:Yl,getLanguage:En,registerAliases:ta,autoDetection:Ma,inherit:Nc,addPlugin:Kt,removePlugin:Ac}),B.debugMode=function(){wt=!1},B.safeMode=function(){wt=!0},B.versionString=ot,B.regex={concat:w,lookahead:x,either:_,optional:S,anyNumberOfTimes:v};for(const ue in Dt)typeof Dt[ue]=="object"&&e(Dt[ue]);return Object.assign(B,Dt),B},Cn=Cr({});return Cn.newInstance=()=>Cr({}),Fm=Cn,Cn.HighlightJS=Cn,Cn.default=Cn,Fm}var H4=q4();const K4=Np(H4),tE={},G4="hljs-";function Q4(e){const t=K4.newInstance();return e&&o(e),{highlight:n,highlightAuto:a,listLanguages:s,register:o,registerAlias:c,registered:f};function n(d,h,y){const g=y||tE,x=typeof g.prefix=="string"?g.prefix:G4;if(!t.getLanguage(d))throw new Error("Unknown language: `"+d+"` is not registered");t.configure({__emitter:Y4,classPrefix:x});const v=t.highlight(h,{ignoreIllegals:!0,language:d});if(v.errorRaised)throw new Error("Could not highlight with `Highlight.js`",{cause:v.errorRaised});const S=v._emitter.root,w=S.data;return w.language=v.language,w.relevance=v.relevance,S}function a(d,h){const g=(h||tE).subset||s();let x=-1,v=0,S;for(;++x<g.length;){const w=g[x];if(!t.getLanguage(w))continue;const k=n(w,d,h);k.data&&k.data.relevance!==void 0&&k.data.relevance>v&&(v=k.data.relevance,S=k)}return S||{type:"root",children:[],data:{language:void 0,relevance:v}}}function s(){return t.listLanguages()}function o(d,h){if(typeof d=="string")t.registerLanguage(d,h);else{let y;for(y in d)Object.hasOwn(d,y)&&t.registerLanguage(y,d[y])}}function c(d,h){if(typeof d=="string")t.registerAliases(typeof h=="string"?h:[...h],{languageName:d});else{let y;for(y in d)if(Object.hasOwn(d,y)){const g=d[y];t.registerAliases(typeof g=="string"?g:[...g],{languageName:y})}}}function f(d){return!!t.getLanguage(d)}}class Y4{constructor(t){this.options=t,this.root={type:"root",children:[],data:{language:void 0,relevance:0}},this.stack=[this.root]}addText(t){if(t==="")return;const n=this.stack[this.stack.length-1],a=n.children[n.children.length-1];a&&a.type==="text"?a.value+=t:n.children.push({type:"text",value:t})}startScope(t){this.openNode(String(t))}endScope(){this.closeNode()}__addSublanguage(t,n){const a=this.stack[this.stack.length-1],s=t.root.children;n?a.children.push({type:"element",tagName:"span",properties:{className:[n]},children:s}):a.children.push(...s)}openNode(t){const n=this,a=t.split(".").map(function(c,f){return f?c+"_".repeat(f):n.options.classPrefix+c}),s=this.stack[this.stack.length-1],o={type:"element",tagName:"span",properties:{className:a},children:[]};s.children.push(o),this.stack.push(o)}closeNode(){this.stack.pop()}finalize(){}toHTML(){return""}}const V4={};function Mg(e){const t=e||V4,n=t.aliases,a=t.detect||!1,s=t.languages||P4,o=t.plainText,c=t.prefix,f=t.subset;let d="hljs";const h=Q4(s);if(n&&h.registerAlias(n),c){const y=c.indexOf("-");d=y===-1?c:c.slice(0,y)}return function(y,g){Jf(y,"element",function(x,v,S){if(x.tagName!=="code"||!S||S.type!=="element"||S.tagName!=="pre")return;const w=X4(x);if(w===!1||!w&&!a||w&&o&&o.includes(w))return;Array.isArray(x.properties.className)||(x.properties.className=[]),x.properties.className.includes(d)||x.properties.className.unshift(d);const k=pz(x,{whitespace:"pre"});let _;try{_=w?h.highlight(w,k,{prefix:c}):h.highlightAuto(k,{prefix:c,subset:f})}catch(A){const T=A;if(w&&/Unknown language/.test(T.message)){g.message("Cannot highlight as `"+w+"`, it’s not registered",{ancestors:[S,x],cause:T,place:x.position,ruleId:"missing-language",source:"rehype-highlight"});return}throw T}!w&&_.data&&_.data.language&&x.properties.className.push("language-"+_.data.language),_.children.length>0&&(x.children=_.children)})}}function X4(e){const t=e.properties.className;let n=-1;if(!Array.isArray(t))return;let a;for(;++n<t.length;){const s=String(t[n]);if(s==="no-highlight"||s==="nohighlight")return!1;!a&&s.slice(0,5)==="lang-"&&(a=s.slice(5)),!a&&s.slice(0,9)==="language-"&&(a=s.slice(9))}return a}function Z4({name:e,projects:t,onClose:n,onChange:a}){const{confirm:s,alert:o}=si(),{data:c,isLoading:f,isError:d,error:h,refetch:y}=lt({queryKey:["skill",e],queryFn:()=>zO(e)});M.useEffect(()=>{const _=A=>{A.key==="Escape"&&n()};return window.addEventListener("keydown",_),()=>window.removeEventListener("keydown",_)},[n]);const g=async(_,A)=>{try{await A(),await y(),a()}catch(T){o({title:`${_}失败`,body:T instanceof Error?T.message:String(T)})}},x=_=>g("link",()=>UO(e,_)),v=async _=>{await s({title:`从 ${_} 移除 ${e}`,body:"skill 链接会被解除,项目后续运行时将无法使用该 skill。",confirm:"移除",danger:!0})&&await g("unlink",()=>FO(e,_))},S=_=>g("freeze",()=>$O(e,_)),w=async _=>{await s({title:`解冻 ${e} @ ${_}`,body:"本地对这个 skill 的改动会被覆盖,回到最新共享版本。",confirm:"解冻",danger:!0})&&await g("unfreeze",()=>PO(e,_))},k=new Map(((c==null?void 0:c.linkedProjects)??[]).map(_=>[_.project,_.state]));return m.jsx("div",{role:"dialog","aria-modal":"true",className:"fixed inset-0 z-40 flex items-start justify-center p-6 bg-black/30 overflow-auto",children:m.jsxs("div",{className:"nb-card mt-8 w-full max-w-4xl",children:[m.jsxs("header",{className:"flex items-start justify-between gap-4 mb-4",children:[m.jsxs("div",{children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-3xl font-bold",children:e}),c&&m.jsxs("p",{className:"text-sm text-[var(--color-text-muted)] mt-1",children:[c.category," · ",c.origin||"local"]})]}),m.jsx("button",{onClick:n,className:"nb-btn nb-btn-mint p-2","aria-label":"关闭",type:"button",children:m.jsx(vr,{size:16,strokeWidth:3})})]}),f&&m.jsx("p",{children:"加载中…"}),d&&m.jsxs("p",{className:"text-[var(--color-crashed)]",children:["加载失败: ",h instanceof Error?h.message:String(h)]}),c&&m.jsxs("div",{className:"flex flex-col gap-4",children:[m.jsxs("div",{className:"nb-card bg-[var(--color-bg-cream)] p-4",children:[m.jsx("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-3 uppercase tracking-wider",children:"项目链接状态"}),m.jsxs("div",{className:"flex flex-col gap-2",children:[t.map(_=>{const A=k.get(_);return m.jsxs("div",{className:"flex items-center justify-between gap-3 p-2 bg-[var(--color-bg)] border-2 border-[var(--color-text)] rounded-lg",children:[m.jsxs("div",{className:"flex items-center gap-3",children:[m.jsx("span",{className:"font-[family-name:var(--font-mono)] font-bold text-sm",children:_}),A==="linked"&&m.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"linked"}),A==="frozen"&&m.jsx("span",{className:"nb-status",style:{background:"var(--color-stuck-bg)",color:"var(--color-stuck)"},children:"frozen"}),!A&&m.jsx("span",{className:"nb-status",style:{background:"var(--color-idle-bg)",color:"var(--color-idle)"},children:"absent"})]}),m.jsxs("div",{className:"flex gap-2",children:[!A&&m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"4px 10px",fontSize:11},onClick:()=>x(_),type:"button",children:[m.jsx(iA,{size:11})," link"]}),A==="linked"&&m.jsxs(m.Fragment,{children:[m.jsxs("button",{className:"nb-btn",style:{padding:"4px 10px",fontSize:11},onClick:()=>S(_),type:"button",children:[m.jsx(_A,{size:11})," freeze"]}),m.jsx("button",{className:"nb-btn nb-btn-danger",style:{padding:"4px 10px",fontSize:11},onClick:()=>v(_),type:"button",children:"unlink"})]}),A==="frozen"&&m.jsxs(m.Fragment,{children:[m.jsxs("button",{className:"nb-btn",style:{padding:"4px 10px",fontSize:11},onClick:()=>w(_),type:"button",children:[m.jsx(UC,{size:11})," unfreeze"]}),m.jsx("button",{className:"nb-btn nb-btn-danger",style:{padding:"4px 10px",fontSize:11},onClick:()=>v(_),type:"button",children:"unlink"})]})]})]},_)}),t.length===0&&m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] italic",children:"还没有任何项目。先去创建一个项目。"})]})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-2 uppercase tracking-wider",children:"SKILL.md 预览"}),m.jsx("div",{className:"prose-chat bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg p-4 max-h-80 overflow-auto text-sm",children:c.body?m.jsx(kg,{remarkPlugins:[Ag],rehypePlugins:[Mg],children:c.body}):m.jsx("p",{className:"text-[var(--color-text-muted)] italic",children:"(empty)"})})]}),c.references.length>0&&m.jsxs("div",{children:[m.jsx("h3",{className:"font-[family-name:var(--font-heading)] text-sm font-bold mb-2 uppercase tracking-wider",children:"References"}),m.jsx("ul",{className:"flex flex-col gap-2",children:c.references.map(_=>m.jsx(W4,{skillName:e,file:_.name,lines:_.lines},_.name))})]})]})]})})}function W4({skillName:e,file:t,lines:n}){const[a,s]=M.useState(!1),{data:o,isLoading:c,isError:f,error:d}=lt({queryKey:["skill-ref",e,t],queryFn:()=>BO(e,t),enabled:a,staleTime:1/0});return m.jsxs("li",{className:"border-2 border-[var(--color-text)] rounded-lg overflow-hidden bg-[var(--color-bg-cream)]",children:[m.jsxs("button",{type:"button",onClick:()=>s(h=>!h),"aria-label":`${a?"收起":"展开"} ${t}`,"aria-expanded":a,className:"w-full flex items-center gap-2 px-3 py-2 text-sm font-[family-name:var(--font-mono)] hover:bg-[var(--color-accent-yellow)] transition-colors",children:[m.jsx($p,{size:12,strokeWidth:3,className:["transition-transform",a?"rotate-90":""].join(" ")}),m.jsx(qp,{size:12,strokeWidth:2.5}),m.jsx("span",{className:"flex-1 text-left font-bold",children:t}),m.jsxs("span",{className:"text-xs text-[var(--color-text-subtle)]",children:[n," lines"]})]}),a&&m.jsxs("div",{className:"px-4 py-3 border-t-2 border-[var(--color-text)] bg-[var(--color-bg)] max-h-96 overflow-auto",children:[c&&m.jsx("p",{className:"text-xs text-[var(--color-text-muted)]",children:"加载中…"}),f&&m.jsxs("p",{className:"text-xs text-[var(--color-crashed)]",children:["加载失败: ",d instanceof Error?d.message:String(d)]}),o&&m.jsx("div",{className:"prose-chat text-sm",children:m.jsx(kg,{remarkPlugins:[Ag],rehypePlugins:[Mg],children:o.content})})]})]})}const J4=[{value:"all",label:"全部"},{value:"language",label:"language"},{value:"end",label:"end"},{value:"persona",label:"persona"},{value:"workflow",label:"workflow"},{value:"other",label:"other"}],eB={language:"var(--color-accent-purple)",end:"var(--color-secondary)",persona:"var(--color-primary)",workflow:"var(--color-accent-mint)",other:"var(--color-bg-cream)"};function tB(){var x;const[e,t]=M.useState("all"),[n,a]=M.useState(""),[s,o]=M.useState(null),c=qn(),{data:f,isLoading:d}=lt({queryKey:["skills"],queryFn:()=>lg()}),h=lt({queryKey:["projects"],queryFn:wr}),y=M.useMemo(()=>((f==null?void 0:f.data)??[]).filter(S=>!(e!=="all"&&S.category!==e||n&&!S.name.toLowerCase().includes(n.toLowerCase()))),[f,e,n]),g=M.useMemo(()=>{const v=(f==null?void 0:f.data)??[],S={all:v.length};for(const w of v)S[w.category]=(S[w.category]??0)+1;return S},[f]);return m.jsxs("div",{className:"flex flex-col gap-4 max-w-full",children:[m.jsxs("header",{className:"flex items-center justify-between flex-wrap gap-3",children:[m.jsxs("div",{children:[m.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-4xl font-bold",children:"Skills 🎯"}),m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] mt-1",children:d?"加载中…":`${(f==null?void 0:f.data.length)??0} 个 user-level skill`})]}),m.jsx("div",{className:"flex gap-3 items-center",children:m.jsxs("button",{className:"nb-btn nb-btn-mint",onClick:async()=>{await qO(),c.invalidateQueries({queryKey:["skills"]})},type:"button",children:[m.jsx(Cl,{size:14,strokeWidth:2.5}),"Sync bundled"]})})]}),m.jsxs("div",{className:"flex items-center gap-3 flex-wrap",children:[m.jsxs("div",{className:"relative flex-1 max-w-md",children:[m.jsx(xf,{size:14,className:"absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-text-subtle)]"}),m.jsx("input",{className:"nb-input pl-9 w-full",placeholder:"搜索 skill…",value:n,onChange:v=>a(v.target.value),"aria-label":"搜索 skill"})]}),m.jsx("div",{className:"flex gap-1 p-1 bg-[var(--color-bg)] border-[2px] border-[var(--color-text)] rounded-full shadow-[2px_2px_0_var(--color-text)]",children:J4.map(v=>m.jsxs("button",{type:"button",onClick:()=>t(v.value),className:["px-3 py-1 rounded-full text-xs font-bold font-[family-name:var(--font-body)]",e===v.value?"bg-[var(--color-text)] text-[var(--color-bg)]":"text-[var(--color-text-muted)] hover:text-[var(--color-text)]"].join(" "),children:[v.label," ",g[v.value]]},v.value))})]}),m.jsx("div",{className:"grid gap-4 grid-cols-[repeat(auto-fill,minmax(280px,1fr))]",children:y.map(v=>{var S;return m.jsx(nB,{skill:v,projectCount:((S=h.data)==null?void 0:S.data.length)??0,onOpen:()=>o(v.name)},v.name)})}),s&&m.jsx(Z4,{name:s,projects:((x=h.data)==null?void 0:x.data.map(v=>v.name))??[],onClose:()=>o(null),onChange:()=>c.invalidateQueries({queryKey:["skills"]})})]})}function nB({skill:e,projectCount:t,onOpen:n}){const a=eB[e.category];return m.jsxs("article",{onClick:n,onKeyDown:s=>{(s.key==="Enter"||s.key===" ")&&(s.preventDefault(),n())},tabIndex:0,role:"button","aria-label":`Open ${e.name}`,className:"nb-card nb-card-interactive flex flex-col gap-3",children:[m.jsxs("div",{className:"flex items-center justify-between",children:[m.jsx("h3",{className:"font-[family-name:var(--font-heading)] font-bold text-lg",children:e.name}),m.jsx("span",{className:"nb-badge text-[10px]",style:{background:a},children:e.category})]}),m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] leading-5 line-clamp-3",children:e.description||"(no description)"}),m.jsxs("div",{className:"flex items-center justify-between text-xs font-[family-name:var(--font-mono)] pt-2 border-t-[1.5px] border-dashed border-[var(--color-border-light)]",children:[m.jsx("span",{className:"font-bold",children:e.linkedProjects.length>0?`● linked in ${e.linkedProjects.length}`:"○ not linked"}),m.jsxs("span",{className:"text-[var(--color-text-subtle)]",children:[t," projects"]})]})]})}function iB(){var s;const e=lt({queryKey:["system-info"],queryFn:r1}),t=lt({queryKey:["system-env"],queryFn:$A}),[n,a]=M.useState(!1);return m.jsxs("div",{className:"flex flex-col gap-6 max-w-4xl",children:[m.jsx("header",{children:m.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-4xl font-bold",children:"系统 ⚙️"})}),m.jsx(aB,{current:(s=e.data)==null?void 0:s.version}),m.jsxs("section",{className:"nb-card",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold mb-3",children:"运行时"}),e.data?m.jsxs("dl",{className:"grid grid-cols-[160px_1fr] gap-y-2 text-sm",children:[m.jsx("dt",{className:"font-bold",children:"Node"}),m.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:e.data.nodeVersion}),m.jsx("dt",{className:"font-bold",children:"Platform"}),m.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:e.data.platform}),m.jsx("dt",{className:"font-bold",children:"PID"}),m.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:e.data.pid??"—"}),m.jsx("dt",{className:"font-bold",children:"Uptime"}),m.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:oB(e.data.uptimeMs)})]}):m.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"})]}),m.jsxs("section",{className:"nb-card",children:[m.jsxs("div",{className:"flex items-center justify-between mb-3",children:[m.jsxs("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold",children:["全局配置 ",m.jsx("code",{className:"text-sm font-[family-name:var(--font-mono)] font-normal bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] px-2 py-0.5 rounded",children:"~/.coral/env"})]}),n?m.jsx("span",{className:"text-xs text-[var(--color-stuck)] font-bold",children:"⚠ 编辑模式"}):m.jsxs("button",{className:"nb-btn",style:{padding:"6px 12px",fontSize:12},onClick:()=>a(!0),type:"button","aria-label":"编辑 env 文件",children:[m.jsx(Hp,{size:12,strokeWidth:2.5})," 编辑"]})]}),n?m.jsx(rB,{onClose:()=>{a(!1),t.refetch()}}):t.data&&t.data.exists?m.jsx("dl",{className:"grid grid-cols-[220px_1fr] gap-y-1 text-sm font-[family-name:var(--font-mono)]",children:t.data.entries.map(o=>m.jsxs("div",{className:"contents",children:[m.jsxs("dt",{className:"font-bold flex items-center gap-2",children:[o.masked&&m.jsx("span",{className:"text-[var(--color-stuck)]",children:"🔒"}),o.key]}),m.jsx("dd",{className:"text-[var(--color-text-muted)] truncate",children:o.value})]},o.key))}):m.jsxs("p",{className:"text-[var(--color-text-muted)] text-sm",children:['env 文件不存在。点"编辑"或者终端运行 ',m.jsx("code",{className:"bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] px-2 py-0.5 rounded font-[family-name:var(--font-mono)]",children:"sps setup"}),"。"]})]}),m.jsx(sB,{})]})}function aB({current:e}){var S;const{confirm:t,alert:n}=si(),[a,s]=M.useState(!1),[o,c]=M.useState(null),f=lt({queryKey:["latest-version"],queryFn:HA,enabled:!1}),[d,h]=M.useState(null),[y,g]=M.useState("npm i -g @coralai/sps-cli@latest"),x=async()=>{var k;if(await t({title:"升级 sps-cli",body:`当前 ${e},升级到 ${(k=f.data)==null?void 0:k.latest}。要求所有 pipeline 已停止。升级后请重启 sps console 生效。`,confirm:"升级"})){s(!0),c(null),h(null);try{const _=await KA();if(c(_.output),h(_.installedVersion),g(_.command),_.ok)n({title:"升级完成",body:`装上了 v${_.installedVersion}。请 \`pkill -f "sps console"\` 再重启以生效。`});else{const A=_.installedVersion&&_.installedVersion===e?`npm 执行完毕但版本没变(仍 ${_.installedVersion})——多半是权限或 registry 问题。可复制下面的命令在终端手动跑。`:"npm 没装上新版本。可复制命令手动跑,或看下面日志定位。";n({title:"升级未生效",body:A})}}catch(_){c(_.message),n({title:"升级失败",body:_.message})}finally{s(!1)}}},v=async()=>{const w=f.data&&!f.data.upToDate?`npm i -g @coralai/sps-cli@${f.data.latest}`:y;try{await navigator.clipboard.writeText(w),n({title:"命令已复制",body:`粘贴到终端运行即可:
|
|
515
515
|
${w}`})}catch{n({title:"复制失败",body:`请手动复制:
|
|
516
|
-
${w}`})}};return m.jsxs("section",{className:"nb-card",children:[m.jsxs("div",{className:"flex items-center justify-between mb-3",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold",children:"版本"}),m.jsxs("button",{className:"nb-btn",style:{padding:"6px 12px",fontSize:12},onClick:()=>f.refetch(),disabled:f.isFetching||!e,type:"button","aria-label":"检查最新版本",children:[f.isFetching?m.jsx(Wt,{size:12,strokeWidth:3,className:"animate-spin"}):m.jsx(Cl,{size:12,strokeWidth:2.5}),"检查更新"]})]}),m.jsxs("dl",{className:"grid grid-cols-[160px_1fr] gap-y-2 text-sm",children:[m.jsx("dt",{className:"font-bold",children:"sps-cli (当前)"}),m.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:e??"—"}),f.data&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{className:"font-bold",children:"npm (最新)"}),m.jsxs("dd",{className:"font-[family-name:var(--font-mono)] flex items-center gap-2 flex-wrap",children:[f.data.latest,f.data.upToDate?m.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"最新"}):m.jsxs(m.Fragment,{children:[m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"3px 10px",fontSize:11},onClick:x,disabled:a,type:"button","aria-label":"升级到最新版本",children:[a?m.jsx(Wt,{size:11,strokeWidth:3,className:"animate-spin"}):m.jsx(XE,{size:11,strokeWidth:2.5}),"升级"]}),m.jsxs("button",{className:"nb-btn",style:{padding:"3px 10px",fontSize:11},onClick:v,type:"button","aria-label":"复制升级命令",title:"自动升级失败时手动跑",children:[m.jsx(DC,{size:11,strokeWidth:2.5})," 复制命令"]})]})]})]}),d&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{className:"font-bold",children:"已安装"}),m.jsxs("dd",{className:"font-[family-name:var(--font-mono)] flex items-center gap-2",children:[d,d===((S=f.data)==null?void 0:S.latest)?m.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"已生效(重启 console 后可见)"}):d===e?m.jsx("span",{className:"nb-status",style:{background:"var(--color-stuck-bg)",color:"var(--color-stuck)"},children:"未升级成功"}):null]})]}),f.isError&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{className:"font-bold",children:"检查"}),m.jsx("dd",{className:"text-[var(--color-crashed)] text-xs",children:f.error instanceof Error?f.error.message:String(f.error)})]})]}),o&&m.jsx("pre",{className:"mt-3 text-xs font-[family-name:var(--font-mono)] bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg p-3 max-h-40 overflow-auto whitespace-pre-wrap",children:o})]})}function rB({onClose:e}){const t=qn(),{alert:n}=si(),a=lt({queryKey:["system-env-raw"],queryFn:PA}),[s,o]=M.useState(null),[c,f]=M.useState(null);M.useEffect(()=>{a.data&&s===null&&(o(a.data.content),f(a.data.etag))},[a.data,s]);const d=s!==null&&a.data&&s!==a.data.content,h=Pn({mutationFn:()=>{if(s===null)throw new Error("no draft");return qA(s,c??"")},onSuccess:()=>{t.invalidateQueries({queryKey:["system-env"]}),t.invalidateQueries({queryKey:["system-env-raw"]}),e()},onError:y=>{const g=y.status;n({title:g===409?"env 被其他地方修改了":"保存失败",body:g===409?"请点取消后重开编辑。":y instanceof Error?y.message:String(y)})}});return a.isLoading?m.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"}):m.jsxs("div",{children:[m.jsx("p",{className:"text-xs text-[var(--color-stuck)] font-bold mb-2",children:"⚠ 文件包含凭证明文。保存时保持 0600 权限。"}),m.jsx("textarea",{className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",style:{minHeight:320,resize:"vertical"},value:s??"",onChange:y=>o(y.target.value),spellCheck:!1,"aria-label":"env 文件编辑器"}),m.jsxs("div",{className:"flex items-center justify-between mt-3",children:[m.jsxs("span",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)]",children:[c?`etag: ${c}`:"",d?" · ● 未保存":""]}),m.jsxs("div",{className:"flex gap-2",children:[m.jsxs("button",{className:"nb-btn",style:{padding:"6px 12px"},onClick:e,disabled:h.isPending,type:"button",children:[m.jsx(vr,{size:12,strokeWidth:3})," 取消"]}),m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"6px 12px"},onClick:()=>h.mutate(),disabled:!d||h.isPending,type:"button","aria-label":"保存 env",children:[h.isPending?m.jsx(Wt,{size:12,strokeWidth:3,className:"animate-spin"}):m.jsx(Df,{size:12,strokeWidth:3}),"保存"]})]})]})]})}function sB(){var g;const{alert:e}=si(),t=lt({queryKey:["projects"],queryFn:wr}),[n,a]=M.useState({}),[s,o]=M.useState({}),[c,f]=M.useState({}),d=(((g=t.data)==null?void 0:g.data)??[]).map(x=>({project:x.name})),h=async(x,v)=>{o(S=>({...S,[x]:v?"fix":"check"}));try{const S=await GA(x,v);a(w=>({...w,[x]:S})),f(w=>({...w,[x]:!0}))}catch(S){e({title:`doctor ${v?"修复":"检查"}失败`,body:S instanceof Error?S.message:String(S)})}finally{o(S=>({...S,[x]:null}))}},y=async()=>{for(const x of d)await h(x.project,!1)};return m.jsxs("section",{className:"nb-card",children:[m.jsxs("div",{className:"flex items-center justify-between mb-3",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold",children:"项目健康检查"}),m.jsxs("button",{className:"nb-btn nb-btn-mint",style:{padding:"6px 12px",fontSize:12},onClick:()=>{y()},disabled:d.length===0||Object.values(s).some(Boolean),type:"button",children:[m.jsx(Cl,{size:12,strokeWidth:2.5}),"检查全部"]})]}),d.length===0?m.jsx("p",{className:"text-[var(--color-text-muted)] text-sm",children:"还没有项目。"}):m.jsx("ul",{className:"flex flex-col gap-2",children:d.map(x=>{const v=n[x.project],S=s[x.project],w=v?v.checks.filter(T=>T.status==="fail").length:0,k=v?v.checks.filter(T=>T.status==="warn").length:0,_=c[x.project]??!1,A=v!=null;return m.jsxs("li",{className:"bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg",children:[m.jsxs("div",{className:"flex items-center gap-3 px-3 py-2",children:[m.jsxs("button",{type:"button",onClick:()=>f(T=>({...T,[x.project]:!_})),disabled:!A,className:"flex items-center gap-2 flex-1 text-left min-w-0","aria-label":_?"折叠":"展开",children:[A&&v.ok?m.jsx(ap,{size:16,className:"text-[var(--color-running)] shrink-0",strokeWidth:2.5}):A?m.jsx(rc,{size:16,className:"text-[var(--color-stuck)] shrink-0",strokeWidth:2.5}):m.jsx(ap,{size:16,className:"text-[var(--color-text-subtle)] shrink-0",strokeWidth:2.5}),A&&(_?m.jsx(yc,{size:12}):m.jsx($p,{size:12})),m.jsx("span",{className:"font-bold font-[family-name:var(--font-mono)]",children:x.project}),A?v.ok?m.jsx("span",{className:"text-xs text-[var(--color-running)] font-semibold",children:"OK"}):m.jsxs("span",{className:"text-xs text-[var(--color-stuck)] font-semibold",children:[w," fail · ",k," warn"]}):m.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:'点 "检查" 运行 sps doctor'})]}),m.jsxs("button",{className:"nb-btn",style:{padding:"4px 10px",fontSize:11},onClick:()=>{h(x.project,!1)},disabled:!!S,type:"button","aria-label":"检查",children:[S==="check"?m.jsx(Wt,{size:11,strokeWidth:3,className:"animate-spin"}):m.jsx(Cl,{size:11,strokeWidth:2.5}),"检查"]}),A&&!v.ok&&m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"4px 10px",fontSize:11},onClick:()=>{h(x.project,!0)},disabled:!!S,type:"button","aria-label":"自动修复",children:[S==="fix"?m.jsx(Wt,{size:11,strokeWidth:3,className:"animate-spin"}):m.jsx(a1,{size:11,strokeWidth:2.5}),"修复"]})]}),_&&A&&m.jsxs("div",{className:"border-t-2 border-dashed border-[var(--color-text)] px-3 py-2",children:[m.jsx("ul",{className:"flex flex-col gap-1 text-xs font-[family-name:var(--font-mono)]",children:v.checks.map((T,D)=>m.jsx(lB,{check:T},`${T.name}-${D}`))}),v.fixes.length>0&&m.jsxs("div",{className:"mt-3 bg-[var(--color-running-bg)] border-2 border-[var(--color-running)] rounded p-2",children:[m.jsx("div",{className:"text-xs font-bold text-[var(--color-running)] mb-1",children:"已修复"}),m.jsx("ul",{className:"text-xs list-disc pl-4",children:v.fixes.map((T,D)=>m.jsx("li",{children:T},D))})]})]})]},x.project)})})]})}function lB({check:e}){const t=e.status==="pass"?m.jsx(ap,{size:12,className:"text-[var(--color-running)]",strokeWidth:2.5}):e.status==="fail"?m.jsx(rc,{size:12,className:"text-[var(--color-crashed)]",strokeWidth:2.5}):e.status==="warn"?m.jsx(rc,{size:12,className:"text-[var(--color-stuck)]",strokeWidth:2.5}):m.jsx("span",{className:"w-3 h-3 rounded-full bg-[var(--color-text-subtle)] inline-block"});return m.jsxs("li",{className:"flex items-start gap-2",children:[m.jsx("span",{className:"pt-0.5 shrink-0",children:t}),m.jsx("span",{className:"font-bold w-32 shrink-0",children:e.name}),m.jsx("span",{className:"text-[var(--color-text-muted)] break-words",children:e.message})]})}function oB(e){const t=Math.floor(e/1e3),n=Math.floor(t/3600),a=Math.floor(t%3600/60),s=t%60;return n>0?`${n}h ${a}m ${s}s`:a>0?`${a}m ${s}s`:`${s}s`}function cB(){return Ht("/api/chat/sessions")}function uB(e){return Ht(`/api/chat/sessions/${e}`)}async function nE(e={}){const t=await fetch("/api/chat/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new Error(`${t.status}: ${await t.text()}`);return await t.json()}async function fB(e){const t=await fetch(`/api/chat/sessions/${e}`,{method:"DELETE"});if(!t.ok)throw new Error(`${t.status}`)}async function dB(e,t){const n=await fetch(`/api/chat/sessions/${e}/messages`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:t})});if(!n.ok)throw new Error(`${n.status}: ${await n.text()}`);return await n.json()}async function hB(e){const t=await fetch(`/api/chat/sessions/${e}/interrupt`,{method:"POST"});if(!t.ok&&t.status!==204)throw new Error(`${t.status}: ${await t.text()}`)}function mB(e,t){const n=t?`?since=${encodeURIComponent(t)}`:"";return Ht(`/api/chat/sessions/${e}/messages${n}`)}function iE(){var A,T,D,$,j,q;const{sessionId:e}=UE(),t=Sr(),n=qn(),{confirm:a,alert:s}=si(),o=lt({queryKey:["chat-sessions"],queryFn:cB}),c=lt({queryKey:["chat-session",e],queryFn:()=>uB(e??""),enabled:!!e}),[f,d]=M.useState(null),[h,y]=M.useState(""),[g,x]=M.useState(!1),v=M.useRef(null);M.useEffect(()=>{if(!e)return;const U=new EventSource(`/stream/chat/${encodeURIComponent(e)}`);let Z=!0;return U.addEventListener("open",()=>{if(Z){Z=!1;return}const O=n.getQueryData(["chat-session",e]),P=O!=null&&O.messages.length?O.messages[O.messages.length-1].ts:void 0;mB(e,P).then(G=>{G.data.length!==0&&n.setQueryData(["chat-session",e],le=>{if(!le)return le;const ae=new Set(le.messages.map(K=>K.id)),W=G.data.filter(K=>!ae.has(K.id));return W.length===0?le:{...le,messages:[...le.messages,...W],lastMessageAt:W[W.length-1].ts,messageCount:le.messageCount+W.length}})}).catch(()=>{})}),U.addEventListener("chat.message",O=>{try{const P=JSON.parse(O.data);n.setQueryData(["chat-session",e],G=>{if(!G||G.messages.some(W=>W.id===P.message.id))return G;const ae=G.messages.findIndex(W=>W.role==="user"&&W.id.startsWith("optim-")&&W.content===P.message.content);if(ae>=0){const W=[...G.messages];return W[ae]=P.message,{...G,messages:W}}return{...G,messages:[...G.messages,P.message]}})}catch{}}),U.addEventListener("chat.message.pending",O=>{try{const P=JSON.parse(O.data);d({id:P.assistantId,blocks:[],done:!1,finalMessage:null})}catch{}}),U.addEventListener("chat.message.chunk.text",O=>{try{const P=JSON.parse(O.data);d(G=>{if(!G||G.id!==P.assistantId)return G;const le=[...G.blocks],ae=le[le.length-1];return ae&&ae.type==="text"?le[le.length-1]={...ae,target:ae.target+P.text}:le.push({type:"text",target:P.text,displayed:""}),{...G,blocks:le}})}catch{}}),U.addEventListener("chat.message.chunk.tool_use",O=>{try{const P=JSON.parse(O.data);d(G=>!G||G.id!==P.assistantId?G:{...G,blocks:[...G.blocks,{type:"tool_use",id:P.id,title:P.title,kind:P.kind,status:P.status}]})}catch{}}),U.addEventListener("chat.message.chunk.tool_update",O=>{try{const P=JSON.parse(O.data);d(G=>!G||G.id!==P.assistantId?G:{...G,blocks:G.blocks.map(le=>le.type==="tool_use"&&le.id===P.id?{...le,status:P.status}:le)})}catch{}}),U.addEventListener("chat.message.complete",O=>{try{const P=JSON.parse(O.data);d(G=>G&&G.id===P.assistantId?{...G,done:!0,finalMessage:P.message}:G)}catch{}}),()=>U.close()},[e,n]),M.useEffect(()=>{if(!f)return;const U=f.blocks.reduce((O,P)=>P.type==="text"?O+(P.target.length-P.displayed.length):O,0);if(U<=0){if(f.done&&f.finalMessage){const O=f.finalMessage;n.setQueryData(["chat-session",e],P=>!P||P.messages.some(G=>G.id===O.id)?P:{...P,messages:[...P.messages,O],lastMessageAt:O.ts,messageCount:P.messageCount+1}),n.invalidateQueries({queryKey:["chat-sessions"]}),d(null),x(!1)}return}const Z=setTimeout(()=>{d(O=>{if(!O)return O;let P=Math.max(1,Math.ceil(U/40));const G=O.blocks.map(le=>{if(le.type!=="text"||P<=0)return le;const ae=le.target.length-le.displayed.length;if(ae<=0)return le;const W=Math.min(ae,P);return P-=W,{...le,displayed:le.target.slice(0,le.displayed.length+W)}});return{...O,blocks:G}})},25);return()=>clearTimeout(Z)},[f,n,e]),M.useEffect(()=>{const U=v.current;U&&(U.scrollTop=U.scrollHeight)},[c.data,f]);const S=M.useCallback(async()=>{const U=await nE();n.invalidateQueries({queryKey:["chat-sessions"]}),t(`/chat/${U.id}`)},[n,t]),w=M.useCallback(async()=>{const U=h.trim();if(!U||g)return;let Z=e;if(!Z){const P=await nE();n.invalidateQueries({queryKey:["chat-sessions"]}),Z=P.id,t(`/chat/${Z}`,{replace:!0})}const O={id:`optim-${Date.now()}`,role:"user",content:U,ts:new Date().toISOString(),status:"complete"};n.setQueryData(["chat-session",Z],P=>P?{...P,messages:[...P.messages,O],lastMessageAt:O.ts,messageCount:P.messageCount+1}:{id:Z,createdAt:O.ts,lastMessageAt:O.ts,title:U.slice(0,60),project:null,messageCount:1,messages:[O]}),y(""),x(!0);try{await dB(Z,U)}catch(P){x(!1),console.error("sendMessage failed",P),s({title:"发送失败",body:P instanceof Error?P.message:String(P)})}},[h,g,e,n,t,s]),k=M.useCallback(async U=>{await a({title:"删除对话",body:"对话记录会永久删除,不可恢复。",confirm:"删除",danger:!0})&&(await fB(U),n.invalidateQueries({queryKey:["chat-sessions"]}),e===U&&t("/chat"))},[n,e,t,a]),_=M.useCallback(async()=>{if(e)try{await hB(e)}catch(U){s({title:"中断失败",body:U instanceof Error?U.message:String(U)})}},[e,s]);return m.jsxs("div",{className:"grid grid-cols-[260px_1fr] gap-4 h-[calc(100vh-140px)]",children:[m.jsxs("aside",{className:"nb-card p-3 overflow-auto flex flex-col gap-2",children:[m.jsxs("button",{className:"nb-btn nb-btn-primary w-full justify-center",onClick:S,type:"button",children:[m.jsx(Xi,{size:14,strokeWidth:3}),"新建对话"]}),m.jsxs("div",{className:"mt-2 text-xs font-[family-name:var(--font-heading)] uppercase tracking-wider text-[var(--color-text-muted)] px-2",children:["历史 ",((A=o.data)==null?void 0:A.data.length)??0]}),m.jsxs("div",{className:"flex flex-col gap-1.5 mt-1",children:[(((T=o.data)==null?void 0:T.data)??[]).map(U=>m.jsxs("div",{className:["group flex items-start gap-2 p-2 rounded-lg border-2 border-transparent",e===U.id?"bg-[var(--color-accent-mint)] border-[var(--color-text)] shadow-[2px_2px_0_var(--color-text)]":"hover:bg-[var(--color-bg-cream)] hover:border-[var(--color-text)]"].join(" "),children:[m.jsxs("button",{type:"button","aria-label":`打开对话 ${U.title}`,onClick:()=>t(`/chat/${U.id}`),className:"flex items-start gap-2 flex-1 min-w-0 text-left",children:[m.jsx($v,{size:14,strokeWidth:2.5,className:"mt-0.5 flex-shrink-0"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("p",{className:"text-sm font-semibold truncate",children:U.title}),m.jsxs("p",{className:"text-[10px] text-[var(--color-text-muted)] font-[family-name:var(--font-mono)] truncate",children:[U.messageCount," msg · ",Dw(U.lastMessageAt??U.createdAt)]})]})]}),m.jsx("button",{type:"button","aria-label":"删除对话",className:"opacity-0 group-hover:opacity-100 p-1 hover:text-[var(--color-crashed)]",onClick:Z=>{Z.stopPropagation(),k(U.id)},children:m.jsx(Il,{size:12})})]},U.id)),(((D=o.data)==null?void 0:D.data)??[]).length===0&&m.jsx("p",{className:"text-xs text-[var(--color-text-subtle)] italic text-center py-4",children:"还没对话。点上面新建。"})]})]}),m.jsx("div",{className:"nb-card p-0 flex flex-col overflow-hidden",children:e?m.jsxs(m.Fragment,{children:[m.jsxs("header",{className:"px-4 py-3 border-b-2 border-[var(--color-text)] bg-[var(--color-bg-cream)]",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] font-bold text-lg",children:(($=c.data)==null?void 0:$.title)??"新对话"}),m.jsx("p",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)]",children:e})]}),m.jsxs("div",{ref:v,className:"flex-1 overflow-auto p-4 flex flex-col gap-4",children:[(((j=c.data)==null?void 0:j.messages)??[]).map(U=>m.jsx(pB,{msg:U},U.id)),f&&m.jsx(gB,{pending:f}),!c.isLoading&&(((q=c.data)==null?void 0:q.messages)??[]).length===0&&!f&&!g&&m.jsx("p",{className:"text-center text-[var(--color-text-subtle)] italic mt-12",children:"下方输入问题开始对话 · Enter 发送 · Shift+Enter 换行"})]}),m.jsx("div",{className:"border-t-2 border-[var(--color-text)] p-3 bg-[var(--color-bg-cream)]",children:m.jsxs("div",{className:"flex gap-2 items-end",children:[m.jsx("textarea",{className:"nb-input flex-1 resize-none",placeholder:"说点什么… (Enter 发送,Shift+Enter 换行)",rows:2,value:h,onChange:U=>y(U.target.value),onKeyDown:U=>{U.key==="Enter"&&!U.shiftKey&&!U.nativeEvent.isComposing&&(U.preventDefault(),w())},"aria-label":"消息输入"}),f?m.jsxs("button",{className:"nb-btn nb-btn-danger",onClick:_,type:"button","aria-label":"中断生成",children:[m.jsx(e1,{size:14,strokeWidth:3}),"中断"]}):m.jsxs("button",{className:"nb-btn nb-btn-primary",onClick:w,disabled:!h.trim()||g,type:"button","aria-label":"发送",children:[g?m.jsx(Wt,{size:14,strokeWidth:3,className:"animate-spin"}):m.jsx(xA,{size:14,strokeWidth:3}),"发送"]})]})})]}):m.jsx("div",{className:"flex-1 flex items-center justify-center p-8",children:m.jsxs("div",{className:"text-center max-w-md",children:[m.jsx("div",{className:"w-20 h-20 rounded-2xl bg-[var(--color-accent-mint)] border-[3px] border-[var(--color-text)] shadow-[3px_3px_0_var(--color-text)] flex items-center justify-center mx-auto mb-4",children:m.jsx($v,{size:32,strokeWidth:2.5})}),m.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-2xl font-bold mb-2",children:"对话 💬"}),m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] mb-4",children:'点左上角"新建对话"开始一个 session。或直接在下方输入,会自动建 session。'}),m.jsx("p",{className:"text-xs text-[var(--color-text-subtle)] italic",children:"Enter 发送 · Shift+Enter 换行 · 内容流式返回"})]})})})]})}function pB({msg:e}){const t=e.role==="user",n=e.role==="error",a=e.blocks&&e.blocks.length>0?e.blocks:[{type:"text",text:e.content}];return m.jsx("div",{className:t?"self-end max-w-3xl":"self-start max-w-3xl",children:m.jsxs("div",{className:["nb-card",t?"bg-[var(--color-secondary)]":n?"bg-[var(--color-crashed-bg)]":"bg-[var(--color-bg)]"].join(" "),children:[m.jsxs("p",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-2 flex items-center gap-2",children:[t?"你":n?"错误":"assistant",m.jsx("span",{className:"font-normal",children:"·"}),m.jsx("span",{className:"font-normal",children:Dw(e.ts)})]}),m.jsx("div",{className:"flex flex-col gap-2",children:a.map((s,o)=>m.jsx(bB,{block:s},o))}),e.truncated&&m.jsx("p",{className:"mt-3 px-3 py-2 bg-[var(--color-stuck-bg)] border-2 border-[var(--color-stuck)] rounded-lg text-xs text-[var(--color-stuck)] font-bold",children:"⚠ 输出超过 10MB,已截断"})]})})}function gB({pending:e}){const t=(()=>{for(let n=e.blocks.length-1;n>=0;n--)if(e.blocks[n].type==="text")return n;return-1})();return m.jsx("div",{className:"self-start max-w-3xl",children:m.jsxs("div",{className:"nb-card bg-[var(--color-bg)]",children:[m.jsxs("p",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-2 flex items-center gap-2",children:["assistant",m.jsx("span",{className:"font-normal",children:"·"}),m.jsxs("span",{className:"flex items-center gap-1 font-normal text-[var(--color-running)]",children:[m.jsx(Wt,{size:10,strokeWidth:3,className:"animate-spin"}),"streaming"]})]}),m.jsxs("div",{className:"flex flex-col gap-2",children:[e.blocks.length===0&&m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] italic",children:"…"}),e.blocks.map((n,a)=>{if(n.type==="text"){const s=a===t;return m.jsxs("div",{className:"relative",children:[m.jsx(Mw,{text:n.displayed}),s&&m.jsx("span",{className:"inline-block w-2 h-4 ml-1 bg-[var(--color-text)] animate-pulse align-middle"})]},a)}return m.jsx(jw,{tool:n},a)})]})]})})}function bB({block:e}){return e.type==="text"?m.jsx(Mw,{text:e.text}):m.jsx(jw,{tool:e})}function Mw({text:e}){return e?m.jsx("div",{className:"text-sm font-[family-name:var(--font-body)] break-words prose-chat",children:m.jsx(kg,{remarkPlugins:[Ag],rehypePlugins:[Mg],children:e})}):null}function jw({tool:e}){const[t,n]=M.useState(!1),a=e.status==="completed",s=e.status==="failed",o=!a&&!s;return m.jsxs("div",{className:"border-2 border-[var(--color-text)] rounded-lg overflow-hidden bg-[var(--color-bg-cream)]",children:[m.jsxs("button",{type:"button",onClick:()=>n(c=>!c),className:"w-full flex items-center gap-2 px-3 py-2 text-xs font-[family-name:var(--font-mono)] hover:bg-[var(--color-accent-yellow)] transition-colors",children:[m.jsx($p,{size:12,strokeWidth:3,className:["transition-transform",t?"rotate-90":""].join(" ")}),m.jsx(a1,{size:12,strokeWidth:2.5}),m.jsx("span",{className:"font-bold",children:e.kind}),m.jsx("span",{className:"flex-1 text-left text-[var(--color-text-muted)] truncate",children:e.title}),o&&m.jsx(Wt,{size:12,strokeWidth:3,className:"animate-spin text-[var(--color-running)]"}),a&&m.jsx(Pp,{size:12,strokeWidth:2.5,className:"text-[var(--color-running)]"}),s&&m.jsx(OC,{size:12,strokeWidth:2.5,className:"text-[var(--color-crashed)]"})]}),t&&m.jsxs("div",{className:"px-3 py-2 text-xs font-[family-name:var(--font-mono)] text-[var(--color-text-muted)] border-t-2 border-[var(--color-text)]",children:[m.jsxs("div",{children:["id: ",m.jsx("span",{className:"text-[var(--color-text)]",children:e.id})]}),m.jsxs("div",{children:["status: ",m.jsx("span",{className:"text-[var(--color-text)]",children:e.status})]})]})]})}function Dw(e){if(!e)return"";const t=new Date(e),n=Date.now()-t.getTime();return n<6e4?"刚才":n<36e5?`${Math.floor(n/6e4)}m`:n<864e5?`${Math.floor(n/36e5)}h`:t.toLocaleDateString()}function yB(){return m.jsxs("div",{className:"nb-card max-w-2xl mt-12",children:[m.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-4xl font-bold mb-2",children:"404 · 页面不存在"}),m.jsx("p",{className:"text-[var(--color-text-muted)] mb-6",children:"没找到这个页面。可能是链接过期了。"}),m.jsx(ds,{to:"/",className:"nb-btn nb-btn-mint inline-flex",children:"返回首页"})]})}function xB(){return m.jsx(c2,{children:m.jsx(jT,{children:m.jsxs(zn,{element:m.jsx(l2,{}),children:[m.jsx(zn,{index:!0,element:m.jsx(OT,{to:"/projects",replace:!0})}),m.jsx(zn,{path:"/projects",element:m.jsx(u2,{})}),m.jsx(zn,{path:"/projects/new",element:m.jsx(x2,{})}),m.jsx(zn,{path:"/projects/:name",element:m.jsx(MO,{})}),m.jsx(zn,{path:"/board",element:m.jsx(yR,{})}),m.jsx(zn,{path:"/workers",element:m.jsx(jR,{})}),m.jsx(zn,{path:"/logs",element:m.jsx(BR,{})}),m.jsx(zn,{path:"/skills",element:m.jsx(tB,{})}),m.jsx(zn,{path:"/system",element:m.jsx(iB,{})}),m.jsx(zn,{path:"/chat",element:m.jsx(iE,{})}),m.jsx(zn,{path:"/chat/:sessionId",element:m.jsx(iE,{})}),m.jsx(zn,{path:"*",element:m.jsx(yB,{})})]})})})}o2();const vB=new vN({defaultOptions:{queries:{staleTime:3e4,refetchOnWindowFocus:!1}}}),Lw=document.getElementById("root");if(!Lw)throw new Error("#root not found");Vk.createRoot(Lw).render(m.jsx(M.StrictMode,{children:m.jsx(EN,{client:vB,children:m.jsx(aC,{children:m.jsx(g2,{children:m.jsx(xB,{})})})})}));
|
|
516
|
+
${w}`})}};return m.jsxs("section",{className:"nb-card",children:[m.jsxs("div",{className:"flex items-center justify-between mb-3",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold",children:"版本"}),m.jsxs("button",{className:"nb-btn",style:{padding:"6px 12px",fontSize:12},onClick:()=>f.refetch(),disabled:f.isFetching||!e,type:"button","aria-label":"检查最新版本",children:[f.isFetching?m.jsx(Wt,{size:12,strokeWidth:3,className:"animate-spin"}):m.jsx(Cl,{size:12,strokeWidth:2.5}),"检查更新"]})]}),m.jsxs("dl",{className:"grid grid-cols-[160px_1fr] gap-y-2 text-sm",children:[m.jsx("dt",{className:"font-bold",children:"sps-cli (当前)"}),m.jsx("dd",{className:"font-[family-name:var(--font-mono)]",children:e??"—"}),f.data&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{className:"font-bold",children:"npm (最新)"}),m.jsxs("dd",{className:"font-[family-name:var(--font-mono)] flex items-center gap-2 flex-wrap",children:[f.data.latest,f.data.upToDate?m.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"最新"}):m.jsxs(m.Fragment,{children:[m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"3px 10px",fontSize:11},onClick:x,disabled:a,type:"button","aria-label":"升级到最新版本",children:[a?m.jsx(Wt,{size:11,strokeWidth:3,className:"animate-spin"}):m.jsx(XE,{size:11,strokeWidth:2.5}),"升级"]}),m.jsxs("button",{className:"nb-btn",style:{padding:"3px 10px",fontSize:11},onClick:v,type:"button","aria-label":"复制升级命令",title:"自动升级失败时手动跑",children:[m.jsx(DC,{size:11,strokeWidth:2.5})," 复制命令"]})]})]})]}),d&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{className:"font-bold",children:"已安装"}),m.jsxs("dd",{className:"font-[family-name:var(--font-mono)] flex items-center gap-2",children:[d,d===((S=f.data)==null?void 0:S.latest)?m.jsx("span",{className:"nb-status",style:{background:"var(--color-running-bg)",color:"var(--color-running)"},children:"已生效(重启 console 后可见)"}):d===e?m.jsx("span",{className:"nb-status",style:{background:"var(--color-stuck-bg)",color:"var(--color-stuck)"},children:"未升级成功"}):null]})]}),f.isError&&m.jsxs(m.Fragment,{children:[m.jsx("dt",{className:"font-bold",children:"检查"}),m.jsx("dd",{className:"text-[var(--color-crashed)] text-xs",children:f.error instanceof Error?f.error.message:String(f.error)})]})]}),o&&m.jsx("pre",{className:"mt-3 text-xs font-[family-name:var(--font-mono)] bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg p-3 max-h-40 overflow-auto whitespace-pre-wrap",children:o})]})}function rB({onClose:e}){const t=qn(),{alert:n}=si(),a=lt({queryKey:["system-env-raw"],queryFn:PA}),[s,o]=M.useState(null),[c,f]=M.useState(null);M.useEffect(()=>{a.data&&s===null&&(o(a.data.content),f(a.data.etag))},[a.data,s]);const d=s!==null&&a.data&&s!==a.data.content,h=Pn({mutationFn:()=>{if(s===null)throw new Error("no draft");return qA(s,c??"")},onSuccess:()=>{t.invalidateQueries({queryKey:["system-env"]}),t.invalidateQueries({queryKey:["system-env-raw"]}),e()},onError:y=>{const g=y.status;n({title:g===409?"env 被其他地方修改了":"保存失败",body:g===409?"请点取消后重开编辑。":y instanceof Error?y.message:String(y)})}});return a.isLoading?m.jsx("p",{className:"text-[var(--color-text-muted)]",children:"加载中…"}):m.jsxs("div",{children:[m.jsx("p",{className:"text-xs text-[var(--color-stuck)] font-bold mb-2",children:"⚠ 文件包含凭证明文。保存时保持 0600 权限。"}),m.jsx("textarea",{className:"nb-input w-full font-[family-name:var(--font-mono)] text-xs",style:{minHeight:320,resize:"vertical"},value:s??"",onChange:y=>o(y.target.value),spellCheck:!1,"aria-label":"env 文件编辑器"}),m.jsxs("div",{className:"flex items-center justify-between mt-3",children:[m.jsxs("span",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)]",children:[c?`etag: ${c}`:"",d?" · ● 未保存":""]}),m.jsxs("div",{className:"flex gap-2",children:[m.jsxs("button",{className:"nb-btn",style:{padding:"6px 12px"},onClick:e,disabled:h.isPending,type:"button",children:[m.jsx(vr,{size:12,strokeWidth:3})," 取消"]}),m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"6px 12px"},onClick:()=>h.mutate(),disabled:!d||h.isPending,type:"button","aria-label":"保存 env",children:[h.isPending?m.jsx(Wt,{size:12,strokeWidth:3,className:"animate-spin"}):m.jsx(Df,{size:12,strokeWidth:3}),"保存"]})]})]})]})}function sB(){var g;const{alert:e}=si(),t=lt({queryKey:["projects"],queryFn:wr}),[n,a]=M.useState({}),[s,o]=M.useState({}),[c,f]=M.useState({}),d=(((g=t.data)==null?void 0:g.data)??[]).map(x=>({project:x.name})),h=async(x,v)=>{o(S=>({...S,[x]:v?"fix":"check"}));try{const S=await GA(x,v);a(w=>({...w,[x]:S})),f(w=>({...w,[x]:!0}))}catch(S){e({title:`doctor ${v?"修复":"检查"}失败`,body:S instanceof Error?S.message:String(S)})}finally{o(S=>({...S,[x]:null}))}},y=async()=>{for(const x of d)await h(x.project,!1)};return m.jsxs("section",{className:"nb-card",children:[m.jsxs("div",{className:"flex items-center justify-between mb-3",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] text-xl font-bold",children:"项目健康检查"}),m.jsxs("button",{className:"nb-btn nb-btn-mint",style:{padding:"6px 12px",fontSize:12},onClick:()=>{y()},disabled:d.length===0||Object.values(s).some(Boolean),type:"button",children:[m.jsx(Cl,{size:12,strokeWidth:2.5}),"检查全部"]})]}),d.length===0?m.jsx("p",{className:"text-[var(--color-text-muted)] text-sm",children:"还没有项目。"}):m.jsx("ul",{className:"flex flex-col gap-2",children:d.map(x=>{const v=n[x.project],S=s[x.project],w=v?v.checks.filter(T=>T.status==="fail").length:0,k=v?v.checks.filter(T=>T.status==="warn").length:0,_=c[x.project]??!1,A=v!=null;return m.jsxs("li",{className:"bg-[var(--color-bg-cream)] border-2 border-[var(--color-text)] rounded-lg",children:[m.jsxs("div",{className:"flex items-center gap-3 px-3 py-2",children:[m.jsxs("button",{type:"button",onClick:()=>f(T=>({...T,[x.project]:!_})),disabled:!A,className:"flex items-center gap-2 flex-1 text-left min-w-0","aria-label":_?"折叠":"展开",children:[A&&v.ok?m.jsx(ap,{size:16,className:"text-[var(--color-running)] shrink-0",strokeWidth:2.5}):A?m.jsx(rc,{size:16,className:"text-[var(--color-stuck)] shrink-0",strokeWidth:2.5}):m.jsx(ap,{size:16,className:"text-[var(--color-text-subtle)] shrink-0",strokeWidth:2.5}),A&&(_?m.jsx(yc,{size:12}):m.jsx($p,{size:12})),m.jsx("span",{className:"font-bold font-[family-name:var(--font-mono)]",children:x.project}),A?v.ok?m.jsx("span",{className:"text-xs text-[var(--color-running)] font-semibold",children:"OK"}):m.jsxs("span",{className:"text-xs text-[var(--color-stuck)] font-semibold",children:[w," fail · ",k," warn"]}):m.jsx("span",{className:"text-xs text-[var(--color-text-muted)]",children:'点 "检查" 运行 sps doctor'})]}),m.jsxs("button",{className:"nb-btn",style:{padding:"4px 10px",fontSize:11},onClick:()=>{h(x.project,!1)},disabled:!!S,type:"button","aria-label":"检查",children:[S==="check"?m.jsx(Wt,{size:11,strokeWidth:3,className:"animate-spin"}):m.jsx(Cl,{size:11,strokeWidth:2.5}),"检查"]}),m.jsxs("button",{className:"nb-btn nb-btn-primary",style:{padding:"4px 10px",fontSize:11},onClick:()=>{h(x.project,!0)},disabled:!!S||A&&v.ok,type:"button","aria-label":"自动修复",title:A&&v.ok?"已无可修问题":"调 sps doctor <proj> --fix:自动创建 .claude/hooks/stop.sh、state.json 等",children:[S==="fix"?m.jsx(Wt,{size:11,strokeWidth:3,className:"animate-spin"}):m.jsx(a1,{size:11,strokeWidth:2.5}),"修复"]})]}),_&&A&&m.jsxs("div",{className:"border-t-2 border-dashed border-[var(--color-text)] px-3 py-2",children:[m.jsx("ul",{className:"flex flex-col gap-1 text-xs font-[family-name:var(--font-mono)]",children:v.checks.map((T,D)=>m.jsx(lB,{check:T},`${T.name}-${D}`))}),v.fixes.length>0&&m.jsxs("div",{className:"mt-3 bg-[var(--color-running-bg)] border-2 border-[var(--color-running)] rounded p-2",children:[m.jsx("div",{className:"text-xs font-bold text-[var(--color-running)] mb-1",children:"已修复"}),m.jsx("ul",{className:"text-xs list-disc pl-4",children:v.fixes.map((T,D)=>m.jsx("li",{children:T},D))})]})]})]},x.project)})})]})}function lB({check:e}){const t=e.status==="pass"?m.jsx(ap,{size:12,className:"text-[var(--color-running)]",strokeWidth:2.5}):e.status==="fail"?m.jsx(rc,{size:12,className:"text-[var(--color-crashed)]",strokeWidth:2.5}):e.status==="warn"?m.jsx(rc,{size:12,className:"text-[var(--color-stuck)]",strokeWidth:2.5}):m.jsx("span",{className:"w-3 h-3 rounded-full bg-[var(--color-text-subtle)] inline-block"});return m.jsxs("li",{className:"flex items-start gap-2",children:[m.jsx("span",{className:"pt-0.5 shrink-0",children:t}),m.jsx("span",{className:"font-bold w-32 shrink-0",children:e.name}),m.jsx("span",{className:"text-[var(--color-text-muted)] break-words",children:e.message})]})}function oB(e){const t=Math.floor(e/1e3),n=Math.floor(t/3600),a=Math.floor(t%3600/60),s=t%60;return n>0?`${n}h ${a}m ${s}s`:a>0?`${a}m ${s}s`:`${s}s`}function cB(){return Ht("/api/chat/sessions")}function uB(e){return Ht(`/api/chat/sessions/${e}`)}async function nE(e={}){const t=await fetch("/api/chat/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new Error(`${t.status}: ${await t.text()}`);return await t.json()}async function fB(e){const t=await fetch(`/api/chat/sessions/${e}`,{method:"DELETE"});if(!t.ok)throw new Error(`${t.status}`)}async function dB(e,t){const n=await fetch(`/api/chat/sessions/${e}/messages`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:t})});if(!n.ok)throw new Error(`${n.status}: ${await n.text()}`);return await n.json()}async function hB(e){const t=await fetch(`/api/chat/sessions/${e}/interrupt`,{method:"POST"});if(!t.ok&&t.status!==204)throw new Error(`${t.status}: ${await t.text()}`)}function mB(e,t){const n=t?`?since=${encodeURIComponent(t)}`:"";return Ht(`/api/chat/sessions/${e}/messages${n}`)}function iE(){var A,T,D,$,j,q;const{sessionId:e}=UE(),t=Sr(),n=qn(),{confirm:a,alert:s}=si(),o=lt({queryKey:["chat-sessions"],queryFn:cB}),c=lt({queryKey:["chat-session",e],queryFn:()=>uB(e??""),enabled:!!e}),[f,d]=M.useState(null),[h,y]=M.useState(""),[g,x]=M.useState(!1),v=M.useRef(null);M.useEffect(()=>{if(!e)return;const U=new EventSource(`/stream/chat/${encodeURIComponent(e)}`);let Z=!0;return U.addEventListener("open",()=>{if(Z){Z=!1;return}const O=n.getQueryData(["chat-session",e]),P=O!=null&&O.messages.length?O.messages[O.messages.length-1].ts:void 0;mB(e,P).then(G=>{G.data.length!==0&&n.setQueryData(["chat-session",e],le=>{if(!le)return le;const ae=new Set(le.messages.map(K=>K.id)),W=G.data.filter(K=>!ae.has(K.id));return W.length===0?le:{...le,messages:[...le.messages,...W],lastMessageAt:W[W.length-1].ts,messageCount:le.messageCount+W.length}})}).catch(()=>{})}),U.addEventListener("chat.message",O=>{try{const P=JSON.parse(O.data);n.setQueryData(["chat-session",e],G=>{if(!G||G.messages.some(W=>W.id===P.message.id))return G;const ae=G.messages.findIndex(W=>W.role==="user"&&W.id.startsWith("optim-")&&W.content===P.message.content);if(ae>=0){const W=[...G.messages];return W[ae]=P.message,{...G,messages:W}}return{...G,messages:[...G.messages,P.message]}})}catch{}}),U.addEventListener("chat.message.pending",O=>{try{const P=JSON.parse(O.data);d({id:P.assistantId,blocks:[],done:!1,finalMessage:null})}catch{}}),U.addEventListener("chat.message.chunk.text",O=>{try{const P=JSON.parse(O.data);d(G=>{if(!G||G.id!==P.assistantId)return G;const le=[...G.blocks],ae=le[le.length-1];return ae&&ae.type==="text"?le[le.length-1]={...ae,target:ae.target+P.text}:le.push({type:"text",target:P.text,displayed:""}),{...G,blocks:le}})}catch{}}),U.addEventListener("chat.message.chunk.tool_use",O=>{try{const P=JSON.parse(O.data);d(G=>!G||G.id!==P.assistantId?G:{...G,blocks:[...G.blocks,{type:"tool_use",id:P.id,title:P.title,kind:P.kind,status:P.status}]})}catch{}}),U.addEventListener("chat.message.chunk.tool_update",O=>{try{const P=JSON.parse(O.data);d(G=>!G||G.id!==P.assistantId?G:{...G,blocks:G.blocks.map(le=>le.type==="tool_use"&&le.id===P.id?{...le,status:P.status}:le)})}catch{}}),U.addEventListener("chat.message.complete",O=>{try{const P=JSON.parse(O.data);d(G=>G&&G.id===P.assistantId?{...G,done:!0,finalMessage:P.message}:G)}catch{}}),()=>U.close()},[e,n]),M.useEffect(()=>{if(!f)return;const U=f.blocks.reduce((O,P)=>P.type==="text"?O+(P.target.length-P.displayed.length):O,0);if(U<=0){if(f.done&&f.finalMessage){const O=f.finalMessage;n.setQueryData(["chat-session",e],P=>!P||P.messages.some(G=>G.id===O.id)?P:{...P,messages:[...P.messages,O],lastMessageAt:O.ts,messageCount:P.messageCount+1}),n.invalidateQueries({queryKey:["chat-sessions"]}),d(null),x(!1)}return}const Z=setTimeout(()=>{d(O=>{if(!O)return O;let P=Math.max(1,Math.ceil(U/40));const G=O.blocks.map(le=>{if(le.type!=="text"||P<=0)return le;const ae=le.target.length-le.displayed.length;if(ae<=0)return le;const W=Math.min(ae,P);return P-=W,{...le,displayed:le.target.slice(0,le.displayed.length+W)}});return{...O,blocks:G}})},25);return()=>clearTimeout(Z)},[f,n,e]),M.useEffect(()=>{const U=v.current;U&&(U.scrollTop=U.scrollHeight)},[c.data,f]);const S=M.useCallback(async()=>{const U=await nE();n.invalidateQueries({queryKey:["chat-sessions"]}),t(`/chat/${U.id}`)},[n,t]),w=M.useCallback(async()=>{const U=h.trim();if(!U||g)return;let Z=e;if(!Z){const P=await nE();n.invalidateQueries({queryKey:["chat-sessions"]}),Z=P.id,t(`/chat/${Z}`,{replace:!0})}const O={id:`optim-${Date.now()}`,role:"user",content:U,ts:new Date().toISOString(),status:"complete"};n.setQueryData(["chat-session",Z],P=>P?{...P,messages:[...P.messages,O],lastMessageAt:O.ts,messageCount:P.messageCount+1}:{id:Z,createdAt:O.ts,lastMessageAt:O.ts,title:U.slice(0,60),project:null,messageCount:1,messages:[O]}),y(""),x(!0);try{await dB(Z,U)}catch(P){x(!1),console.error("sendMessage failed",P),s({title:"发送失败",body:P instanceof Error?P.message:String(P)})}},[h,g,e,n,t,s]),k=M.useCallback(async U=>{await a({title:"删除对话",body:"对话记录会永久删除,不可恢复。",confirm:"删除",danger:!0})&&(await fB(U),n.invalidateQueries({queryKey:["chat-sessions"]}),e===U&&t("/chat"))},[n,e,t,a]),_=M.useCallback(async()=>{if(e)try{await hB(e)}catch(U){s({title:"中断失败",body:U instanceof Error?U.message:String(U)})}},[e,s]);return m.jsxs("div",{className:"grid grid-cols-[260px_1fr] gap-4 h-[calc(100vh-140px)]",children:[m.jsxs("aside",{className:"nb-card p-3 overflow-auto flex flex-col gap-2",children:[m.jsxs("button",{className:"nb-btn nb-btn-primary w-full justify-center",onClick:S,type:"button",children:[m.jsx(Xi,{size:14,strokeWidth:3}),"新建对话"]}),m.jsxs("div",{className:"mt-2 text-xs font-[family-name:var(--font-heading)] uppercase tracking-wider text-[var(--color-text-muted)] px-2",children:["历史 ",((A=o.data)==null?void 0:A.data.length)??0]}),m.jsxs("div",{className:"flex flex-col gap-1.5 mt-1",children:[(((T=o.data)==null?void 0:T.data)??[]).map(U=>m.jsxs("div",{className:["group flex items-start gap-2 p-2 rounded-lg border-2 border-transparent",e===U.id?"bg-[var(--color-accent-mint)] border-[var(--color-text)] shadow-[2px_2px_0_var(--color-text)]":"hover:bg-[var(--color-bg-cream)] hover:border-[var(--color-text)]"].join(" "),children:[m.jsxs("button",{type:"button","aria-label":`打开对话 ${U.title}`,onClick:()=>t(`/chat/${U.id}`),className:"flex items-start gap-2 flex-1 min-w-0 text-left",children:[m.jsx($v,{size:14,strokeWidth:2.5,className:"mt-0.5 flex-shrink-0"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("p",{className:"text-sm font-semibold truncate",children:U.title}),m.jsxs("p",{className:"text-[10px] text-[var(--color-text-muted)] font-[family-name:var(--font-mono)] truncate",children:[U.messageCount," msg · ",Dw(U.lastMessageAt??U.createdAt)]})]})]}),m.jsx("button",{type:"button","aria-label":"删除对话",className:"opacity-0 group-hover:opacity-100 p-1 hover:text-[var(--color-crashed)]",onClick:Z=>{Z.stopPropagation(),k(U.id)},children:m.jsx(Il,{size:12})})]},U.id)),(((D=o.data)==null?void 0:D.data)??[]).length===0&&m.jsx("p",{className:"text-xs text-[var(--color-text-subtle)] italic text-center py-4",children:"还没对话。点上面新建。"})]})]}),m.jsx("div",{className:"nb-card p-0 flex flex-col overflow-hidden",children:e?m.jsxs(m.Fragment,{children:[m.jsxs("header",{className:"px-4 py-3 border-b-2 border-[var(--color-text)] bg-[var(--color-bg-cream)]",children:[m.jsx("h2",{className:"font-[family-name:var(--font-heading)] font-bold text-lg",children:(($=c.data)==null?void 0:$.title)??"新对话"}),m.jsx("p",{className:"text-xs text-[var(--color-text-muted)] font-[family-name:var(--font-mono)]",children:e})]}),m.jsxs("div",{ref:v,className:"flex-1 overflow-auto p-4 flex flex-col gap-4",children:[(((j=c.data)==null?void 0:j.messages)??[]).map(U=>m.jsx(pB,{msg:U},U.id)),f&&m.jsx(gB,{pending:f}),!c.isLoading&&(((q=c.data)==null?void 0:q.messages)??[]).length===0&&!f&&!g&&m.jsx("p",{className:"text-center text-[var(--color-text-subtle)] italic mt-12",children:"下方输入问题开始对话 · Enter 发送 · Shift+Enter 换行"})]}),m.jsx("div",{className:"border-t-2 border-[var(--color-text)] p-3 bg-[var(--color-bg-cream)]",children:m.jsxs("div",{className:"flex gap-2 items-end",children:[m.jsx("textarea",{className:"nb-input flex-1 resize-none",placeholder:"说点什么… (Enter 发送,Shift+Enter 换行)",rows:2,value:h,onChange:U=>y(U.target.value),onKeyDown:U=>{U.key==="Enter"&&!U.shiftKey&&!U.nativeEvent.isComposing&&(U.preventDefault(),w())},"aria-label":"消息输入"}),f?m.jsxs("button",{className:"nb-btn nb-btn-danger",onClick:_,type:"button","aria-label":"中断生成",children:[m.jsx(e1,{size:14,strokeWidth:3}),"中断"]}):m.jsxs("button",{className:"nb-btn nb-btn-primary",onClick:w,disabled:!h.trim()||g,type:"button","aria-label":"发送",children:[g?m.jsx(Wt,{size:14,strokeWidth:3,className:"animate-spin"}):m.jsx(xA,{size:14,strokeWidth:3}),"发送"]})]})})]}):m.jsx("div",{className:"flex-1 flex items-center justify-center p-8",children:m.jsxs("div",{className:"text-center max-w-md",children:[m.jsx("div",{className:"w-20 h-20 rounded-2xl bg-[var(--color-accent-mint)] border-[3px] border-[var(--color-text)] shadow-[3px_3px_0_var(--color-text)] flex items-center justify-center mx-auto mb-4",children:m.jsx($v,{size:32,strokeWidth:2.5})}),m.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-2xl font-bold mb-2",children:"对话 💬"}),m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] mb-4",children:'点左上角"新建对话"开始一个 session。或直接在下方输入,会自动建 session。'}),m.jsx("p",{className:"text-xs text-[var(--color-text-subtle)] italic",children:"Enter 发送 · Shift+Enter 换行 · 内容流式返回"})]})})})]})}function pB({msg:e}){const t=e.role==="user",n=e.role==="error",a=e.blocks&&e.blocks.length>0?e.blocks:[{type:"text",text:e.content}];return m.jsx("div",{className:t?"self-end max-w-3xl":"self-start max-w-3xl",children:m.jsxs("div",{className:["nb-card",t?"bg-[var(--color-secondary)]":n?"bg-[var(--color-crashed-bg)]":"bg-[var(--color-bg)]"].join(" "),children:[m.jsxs("p",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-2 flex items-center gap-2",children:[t?"你":n?"错误":"assistant",m.jsx("span",{className:"font-normal",children:"·"}),m.jsx("span",{className:"font-normal",children:Dw(e.ts)})]}),m.jsx("div",{className:"flex flex-col gap-2",children:a.map((s,o)=>m.jsx(bB,{block:s},o))}),e.truncated&&m.jsx("p",{className:"mt-3 px-3 py-2 bg-[var(--color-stuck-bg)] border-2 border-[var(--color-stuck)] rounded-lg text-xs text-[var(--color-stuck)] font-bold",children:"⚠ 输出超过 10MB,已截断"})]})})}function gB({pending:e}){const t=(()=>{for(let n=e.blocks.length-1;n>=0;n--)if(e.blocks[n].type==="text")return n;return-1})();return m.jsx("div",{className:"self-start max-w-3xl",children:m.jsxs("div",{className:"nb-card bg-[var(--color-bg)]",children:[m.jsxs("p",{className:"text-xs font-bold uppercase tracking-wider text-[var(--color-text-muted)] mb-2 flex items-center gap-2",children:["assistant",m.jsx("span",{className:"font-normal",children:"·"}),m.jsxs("span",{className:"flex items-center gap-1 font-normal text-[var(--color-running)]",children:[m.jsx(Wt,{size:10,strokeWidth:3,className:"animate-spin"}),"streaming"]})]}),m.jsxs("div",{className:"flex flex-col gap-2",children:[e.blocks.length===0&&m.jsx("p",{className:"text-sm text-[var(--color-text-muted)] italic",children:"…"}),e.blocks.map((n,a)=>{if(n.type==="text"){const s=a===t;return m.jsxs("div",{className:"relative",children:[m.jsx(Mw,{text:n.displayed}),s&&m.jsx("span",{className:"inline-block w-2 h-4 ml-1 bg-[var(--color-text)] animate-pulse align-middle"})]},a)}return m.jsx(jw,{tool:n},a)})]})]})})}function bB({block:e}){return e.type==="text"?m.jsx(Mw,{text:e.text}):m.jsx(jw,{tool:e})}function Mw({text:e}){return e?m.jsx("div",{className:"text-sm font-[family-name:var(--font-body)] break-words prose-chat",children:m.jsx(kg,{remarkPlugins:[Ag],rehypePlugins:[Mg],children:e})}):null}function jw({tool:e}){const[t,n]=M.useState(!1),a=e.status==="completed",s=e.status==="failed",o=!a&&!s;return m.jsxs("div",{className:"border-2 border-[var(--color-text)] rounded-lg overflow-hidden bg-[var(--color-bg-cream)]",children:[m.jsxs("button",{type:"button",onClick:()=>n(c=>!c),className:"w-full flex items-center gap-2 px-3 py-2 text-xs font-[family-name:var(--font-mono)] hover:bg-[var(--color-accent-yellow)] transition-colors",children:[m.jsx($p,{size:12,strokeWidth:3,className:["transition-transform",t?"rotate-90":""].join(" ")}),m.jsx(a1,{size:12,strokeWidth:2.5}),m.jsx("span",{className:"font-bold",children:e.kind}),m.jsx("span",{className:"flex-1 text-left text-[var(--color-text-muted)] truncate",children:e.title}),o&&m.jsx(Wt,{size:12,strokeWidth:3,className:"animate-spin text-[var(--color-running)]"}),a&&m.jsx(Pp,{size:12,strokeWidth:2.5,className:"text-[var(--color-running)]"}),s&&m.jsx(OC,{size:12,strokeWidth:2.5,className:"text-[var(--color-crashed)]"})]}),t&&m.jsxs("div",{className:"px-3 py-2 text-xs font-[family-name:var(--font-mono)] text-[var(--color-text-muted)] border-t-2 border-[var(--color-text)]",children:[m.jsxs("div",{children:["id: ",m.jsx("span",{className:"text-[var(--color-text)]",children:e.id})]}),m.jsxs("div",{children:["status: ",m.jsx("span",{className:"text-[var(--color-text)]",children:e.status})]})]})]})}function Dw(e){if(!e)return"";const t=new Date(e),n=Date.now()-t.getTime();return n<6e4?"刚才":n<36e5?`${Math.floor(n/6e4)}m`:n<864e5?`${Math.floor(n/36e5)}h`:t.toLocaleDateString()}function yB(){return m.jsxs("div",{className:"nb-card max-w-2xl mt-12",children:[m.jsx("h1",{className:"font-[family-name:var(--font-heading)] text-4xl font-bold mb-2",children:"404 · 页面不存在"}),m.jsx("p",{className:"text-[var(--color-text-muted)] mb-6",children:"没找到这个页面。可能是链接过期了。"}),m.jsx(ds,{to:"/",className:"nb-btn nb-btn-mint inline-flex",children:"返回首页"})]})}function xB(){return m.jsx(c2,{children:m.jsx(jT,{children:m.jsxs(zn,{element:m.jsx(l2,{}),children:[m.jsx(zn,{index:!0,element:m.jsx(OT,{to:"/projects",replace:!0})}),m.jsx(zn,{path:"/projects",element:m.jsx(u2,{})}),m.jsx(zn,{path:"/projects/new",element:m.jsx(x2,{})}),m.jsx(zn,{path:"/projects/:name",element:m.jsx(MO,{})}),m.jsx(zn,{path:"/board",element:m.jsx(yR,{})}),m.jsx(zn,{path:"/workers",element:m.jsx(jR,{})}),m.jsx(zn,{path:"/logs",element:m.jsx(BR,{})}),m.jsx(zn,{path:"/skills",element:m.jsx(tB,{})}),m.jsx(zn,{path:"/system",element:m.jsx(iB,{})}),m.jsx(zn,{path:"/chat",element:m.jsx(iE,{})}),m.jsx(zn,{path:"/chat/:sessionId",element:m.jsx(iE,{})}),m.jsx(zn,{path:"*",element:m.jsx(yB,{})})]})})})}o2();const vB=new vN({defaultOptions:{queries:{staleTime:3e4,refetchOnWindowFocus:!1}}}),Lw=document.getElementById("root");if(!Lw)throw new Error("#root not found");Vk.createRoot(Lw).render(m.jsx(M.StrictMode,{children:m.jsx(EN,{client:vB,children:m.jsx(aC,{children:m.jsx(g2,{children:m.jsx(xB,{})})})})}));
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600;700&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-KZ-tPjmm.js"></script>
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/index-BgOHCIG1.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|