claude-simple 0.2.27 → 0.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/bin/edge-ctl.js +151 -4
- package/client.js +29 -4
- package/dist/addon-fit.min.js +0 -0
- package/dist/app.0.2.30.min.js +1308 -0
- package/dist/index.html +2 -2
- package/dist/style.0.2.30.min.css +2012 -0
- package/dist/xterm.min.css +0 -0
- package/dist/xterm.min.js +0 -0
- package/gateway.js +0 -0
- package/package.json +2 -2
- package/public/addon-fit.min.js +0 -0
- package/public/agent-panel.js +54 -22
- package/public/api.js +8 -5
- package/public/app.js +7 -5
- package/public/base.css +0 -0
- package/public/cache.js +19 -0
- package/public/chat.js +110 -19
- package/public/files.js +26 -10
- package/public/git.js +2 -2
- package/public/icons/icon-180.png +0 -0
- package/public/icons/icon-192.png +0 -0
- package/public/icons/icon-512.png +0 -0
- package/public/icons/icon-maskable-512.png +0 -0
- package/public/index.html +2 -2
- package/public/lib.js +0 -0
- package/public/manifest.webmanifest +0 -0
- package/public/markdown.js +16 -0
- package/public/math.js +145 -7
- package/public/mobile.js +0 -0
- package/public/notes.js +316 -0
- package/public/notifications.js +0 -0
- package/public/offline.html +0 -0
- package/public/pwa.js +1 -1
- package/public/router.js +4 -0
- package/public/scroll-follow.js +78 -0
- package/public/settings.js +41 -0
- package/public/shell/boot.js +0 -0
- package/public/shell/dashboard.js +0 -0
- package/public/shell/hub.js +0 -0
- package/public/shell/layout.js +0 -0
- package/public/shell/notes.js +0 -0
- package/public/shell/session-context.js +0 -0
- package/public/shell/session-list.js +79 -21
- package/public/shell/session-nav.js +70 -21
- package/public/shell/templates.js +3 -0
- package/public/shell/util.js +0 -0
- package/public/shell.js +15 -2
- package/public/state.js +7 -7
- package/public/style.css +161 -0
- package/public/sw.js +10 -5
- package/public/terminal.js +0 -0
- package/public/wake-lock.js +0 -0
- package/public/workspace-path.js +61 -0
- package/public/xterm.min.css +0 -0
- package/public/xterm.min.js +0 -0
- package/src/agent-quota.js +228 -0
- package/src/agents/claude.js +0 -0
- package/src/agents/codex.js +2 -0
- package/src/agents/cursor.js +2 -1
- package/src/agents/gemini.js +2 -1
- package/src/agents/grok.js +22 -1
- package/src/agents/meta-agent.js +7 -4
- package/src/agents/models.js +21 -12
- package/src/agents/sessions.js +270 -81
- package/src/agents/stream-batch.js +0 -0
- package/src/app.js +111 -51
- package/src/auto-update.js +2 -0
- package/src/collab.js +3 -0
- package/src/platform.js +133 -0
- package/src/project-api-path.js +14 -0
- package/src/runtime/approvals.js +0 -0
- package/src/runtime/chat-broadcast.js +12 -0
- package/src/runtime/outbox.js +0 -0
- package/src/runtime/port-websocket.js +80 -0
- package/src/runtime/protocol.js +0 -0
- package/src/session-history.js +31 -0
- package/dist/app.0.2.27.min.js +0 -1182
- package/dist/style.0.2.27.min.css +0 -1851
|
@@ -0,0 +1,1308 @@
|
|
|
1
|
+
var wd=Object.defineProperty;var U=(e,t,n)=>()=>{if(n)throw n[0];try{return e&&(t=e(e=0)),t}catch(s){throw n=[s],s}};var ls=(e,t)=>{for(var n in t)wd(e,n,{get:t[n],enumerable:!0})};function $d(){Ho||(Ho=!0,queueMicrotask(()=>{Ho=!1,Bo()}))}function yi(e){for(let t of e)(t._isComputed?En:In).add(t);Ro>0||na||(kd==="microtask"?$d():Bo())}function ki(e,t,n,s){let a=new Set(n);for(let r of n)r._subs.delete(t);n.clear(),s?.forEach(r=>r?.()),s?.splice(0);let o=[Gt,us,No];[Gt,us,No]=[t,n,s];try{return e()}catch(r){for(let d of a)d._subs.add(t),n.add(d);throw r}finally{[Gt,us,No]=o}}var Gt,us,Ro,No,En,In,na,cs,Po,kd,Ho,Bo,wi,I,Oo,je,xe,De,Tn,Sd,p,b,$i,i,qo,Ld,ot,ds,Ed,sa,Id,Hf,aa,qf,Rf,Si,Li=U(()=>{Gt=null,us=null,Ro=0,No=null,En=new Set,In=new Set,na=!1,cs=1e4,Po={flushes:0,runs:0,lastFlushRuns:0},kd="sync",Ho=!1;Bo=()=>{if(na)return;na=!0;let e=0;Po.flushes++;try{for(;En.size||In.size;){for(;En.size;){let t=En.values().next().value;if(En.delete(t),++e>cs)throw new Error(`mini-react: reactive update loop exceeded ${cs} runs`);t()}if(In.size){let t=In.values().next().value;if(In.delete(t),++e>cs)throw new Error(`mini-react: reactive update loop exceeded ${cs} runs`);t()}}}finally{Po.runs+=e,Po.lastFlushRuns=e,e>cs&&(En.clear(),In.clear()),na=!1}};wi=class{constructor(e,t){this._v=e,this._subs=new Set,this._eq=t??((n,s)=>n===s)}get value(){return Gt&&(this._subs.add(Gt),us?.add(this)),this._v}set value(e){this._eq(e,this._v)||(this._v=e,yi(this._subs))}peek(){return this._v}},I=(e,{equals:t}={})=>new wi(e,t);Oo=e=>{let t=new wi(void 0),n=new Set,s=!0,a=!1,o=u=>{if(!s||a)return t._v;s=!1;try{let l=ki(e,r,n,null),f=l!==t._v;f&&(t._v=l),f&&u&&yi(t._subs)}catch(l){s=!0,console.error("[computed]",l)}return t._v},r=()=>{s||a||(s=!0,t._subs.size&&o(!0))};r._isComputed=!0;let d=()=>o(!1);return Object.defineProperty(t,"value",{get(){return Gt&&(t._subs.add(Gt),us?.add(t)),d()},set(){throw new TypeError("Cannot assign to a computed signal")}}),t.dispose=()=>{if(!a){a=!0;for(let u of n)u._subs.delete(r);n.clear()}},t},je=e=>{let t=new Set,n=[],s=()=>{try{let a=ki(e,s,t,n);typeof a=="function"&&n.push(a)}catch(a){console.error("[effect]",a)}};return s(),()=>{for(let a of t)a._subs.delete(s);t.clear(),n.forEach(a=>a?.()),n.splice(0)}},xe=e=>{Ro++;try{e()}finally{--Ro===0&&Bo()}},De=(e,t)=>{let n=e.peek(),s=!1;return je(()=>{let a=e.value;s&&t(a,n),s=!0,n=a})},Tn=e=>je(()=>{let t=new AbortController;return Promise.resolve(e(t.signal)).catch(n=>{n?.name!=="AbortError"&&console.error("[asyncEffect]",n)}),()=>t.abort()}),Sd={"&":"&","<":"<",">":">",'"':"""},p=e=>String(e??"").replace(/[&<>"]/g,t=>Sd[t]),b=(()=>{let e=new Map,t=n=>{e.has(n)||(e.set(n,[]),document.addEventListener(n,s=>{xe(()=>{for(let[a,o]of e.get(n)){let r=s.target.closest(a);r&&o(s,r)}})},{capture:!0}))};return{on:(n,s,a)=>{t(n);let o=[s,a];return e.get(n).push(o),()=>e.set(n,e.get(n).filter(r=>r!==o))},off:(n,s)=>{e.has(n)&&e.set(n,e.get(n).filter(([a])=>a!==s))}}})(),$i=(e,{keepAlive:t=!1}={})=>{let n=I(location.hash.slice(1)||"/"),s=!1,a=()=>{n.value=location.hash.slice(1)||"/"};window.addEventListener("hashchange",a);let o=t?new Map:null,r=(l,f)=>{if(!t)return f();if(o.has(l))return o.get(l);let m=f();return o.set(l,m),m},d=I(void 0),u=je(()=>{let l=n.value;for(let[f,m]of Object.entries(e)){if(f==="*")continue;let g=new RegExp("^"+f.replace(/:\w+/g,"([^/]+)")+"$"),w=l.match(g);if(w){let y=w.slice(1);d.value=typeof m=="function"?r(`${f}|${y.join("/")}`,()=>m(...y)):m;return}}if(e["*"]){let f=e["*"];d.value=typeof f=="function"?r("*",f):f;return}d.value=null});return{current:n,route:d,navigate:l=>{s||(location.hash=l)},match:l=>{let f=n.value.match(new RegExp("^"+l.replace(/:\w+/g,"([^/]+)")+"$"));return f?f.slice(1):null},invalidate:l=>{if(o){if(l===void 0){o.clear();return}for(let f of[...o.keys()])(f===l||f.startsWith(`${l}|`))&&o.delete(f)}},dispose:()=>{s||(s=!0,window.removeEventListener("hashchange",a),u(),o?.clear())}}},i=e=>document.getElementById(e),qo=()=>typeof navigator>"u"||navigator.onLine!==!1,Ld=e=>new Promise(t=>setTimeout(t,e)),ot=e=>e===void 0?"undefined":e===null||typeof e!="object"?JSON.stringify(e):e instanceof Date?`Date(${e.toJSON()})`:Array.isArray(e)?`[${e.map(ot).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${ot(e[t])}`).join(",")}}`,ds=(e,t)=>{if(!t)return!0;if(typeof t=="function")return t(e);if(t.queryKey){let n=ot(t.queryKey);if(t.exact?e.hash!==n:!e.hash.startsWith(n.slice(0,-1)))return!1}return!t.tags||t.tags.some(n=>e.tags.has(n))},Ed=e=>{try{return JSON.stringify(e),!0}catch{return!1}},sa=(e,t)=>{if(Object.is(e,t))return e;if(!e||!t||typeof e!="object"||typeof t!="object")return t;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return t;let a=t.map((o,r)=>sa(e[r],o));return a.every((o,r)=>o===e[r])?e:a}if(Array.isArray(e)||Array.isArray(t)||Object.getPrototypeOf(e)!==Object.prototype||Object.getPrototypeOf(t)!==Object.prototype)return t;let n=Object.keys(t);if(n.length!==Object.keys(e).length)return t;let s={};for(let a of n){if(!(a in e))return t;s[a]=sa(e[a],t[a])}return n.every(a=>s[a]===e[a])?e:s},Id=({staleTime:e=3e4,gcTime:t=3e5,retry:n=2,retryDelay:s=1e3,refetchOnWindowFocus:a=!1,refetchOnReconnect:o=!0}={})=>{let r=new Map,d=new Set,u=new Map,l=null,f=!1,m=h=>{for(let v of d)v(h)},g=h=>h.state,w=h=>!h.invalidated&&Date.now()-h.state.updatedAt.peek()<h.options.staleTime,y=h=>{h.invalidated=!0,h.state.isStale.value=!0},H=h=>{h.gcTimer&&clearTimeout(h.gcTimer),h.gcTimer=null},me=h=>{H(h),!h.observers&&Number.isFinite(h.options.gcTime)&&(h.gcTimer=setTimeout(()=>{!h.observers&&!h.promise&&(r.delete(h.hash),m({type:"gc",key:h.key}))},h.options.gcTime))},z=h=>{h.pollTimer&&clearTimeout(h.pollTimer),h.pollTimer=null},ue=h=>{z(h);let v=typeof h.options.refetchInterval=="function"?h.options.refetchInterval(h):h.options.refetchInterval;h.observers&&Number.isFinite(v)&&v>0&&(h.pollTimer=setTimeout(async()=>{qo()&&await he(h,{force:!0}).catch(()=>{}),ue(h)},v))},q=(h,v=ot(h.queryKey))=>{let $={staleTime:e,gcTime:t,retry:n,retryDelay:s,...h},k={hash:v,key:h.queryKey,queryFn:h.queryFn,options:$,tags:new Set(h.tags??[]),observers:0,invalidated:!0,promise:null,ctrl:null,version:0,gcTimer:null,pollTimer:null,state:{data:I(h.initialData),error:I(null),status:I(h.initialData===void 0?"idle":"success"),fetchStatus:I("idle"),updatedAt:I(h.initialData===void 0?0:Date.now()),isStale:I(!0)}};return r.set(v,k),k},J=h=>{if(!h?.queryKey)throw new TypeError("query: queryKey is required");let v=ot(h.queryKey),$=r.get(v)??q(h,v);h.queryFn&&($.queryFn=h.queryFn),$.options={...$.options,...h};for(let k of h.tags??[])$.tags.add(k);return $},he=(h,{force:v=!1}={})=>{if(!h.queryFn)return Promise.reject(new TypeError(`query ${h.hash} has no queryFn`));if(!v&&w(h))return Promise.resolve(h.state.data.peek());if(h.promise)return h.promise;if(!qo())return h.state.fetchStatus.value="paused",Promise.reject(new Error("Query paused while offline"));H(h);let $=++h.version,k=new AbortController;h.ctrl=k,xe(()=>{h.state.data.peek()===void 0&&(h.state.status.value="pending"),h.state.fetchStatus.value="fetching",h.state.error.value=null}),m({type:"fetch",key:h.key});let R=async(N,Q)=>{try{return await h.queryFn({queryKey:h.key,signal:k.signal,meta:h.options.meta})}catch(B){if(k.signal.aborted||B?.name==="AbortError"||N<=0||h.options.retry===!1)throw B;return await Ld(typeof Q=="function"?Q(N,B):Q),R(N-1,typeof Q=="number"?Q*2:Q)}},Z=R(h.options.retry??n,h.options.retryDelay??s).then(N=>(h.version===$&&!k.signal.aborted&&xe(()=>{h.state.data.value=h.options.structuralSharing===!1?N:sa(h.state.data.peek(),N),h.state.status.value="success",h.state.fetchStatus.value="idle",h.state.updatedAt.value=Date.now(),h.state.isStale.value=!1,h.invalidated=!1}),m({type:"success",key:h.key}),N)).catch(N=>{throw h.version===$&&!k.signal.aborted&&xe(()=>{h.state.error.value=N,h.state.status.value=h.state.data.peek()===void 0?"error":"success",h.state.fetchStatus.value="idle"}),k.signal.aborted||m({type:"error",key:h.key,error:N}),N}).finally(()=>{h.promise===Z&&(h.promise=null,h.ctrl=null,me(h))});return h.promise=Z,Z},Ae=h=>Promise.all([...r.values()].filter(v=>ds(v,h)&&v.observers).map(v=>he(v,{force:!0}).catch(()=>{}))),L={query(h){let v=J(h);v.observers++,H(v),ue(v),h.enabled!==!1&&(!w(v)||h.refetchOnMount)&&he(v).catch(()=>{});let $=()=>{v.observers=Math.max(0,v.observers-1),me(v),ue(v)};return[g(v),{refetch:()=>he(v,{force:!0}),invalidate:()=>L.invalidateQueries({queryKey:v.key,exact:!0}),setData:k=>L.setQueryData(v.key,k),cancel:()=>L.cancelQueries({queryKey:v.key,exact:!0}),dispose:$}]},prefetchQuery(h){let v=J(h);return he(v)},fetchQuery(h){let v=J(h);return he(v)},getQueryData(h){return r.get(ot(h))?.state.data.peek()},getQueryState(h){let v=r.get(ot(h));return v&&g(v)},setQueryData(h,v,{tags:$}={}){let k=r.get(ot(h))??J({queryKey:h,tags:$}),R=typeof v=="function"?v(k.state.data.peek()):v,Z=k.options.structuralSharing===!1?R:sa(k.state.data.peek(),R);xe(()=>{k.state.data.value=Z,k.state.status.value="success",k.state.error.value=null,k.state.updatedAt.value=Date.now(),k.state.isStale.value=!1}),k.invalidated=!1;for(let N of $??[])k.tags.add(N);return m({type:"set",key:k.key}),l&&l.postMessage({type:"invalidate",hash:k.hash}),Z},invalidateQueries(h){for(let v of r.values())ds(v,h)&&y(v);return m({type:"invalidate",filter:h}),l&&l.postMessage({type:"invalidate",filter:h}),Ae(h)},cancelQueries(h){for(let v of r.values())ds(v,h)&&v.ctrl?.abort()},removeQueries(h){for(let v of[...r.values()])ds(v,h)&&(v.ctrl?.abort(),H(v),z(v),r.delete(v.hash))},mutate({mutationFn:h,variables:v,optimistic:$,invalidate:k,onMutate:R,onSuccess:Z,onError:N,networkMode:Q="online"}={}){if(typeof h!="function")return Promise.reject(new TypeError("mutate: mutationFn is required"));let B=[],ve=A=>(Array.isArray(A)?A:[A]).filter(Boolean).forEach(ce=>{let Wt=L.getQueryData(ce.queryKey);B.push([ce.queryKey,Wt]),L.setQueryData(ce.queryKey,Ln=>ce.updater(Ln))}),Ke=async()=>{let A=await R?.(v,{client:L});$&&ve(typeof $=="function"?$(v):$);try{let ce=await h(v);return await Z?.(ce,v,A),k&&await L.invalidateQueries(k),m({type:"mutation-success"}),ce}catch(ce){for(let[Wt,Ln]of B)L.setQueryData(Wt,Ln);throw await N?.(ce,v,A),m({type:"mutation-error",error:ce}),ce}};return!qo()&&Q==="offlineFirst"?(ge.push(Ke),m({type:"mutation-queued"}),Promise.resolve({queued:!0})):Ke()},infiniteQuery({queryKey:h,queryFn:v,initialPageParam:$=0,getNextPageParam:k,...R}){let[Z,N]=L.query({queryKey:h,...R,queryFn:async Q=>({pages:[await v({...Q,pageParam:$})],pageParams:[$]})});return[Z,{...N,fetchNextPage:async()=>{let Q=Z.data.peek()??{pages:[],pageParams:[]},B=k?.(Q.pages.at(-1),Q.pages);if(B==null)return;let ve=await v({queryKey:h,pageParam:B,signal:new AbortController().signal});return L.setQueryData(h,{pages:[...Q.pages,ve],pageParams:[...Q.pageParams,B]}),ve}}]},dehydrate({shouldDehydrate:h=$=>$.state.status.peek()==="success",version:v=1}={}){return{version:v,timestamp:Date.now(),queries:[...r.values()].filter(h).filter($=>Ed($.state.data.peek())).map($=>({key:$.key,data:$.state.data.peek(),updatedAt:$.state.updatedAt.peek(),staleTime:$.options.staleTime,tags:[...$.tags]}))}},hydrate(h,{version:v=1}={}){if(!h||h.version!==v||!Array.isArray(h.queries))return!1;for(let $ of h.queries){let k=r.get(ot($.key))??J({queryKey:$.key,staleTime:$.staleTime,tags:$.tags});xe(()=>{k.state.data.value=$.data,k.state.status.value="success",k.state.updatedAt.value=$.updatedAt,k.state.isStale.value=Date.now()-$.updatedAt>=k.options.staleTime}),k.invalidated=k.state.isStale.peek()}return m({type:"hydrate"}),!0},persist({storage:h=typeof localStorage>"u"?null:localStorage,key:v="mini-react-query",version:$=1}={}){if(!h)throw new Error("persist: a storage adapter is required");let k=!1,R=async()=>{let N=JSON.stringify(L.dehydrate({version:$}));return h.set?h.set(v,N):h.setItem(v,N)},Z=L.subscribe(()=>{k||(k=!0,queueMicrotask(()=>{k=!1,R().catch(()=>{})}))});return{restore:async()=>{let N=await(h.get?h.get(v):h.getItem(v));return N?L.hydrate(JSON.parse(N),{version:$}):!1},save:R,dispose:Z}},sync(h="mini-react-query"){return typeof BroadcastChannel>"u"?()=>{}:(l?.close(),l=new BroadcastChannel(h),l.onmessage=v=>{if(v.data?.type!=="invalidate")return;let $=v.data.hash?k=>k.hash===v.data.hash:v.data.filter;for(let k of r.values())ds(k,$)&&y(k);Ae($)},()=>{l?.close(),l=null})},subscribe(h){return d.add(h),()=>d.delete(h)},getDebugSnapshot(){return[...r.values()].map(h=>({key:h.key,observers:h.observers,status:h.state.status.peek(),fetchStatus:h.state.fetchStatus.peek(),updatedAt:h.state.updatedAt.peek(),stale:h.state.isStale.peek(),tags:[...h.tags]}))},async fetchJSON(h,v={},{queryKey:$=["GET",h,v.body??null],...k}={}){let R=ot($);return L.fetchQuery({queryKey:$,...k,queryFn:async({signal:Z})=>{let N=new Headers(v.headers),Q=u.get(R);Q?.etag&&N.set("If-None-Match",Q.etag);let B=await fetch(h,{...v,headers:N,signal:Z});if(B.status===304&&Q)return L.getQueryData($);if(!B.ok)throw new Error(`HTTP ${B.status}`);let ve=B.headers.get("cache-control")?.match(/max-age=(\d+)/)?.[1];if(ve){let Ke=r.get(R);Ke&&(Ke.options.staleTime=Number(ve)*1e3)}return u.set(R,{etag:B.headers.get("etag")}),B.json()}})},destroy(){f=!0;for(let h of r.values())h.ctrl?.abort(),H(h),z(h);l?.close(),d.clear()}},ge=[],be=()=>{a&&Ae()},ae=()=>{for(o&&Ae();ge.length;)ge.shift()().catch(()=>{})};typeof window<"u"&&(window.addEventListener("focus",be),window.addEventListener("online",ae));let Ft=L.destroy;return L.destroy=()=>{f||(typeof window<"u"&&(window.removeEventListener("focus",be),window.removeEventListener("online",ae)),Ft())},L},Hf=Id(),aa=({cache:e=!0,ttl:t=3e4,retry:n=2,retryDelay:s=1e3,store:a=null,dedupe:o=!0}={})=>{let r=new Map,d=new Map,u=new Map,l=(m,g)=>{if(a)return a.get(m);let w=r.get(m);return w&&Date.now()-w.ts<g?w.data:void 0},f=async(m,g,w)=>{if(a)return a.set(m,g,{ttl:w});r.set(m,{data:g,ts:Date.now()})};return{get:(m,g,w={})=>{let y=w.ttl??t,H=e&&w.cache!==!1&&y!==0,me=w.dedupe??o;if(me&&d.has(m))return d.get(m);let z=()=>{let q=u.get(m)??0,J=(he,Ae)=>Promise.resolve(g()).then(async L=>(H&&(u.get(m)??0)===q&&await f(m,L,y),L)).catch(L=>{if(he>0&&L?.name!=="AbortError")return new Promise(ge=>setTimeout(ge,Ae)).then(()=>J(he-1,Ae*2));throw L});return J(w.retry??n,s)},ue=q=>(me&&(d.set(m,q),q.finally(()=>{d.get(m)===q&&d.delete(m)}).catch(()=>{})),q);if(!H)return ue(z());if(!a){let q=l(m,y);return q!==void 0?Promise.resolve(q):ue(z())}return ue(Promise.resolve(l(m,y)).then(q=>q!==void 0?q:z()))},invalidate:m=>{if(m!==void 0)u.set(m,(u.get(m)??0)+1);else{for(let g of r.keys())u.set(g,(u.get(g)??0)+1);for(let g of d.keys())u.set(g,(u.get(g)??0)+1)}if(a)return m===void 0?a.clear():a.delete(m);m===void 0?r.clear():r.delete(m)}}},qf=new TextEncoder,Rf=new TextDecoder,Si=(e,t="kv")=>{let n=null,s=()=>n?Promise.resolve(n):new Promise((o,r)=>{let d=indexedDB.open(e,1);d.onupgradeneeded=u=>u.target.result.createObjectStore(t),d.onsuccess=u=>{n=u.target.result,o(n)},d.onerror=u=>r(u.target.error)}),a=async(o,r)=>{let d=await s();return new Promise((u,l)=>{let f=d.transaction(t,o),m=r(f.objectStore(t));m.onsuccess=()=>u(m.result),m.onerror=()=>l(m.error)})};return{async get(o){let r=await a("readonly",d=>d.get(o));if(r){if(r.expires&&Date.now()>r.expires){this.delete(o);return}return r.val}},async set(o,r,{ttl:d}={}){await a("readwrite",u=>u.put({val:r,expires:d?Date.now()+d:null},o))},delete:o=>a("readwrite",r=>r.delete(o)),clear:()=>a("readwrite",o=>o.clear()),keys:()=>a("readonly",o=>o.getAllKeys())}}});var W=U(()=>{Li()});var _i={};ls(_i,{AGENT_DEFAULT_MODEL:()=>Ai,AGENT_LABELS:()=>X,AGENT_MODELS:()=>Uo,LOW_TURN_THRESHOLD:()=>Wo,activityHits:()=>rt,activityLoading:()=>gt,addCustomModel:()=>Jt,agentFilter:()=>ye,agentFilters:()=>zt,agentsMeta:()=>Kt,chatDensity:()=>_e,collapsedFolders:()=>Mn,ctx:()=>c,currentAgent:()=>S,currentEffort:()=>te,currentModel:()=>_,currentPermission:()=>de,currentProject:()=>E,currentTab:()=>Y,expandedFolders:()=>Cn,favoritesOnly:()=>ze,filesPath:()=>V,filesRoot:()=>re,filteredSessions:()=>Dt,getCustomModels:()=>ra,getDefaultEffort:()=>Qe,getDefaultModel:()=>Oe,getEffortsForModel:()=>Qt,getModelsForAgent:()=>Be,getSavedModel:()=>Mi,getSessionMeta:()=>An,gitRoot:()=>Se,hubMachineReady:()=>it,hubMode:()=>M,isProcessing:()=>D,machinesList:()=>ie,metaKey:()=>K,projectGroups:()=>Vt,removeCustomModel:()=>zo,selectedMachineId:()=>j,sessionDisplayTitle:()=>bt,sessionFilter:()=>ke,sessionMetaMap:()=>T,sessionSearch:()=>$e,sessionSort:()=>Ei,sessionsData:()=>ne,setAgent:()=>Ne,setChatDensity:()=>Go,setCurrentModel:()=>se,setSelectedMachine:()=>Le,showHiddenOnly:()=>Je,sidebarView:()=>ht,timeRange:()=>oa,viewingFile:()=>oe,workspacesData:()=>pe,wsStatus:()=>fe});function Ti(){try{let e=JSON.parse(localStorage.getItem(Ii)||"{}");return e&&typeof e=="object"?e:{}}catch{return{}}}function Ci(e,t=c.sessionId,n=c.machineId){if(!t)return"";let s=(e||"claude").toLowerCase();return`${n||""}:${s}:${t}`}function Mi(e,t=c.sessionId,n=c.machineId){let s=Ci(e,t,n);if(!s)return null;let a=Ti()[s];return typeof a=="string"&&a.trim()?a:null}function se(e,t=S.peek(),n=c.sessionId,s=c.machineId){let a=String(e||"").trim();if(!a)return;let o=Ci(t,n,s);if(o){let r=Ti();r[o]=a,localStorage.setItem(Ii,JSON.stringify(r))}_.value=a}function Le(e){let t=e||null;j.value=t,c.machineId=t,t?localStorage.setItem("machineId",t):localStorage.removeItem("machineId")}function K(e,t,n){let s=`${e||"claude"}:${t}`;return n||c?.machineId?`${n||c.machineId}:${s}`:s}function An(e,t,n){return T.peek()?.[K(e,t,n)]||{favorite:!1,notes:"",title:"",hidden:!1,branch:null}}function bt(e,{preferSnippet:t=!1}={}){if(!e)return"Session";if(t&&e.snippet)return e.snippet;let s=(An(e.agent,e.sessionId,e.machineId).title||"").trim();return s||e.display||e.sessionId?.slice(0,8)||"Session"}function Go(e){let t=["clean","normal","full"].includes(e)?e:"normal";_e.value=t,localStorage.setItem("chatDensity",t),document.getElementById("messages")?.setAttribute("data-density",t)}function Cd(e){return e?typeof e=="string"?{value:e,label:e}:e.value?{value:String(e.value),label:e.label||e.value,...Array.isArray(e.efforts)&&e.efforts.length?{efforts:e.efforts.map(String)}:{},...e.defaultEffort?{defaultEffort:String(e.defaultEffort)}:{}}:null:null}function Ko(){try{let e=localStorage.getItem(ji);if(!e)return{};let t=JSON.parse(e);return t&&typeof t=="object"?t:{}}catch{return{}}}function Di(e){localStorage.setItem(ji,JSON.stringify(e))}function ra(e){let t=(e||"claude").toLowerCase(),n=Ko()[t];return Array.isArray(n)?n.filter(Boolean).map(String):[]}function Jt(e,t){let n=(e||"claude").toLowerCase(),s=String(t||"").trim();if(!s)return!1;let a=Ko(),o=Array.isArray(a[n])?[...a[n]]:[];return o.includes(s)||o.push(s),a[n]=o,Di(a),!0}function zo(e,t){let n=(e||"claude").toLowerCase(),s=String(t||"").trim(),a=Ko(),o=Array.isArray(a[n])?a[n].filter(r=>r!==s):[];return a[n]=o,Di(a),!0}function Be(e){let t=(e||"claude").toLowerCase(),n=Kt.peek()?.defaults?.[t],s=n?.models?.length?n.models.map(Cd).filter(Boolean):(Uo[t]||Uo.claude).map(r=>({...r})),a=ra(t),o=new Set(s.map(r=>r.value));for(let r of a){if(o.has(r)){s=s.map(d=>{if(d.value!==r)return d;let u=String(d.label||d.value);return{...d,custom:!0,label:u.includes("\u2605")?u:`${u} \u2605`}});continue}o.add(r),s.push({value:r,label:`${r} \u2605`,custom:!0})}return s}function Oe(e){let t=(e||"claude").toLowerCase(),n=Kt.peek()?.defaults?.[t];return n?.model?String(n.model):Ai[t]||Be(t)[0]?.value||"sonnet"}function Qt(e,t){let s=Be(e).find(o=>o.value===t);if(s?.efforts?.length)return s.efforts;let a=Kt.peek()?.defaults?.[(e||"claude").toLowerCase()];return a?.efforts?.length?a.efforts.map(String):["low","medium","high","xhigh","max"]}function Qe(e,t){let n=(e||"claude").toLowerCase(),s=Kt.peek()?.defaults?.[n];if(s?.effortDefault)return String(s.effortDefault);let o=Be(n).find(r=>r.value===t);return o?.defaultEffort?String(o.defaultEffort):n==="grok"?"low":n==="gemini"&&String(t||"").match(/-(low|medium|high)$/i)?.[1]?.toLowerCase()||""}function Ne(e){let t=(e||"claude").toLowerCase();S.value=t,localStorage.setItem("agent",t),de.value="bypassPermissions";let n=typeof document>"u"?null:document.getElementById("sel-permission");n&&(n.value=de.peek());let s=Mi(t);s?_.value=s:se(Oe(t),t);let a=Qe(t,_.peek());a?te.value=a:t!=="grok"&&t!=="gemini"&&(te.value="")}function Md(e,t){return!t||t==="all"?!0:(e.agent||"claude")===t}function Ad(e,t){if(!t)return!0;let n=T.value?.[K(e.agent,e.sessionId,e.machineId)];return[e.display,e.cwd,e.projectName,e.agent,e.sessionId,e.snippet,e.machineId,n?.notes,n?.title].filter(Boolean).join(" ").toLowerCase().includes(t)}function Fo(e){return Array.isArray(e)?e:e&&Array.isArray(e.results)?e.results:e&&Array.isArray(e.sessions)?e.sessions:[]}var ne,pe,ke,$e,Ei,Cn,Mn,V,oe,E,Y,D,fe,Ii,Td,S,_,te,de,re,Se,Kt,ht,ye,zt,oa,rt,gt,T,ze,Je,Wo,_e,M,ie,j,it,c,X,Uo,Ai,ji,Dt,Vt,F=U(()=>{W();ne=I([]),pe=I([]),ke=I(null),$e=I(""),Ei=I("time"),Cn=I(new Set),Mn=I(new Set),V=I(""),oe=I(null),E=I(null),Y=I("chat"),D=I(!1),fe=I("idle"),Ii="modelBySession",Td=localStorage.getItem("agent")||"claude";S=I(Td),_=I("sonnet"),te=I(""),de=I("bypassPermissions"),re=I(""),Se=I(""),Kt=I(null),ht=I(localStorage.getItem("sidebarView")||"projects"),ye=I(localStorage.getItem("agentFilter")||"all"),zt=I((()=>{try{let e=JSON.parse(localStorage.getItem("agentFilters")||"[]");return Array.isArray(e)?e.filter(Boolean):[]}catch{return[]}})()),oa=I(localStorage.getItem("timeRange")||"14"),rt=I(null),gt=I(!1),T=I({}),ze=I(localStorage.getItem("favoritesOnly")==="1"),Je=I(localStorage.getItem("showHiddenOnly")==="1"),Wo=2,_e=I(localStorage.getItem("chatDensity")||"normal"),M=I(!1),ie=I([]),j=I(null),it=I(!1),c={token:localStorage.getItem("token"),sessionId:null,agent:null,machineId:null,ws:null,shellBubble:null,configDir:null,externalSessionReadOnly:!1,role:null,username:null,lock:{key:null,token:null,holder:null,held:!1,foreign:!1}};X={claude:"Claude",codex:"Codex",grok:"Grok",gemini:"Gemini",cursor:"Cursor"},Uo={claude:[{value:"fable",label:"fable"},{value:"opus",label:"opus"},{value:"sonnet",label:"sonnet"},{value:"haiku",label:"haiku"}],codex:[{value:"gpt-5.4",label:"gpt-5.4"},{value:"gpt-5.3",label:"gpt-5.3"},{value:"gpt-5.2",label:"gpt-5.2"},{value:"o3",label:"o3"},{value:"o4-mini",label:"o4-mini"},{value:"codex-mini-latest",label:"codex-mini"}],grok:[{value:"grok-4.5",label:"grok-4.5"},{value:"grok-4",label:"grok-4"},{value:"grok-3",label:"grok-3"},{value:"grok-3-mini",label:"grok-3-mini"}],gemini:[{value:"gemini-3.7-flash-high",label:"Gemini 3.7 Flash (High)"},{value:"gemini-3.7-flash-medium",label:"Gemini 3.7 Flash (Medium)"},{value:"gemini-3.7-flash-low",label:"Gemini 3.7 Flash (Low)"},{value:"gemini-3.6-flash-high",label:"Gemini 3.6 Flash (High)"},{value:"gemini-3.6-flash-medium",label:"Gemini 3.6 Flash (Medium)"},{value:"gemini-3.6-flash-low",label:"Gemini 3.6 Flash (Low)"},{value:"gemini-3.5-flash-high",label:"Gemini 3.5 Flash (High)"},{value:"gemini-3.5-flash-medium",label:"Gemini 3.5 Flash (Medium)"},{value:"gemini-3.5-flash-low",label:"Gemini 3.5 Flash (Low)"},{value:"gemini-3.1-pro-high",label:"Gemini 3.1 Pro (High)"},{value:"gemini-3.1-pro-low",label:"Gemini 3.1 Pro (Low)"}],cursor:[{value:"auto",label:"Auto"},{value:"gpt-5.3-codex",label:"GPT-5.3 Codex"},{value:"composer-2.5",label:"Composer 2.5"}]},Ai={claude:"sonnet",codex:"gpt-5.4",grok:"grok-4.5",gemini:"gemini-3.7-flash-high",cursor:"auto"};ji="customModelsByAgent";Dt=Oo(()=>{let e=$e.value.toLowerCase().trim(),t=Ei.value,n=ye.value,s=zt.value,a=ze.value,o=Je.value,r=T.value,d=rt.value,u=d?.results?.length&&e?Fo(d.results):Fo(ne.value),l=j.value;return M.value&&l&&(u=u.filter(f=>f&&(!f.machineId||f.machineId===l))),u=u.filter(f=>f&&(s.length?s.includes(f.agent||"claude"):Md(f,n))),o?u=u.filter(f=>f&&r?.[K(f.agent,f.sessionId,f.machineId)]?.hidden):u=u.filter(f=>f&&!r?.[K(f.agent,f.sessionId,f.machineId)]?.hidden),a&&(u=u.filter(f=>f&&r?.[K(f.agent,f.sessionId,f.machineId)]?.favorite)),e&&!(d?.results&&d.q===e)&&(u=u.filter(f=>f&&Ad(f,e))),u=[...u].sort((f,m)=>{let g=r?.[K(f.agent,f.sessionId,f.machineId)]?.favorite?1:0,w=r?.[K(m.agent,m.sessionId,m.machineId)]?.favorite?1:0;return g!==w?w-g:t==="project"&&(f.cwd||"").localeCompare(m.cwd||"")||m.updatedAt-f.updatedAt}),!e&&!a?u.slice(0,120):u}),Vt=Oo(()=>{let e=Fo(Dt.value),t=new Map;for(let n of e){if(!n)continue;let s=n.machineId?`${n.machineId}::${n.cwd||"(no path)"}`:n.cwd||"(no path)";t.has(s)||t.set(s,{cwd:n.cwd||null,machineId:n.machineId||null,projectName:n.projectName||(n.cwd?n.cwd.split("/").filter(Boolean).pop():"(no path)"),updatedAt:0,agents:{},sessions:[],latest:null});let a=t.get(s);a.sessions.push(n),a.agents[n.agent||"claude"]=(a.agents[n.agent||"claude"]||0)+1,(n.updatedAt||0)>a.updatedAt&&(a.updatedAt=n.updatedAt,a.latest=n)}return[...t.values()].sort((n,s)=>s.updatedAt-n.updatedAt)})});function ps(e={}){return e.machineId!==void 0?e.machineId:c.machineId||j.peek()||null}function _d(e){let t=e.split("?")[0];return t==="/api/hub"||t==="/api/machines"||t==="/api/notifications"||t==="/api/notifications/read"||t==="/api/notes"||t.startsWith("/api/notes/")||t==="/api/queue"||t.startsWith("/api/queue/")||t.startsWith("/api/ai/")||t.startsWith("/api/auth/")||t.startsWith("/api/collab/")}async function x(e,t,n,s,a={}){let o=a.hub?null:ps(a),r={"Content-Type":"application/json",...c.token?{Authorization:`Bearer ${c.token}`}:{}};!a.hub&&M.peek()&&o&&!_d(t)&&(r["X-Machine-Id"]=o),e.toUpperCase()!=="GET"&&e.toUpperCase()!=="HEAD"&&c.lock?.token&&c.lock?.key&&!String(t).startsWith("/api/collab/")&&(r["X-Lock-Token"]=c.lock.token,r["X-Lock-Key"]=c.lock.key);let u=a.etag===!0?`${c.token||""}:${o||""}:${t}`:a.etag||null;if(e.toUpperCase()==="GET"&&u){let m=Pi.get(u);m&&(r["If-None-Match"]=m)}let l=async()=>{let m=await fetch(t,{method:e,signal:s,headers:r,cache:a.cache||(e.toUpperCase()==="GET"?"no-store":"default"),...n!==void 0?{body:JSON.stringify(n)}:{}});if(m.status===304)return Dd;let g=await m.json().catch(()=>({}));if(!m.ok)throw new Error(g.error||`HTTP ${m.status}`);if(u){let w=m.headers.get("ETag");w&&Pi.set(u,w)}return g};if(e.toUpperCase()!=="GET"||s||a.dedupe===!1)return l();let f=`${c.token||""}:${o||""}:${t}`;return jd.get(f,l)}function lt(e){return c.ws?.readyState===WebSocket.OPEN?(c.ws.send(JSON.stringify(e)),!0):(e?.type==="ping"||e?.type==="pong"||e?.type==="subscribe"||ia.push(e),!1)}function la(){for(;ia.length&&c.ws?.readyState===WebSocket.OPEN;)c.ws.send(JSON.stringify(ia.shift()))}function ca(){ia.length=0}function Jo(e={}){let t=new URLSearchParams(e);c.token&&t.set("token",c.token);let n=ps();return M.peek()&&n&&t.set("machine",n),t.toString()}function ct(e={},t={}){let n={...e};c.token&&(n.Authorization=`Bearer ${c.token}`);let s=ps();return!t.hub&&M.peek()&&s&&(n["X-Machine-Id"]=s),n}async function da(){try{let e=await fetch("/api/hub");if(!e.ok)return M.value=!1,!1;let t=await e.json();if(t?.hub)return M.value=!0,t}catch{}return M.value=!1,!1}var jd,Pi,Dd,ia,le=U(()=>{F();W();jd=aa({cache:!1,dedupe:!0,retry:0}),Pi=new Map,Dd=Symbol("not-modified");ia=[]});function Yt(e,t){e&&(t?e.setAttribute("inert",""):e.removeAttribute("inert"))}function jn(e){return!e||e.classList.contains("hidden")?!0:e.style.display==="none"}function Ee(){let e=typeof window<"u"&&window.matchMedia("(max-width: 640px)").matches,t=document.getElementById("sidebar");if(t){let s=!e||t.classList.contains("open");Yt(t,!s)}Yt(document.getElementById("welcome"),jn(document.getElementById("welcome"))),Yt(document.getElementById("auth-screen"),jn(document.getElementById("auth-screen"))),Yt(document.getElementById("chat-opts"),jn(document.getElementById("chat-opts"))),Yt(document.getElementById("machine-picker"),jn(document.getElementById("machine-picker")));for(let s of["files","git","shell","memory"]){let a=document.getElementById(`tab-${s}`);Yt(a,jn(a))}let n=document.getElementById("tab-chat");n&&Yt(n,jn(n))}function fs(){let e=window.visualViewport,t=document.documentElement;if(!e)return;let n=e.height<window.innerHeight-80;t.classList.toggle("vv-keyboard",n),t.style.setProperty("--vvh",`${Math.round(e.height)}px`),t.style.setProperty("--vv-top",`${Math.round(e.offsetTop)}px`)}function qi(){Ee(),fs();let e=window.visualViewport;e&&(e.addEventListener("resize",fs),e.addEventListener("scroll",fs)),window.addEventListener("resize",()=>{fs(),Ee()}),window.addEventListener("orientationchange",()=>{setTimeout(()=>{fs(),Ee()},250)})}var Dn=U(()=>{});function Xt(){try{let e=localStorage.getItem(Ri);return e?JSON.parse(e):null}catch{return null}}function Qo(e){try{let n={...Xt()||{},...e,updatedAt:Date.now()};localStorage.setItem(Ri,JSON.stringify(n))}catch{}}var Ri,pa=U(()=>{Ri="lastSessionContext"});function Nd(e){let t=String(e??"").trim();if(!t)return"";try{return decodeURIComponent(t)}catch{return t}}function Bi(e){return String(e||"").replace(/\\/g,"/")}function Pd(e){return e.replace(/:[0-9]+(?::[0-9]+)?$/,"")}function fa(e,t){let n=Nd(e);if(!n||/^(https?:|mailto:|tel:|javascript:|#)/i.test(n)||(n=Bi(n).split(/[?#]/)[0],n=n.replace(/^file:\/\//i,""),/^\/[A-Za-z]:\//.test(n)&&(n=n.slice(1)),!n||n==="."||n==="/")||/^\/(api|ws|session)\b/.test(n))return null;let s=n.endsWith("/"),a=Pd(n.replace(/\/+$/,"")),o=Bi(t).replace(/\/+$/,"");if((a.startsWith("/")||/^[A-Za-z]:\//.test(a))&&o){let d=a.toLowerCase(),u=o.toLowerCase();if(d===u)return{relative:"",isDir:!0,root:o};if(d.startsWith(`${u}/`))return{relative:a.slice(o.length+1),isDir:s,root:o};let l=a.split("/"),f=l.pop()||"",m=l.join("/")||(a.startsWith("/")?"/":"");return{relative:f,isDir:s,root:m}}if(a=a.replace(/^\.\//,""),a.startsWith("../")&&o){let d=o.split("/"),u=a.split("/");for(let f of u)f===".."?d.pop():f&&f!=="."&&d.push(f);let l=d.join("/")||"/";return fa(l,t)}return{relative:a,isDir:s,root:o||t}}var Vo=U(()=>{});function qd(){let e=document.getElementById("mermaid-zoom-overlay");if(e)return e;e=document.createElement("div"),e.id="mermaid-zoom-overlay",e.className="mermaid-zoom-overlay hidden",e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true"),e.setAttribute("aria-label","Mermaid diagram enlarged"),e.innerHTML='<button type="button" class="mermaid-zoom-close" aria-label="\u5173\u95ED\u653E\u5927\u56FE">\xD7</button><div class="mermaid-zoom-canvas"></div>',document.body.appendChild(e);let t=()=>e.classList.add("hidden");return e.addEventListener("click",n=>{(n.target===e||n.target.closest(".mermaid-zoom-close"))&&t()}),Ui||(Ui=!0,document.addEventListener("keydown",n=>{n.key==="Escape"&&t()})),e}function Fi(e){let t=e.querySelector("svg");if(!t)return;let n=qd(),s=n.querySelector(".mermaid-zoom-canvas");s.innerHTML=t.outerHTML;let a=s.querySelector("svg");a?.removeAttribute("width"),a?.removeAttribute("height"),n.classList.remove("hidden")}function Rd(){let e=globalThis.mermaid;return!e||Oi||(e.initialize({startOnLoad:!1,securityLevel:"strict",theme:document.documentElement.dataset.theme==="dark"?"dark":"default",flowchart:{htmlLabels:!1}}),Oi=!0),e}function Bd(e){let t=String(e||"").replace(/\r\n?/g,`
|
|
2
|
+
`).trim();return t=t.replace(/^```(?:mermaid)?\s*/i,"").replace(/\s*```$/,"").trim(),t=t.replace(/^mermaid\s*\n/i,""),t=t.replace(/^graph\s+(TD|TB|BT|RL|LR)\b/i,"flowchart $1"),t}function vt(e){let t=Rd();!t||!e||e.querySelectorAll("pre code.language-mermaid, pre code.lang-mermaid").forEach(n=>{if(n.dataset.mermaidHandled)return;let s=n.closest("pre"),a=Bd(n.textContent);if(!s||!a)return;n.dataset.mermaidHandled="1";let o=document.createElement("div");o.className="mermaid-diagram",o.setAttribute("role","img"),o.setAttribute("aria-label","Mermaid diagram"),s.replaceWith(o);let r=`mermaid-diagram-${++Hd}`;Promise.resolve(t.parse(a)).then(()=>t.render(r,a)).then(({svg:d,bindFunctions:u})=>{o.innerHTML=d,u?.(o),o.tabIndex=0,o.title="\u70B9\u51FB\u653E\u5927\u56FE\u8868",o.addEventListener("click",l=>{l.target.closest("a")||Fi(o)}),o.addEventListener("keydown",l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),Fi(o))})}).catch(d=>{o.replaceWith(s),delete n.dataset.mermaidHandled,s.classList.add("mermaid-error"),s.title=`Mermaid render failed: ${d?.message||"invalid diagram"}`})})}var Oi,Hd,Ui,_n=U(()=>{Oi=!1,Hd=0,Ui=!1});function Xo(e){return Od.test(String(e||""))}function Ud(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function Wi(e,t){return t===0||e[t-1]===`
|
|
3
|
+
`}function Fd(e,t){if(Wi(e,t)&&(e.startsWith("```",t)||e.startsWith("~~~",t))){let n=e.startsWith("```",t)?"```":"~~~",s=e.indexOf(`
|
|
4
|
+
`+n,t+3);return s===-1?{end:e.length}:{end:s+1+n.length}}if(e[t]==="`"){let n=1;for(;e[t+n]==="`";)n++;let s=t+n;for(;s<e.length;){if(e[s]==="`"){let a=0;for(;e[s+a]==="`";)a++;if(a===n)return{end:s+a};s+=a;continue}s++}return{end:t+n}}return null}function Wd(e,t){let n=e.slice(t);if(n.startsWith("$$")){let s=n.indexOf("$$",2);if(s>=2){let a=n.slice(2,s);if(a.trim())return{body:a,display:!0,end:t+s+2}}}if(n.startsWith("\\[")){let s=n.indexOf("\\]",2);if(s>=2){let a=n.slice(2,s);if(a.trim())return{body:a,display:!0,end:t+s+2}}}if(n.startsWith("\\(")){let s=n.indexOf("\\)",2);if(s>=2){let a=n.slice(2,s);if(a.trim())return{body:a,display:!1,end:t+s+2}}}if(n[0]==="$"&&n[1]!=="$"){let s=n.match(/^\$([^$\n]|\\\$)+?(?<!\s)\$/);if(s&&s[0][1]!==" "){let a=s[0].slice(1,-1);if(a.trim())return{body:a,display:!1,end:t+s[0].length}}}if(Wi(e,t)){let s=n.match(/^[ \t]*\[[ \t]*\n([\s\S]*?)\n[ \t]*\][ \t]*(?=\n|$)/);if(s&&Xo(s[1]))return{body:s[1],display:!0,end:t+s[0].length};let a=n.match(/^[ \t]*\[([^\]\n]+)\](?!\()/);if(a&&Xo(a[1]))return{body:a[1],display:!0,end:t+a[0].length}}return null}function Gi(e){let t=[],n=String(e??""),s="",a=0;for(;a<n.length;){let o=Fd(n,a);if(o){s+=n.slice(a,o.end),a=o.end;continue}let r=Wd(n,a);if(r){let d=t.length;t.push({body:r.body,display:r.display}),s+=`@@MATH${d}@@`,a=r.end;continue}s+=n[a],a++}return{text:s,slots:t}}function ma(e,t){return t?.length?String(e).replace(/@@MATH(\d+)@@/g,(n,s)=>{let a=t[Number(s)];if(!a)return n;let o=a.display?"\\[":"\\(",r=a.display?"\\]":"\\)";return Ud(`${o}${a.body}${r}`)}):e}function Gd(e){return e.parentElement?.closest("pre, code, .mermaid-diagram, .katex, script, style")}function Yo(e,t){let n=[{re:/\\\[([\s\S]+?)\\\]/g,display:!0},{re:/\$\$([\s\S]+?)\$\$/g,display:!0},{re:/\\\(([\s\S]+?)\\\)/g,display:!1},{re:/(?<!\\)\$([^$\n]|\\\$)+?(?<!\s)(?<!\\)\$/g,display:!1},{re:/(?:^|\n)[ \t]*\[[ \t]*\n([\s\S]*?)\n[ \t]*\][ \t]*(?=\n|$)/g,display:!0,latex:!0},{re:/(?:^|\n)[ \t]*\[([^\]\n]+\\[a-zA-Z{}_^][^\]\n]*)\](?!\()/g,display:!0,latex:!0}],s=null;for(let a of n){a.re.lastIndex=t;let o=a.re.exec(e);if(!o||s&&o.index>=s.match.index)continue;let r=o[0],d;o[1]!=null&&(a.latex||r.startsWith("\\[")||r.startsWith("\\(")||r.startsWith("$$")||r.startsWith("$"))?d=o[1]:d=r.startsWith("\\[")||r.startsWith("\\(")||r.startsWith("$$")?r.slice(2,-2):r.slice(1,-1),d.trim()&&(a.latex&&!Xo(d)||(s={match:o,body:d,display:a.display}))}return s}function Kd(e){let t=e.nodeValue||"",n=0,s=Yo(t,n);if(!s||typeof globalThis.katex?.renderToString!="function")return;let a=document.createDocumentFragment();for(;s;){s.match.index>n&&a.append(document.createTextNode(t.slice(n,s.match.index)));let o;try{o=globalThis.katex.renderToString(s.body.trim(),{displayMode:s.display,throwOnError:!1,strict:"warn"})}catch{a.append(document.createTextNode(s.match[0])),n=s.match.index+s.match[0].length,s=Yo(t,n);continue}let r=document.createElement(s.display?"div":"span");r.className=s.display?"math-display":"math-inline",r.innerHTML=o,a.append(r),n=s.match.index+s.match[0].length,s=Yo(t,n)}n<t.length&&a.append(document.createTextNode(t.slice(n))),e.replaceWith(a)}function xt(e){if(!e||typeof globalThis.katex?.renderToString!="function")return;let t=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];for(;t.nextNode();)Gd(t.currentNode)||n.push(t.currentNode);n.forEach(Kd)}var Od,Zt=U(()=>{Od=/\\[a-zA-Z]+|[_^]\{|\\[,;!]|\\[{}()[\]]|\\leq\b|\\geq\b|\\neq\b|\\in\b|\\sum\b|\\int\b|\\frac\b|\\min\b|\\max\b|\\mathrm\b|\\text\b|\\left\b|\\right\b/});function Jd(e){return String(e??"").replace(zd,(t,n)=>`
|
|
5
|
+
|
|
6
|
+
> \u26A0\uFE0F \u539F\u59CB\u8BB0\u5F55\u5DF2\u622A\u65AD\uFF08${n} bytes\uFF09
|
|
7
|
+
|
|
8
|
+
`)}function Ve(e,{fallback:t}={}){let{text:n,slots:s}=Gi(Jd(e));if(typeof marked>"u"){let a=t?t(n):n;return ma(a,s)}try{return ma(marked.parse(n,{breaks:!0,gfm:!0}),s)}catch{let a=t?t(n):n;return ma(a,s)}}var zd,en=U(()=>{Zt();zd=/(?:<|\[)\s*(?:…\s*)?truncated\s+([\d,]+)\s+bytes\s*(?:>|\])/gi});function Zo(e,t){let n=fa(e,t||re.peek()||E.peek()?.path||"");if(!n)return!1;if(n.root&&(re.value=n.root),n.isDir)oe.value=null,V.value=n.relative;else{let s=n.relative.split("/").filter(Boolean);V.value=s.slice(0,-1).join("/"),oe.value=n.relative}return Y.value="files",!0}var er=U(()=>{W();F();le();Vo();_n();Zt();en()});function Vd({sessionId:e=c.sessionId,agent:t=c.agent||S.peek()||"claude",machineId:n=c.machineId||j.peek()||"local"}={}){return e?`session:${n||"local"}:${t||"claude"}:${e}`:null}function tn(){return!((c.role||"editor")==="viewer"||c.lock?.foreign)}function Yd(){document.dispatchEvent(new CustomEvent("session-lock-changed",{detail:c.lock}))}function Nn(e){c.lock={key:null,token:null,holder:null,held:!1,foreign:!1,...e||{}},Yd()}async function yt(e={}){let t=Vd(e);return t?(c.role||"editor")==="viewer"?(Nn({key:t,held:!1,foreign:!0,holder:"viewer"}),{ok:!1,error:"viewers cannot take exclusive locks",code:403}):(c.lock?.key&&c.lock.key!==t&&await ga(),ms||(ms=(async()=>{try{let s={key:t,kind:"session",ttlSec:tr,exclusive:!0,...c.lock?.token&&c.lock?.key===t?{token:c.lock.token}:{}},a=await x("POST","/api/collab/locks",s,void 0,{hub:!0});return Nn({key:t,token:a.token,holder:a.holder,held:!0,foreign:!1,expiresAt:a.expiresAt,version:a.version}),Zd(),{ok:!0,lock:a}}catch(s){let a=String(s.message||s);return/locked|HTTP 423|423/.test(a)?(Nn({key:t,held:!1,foreign:!0,holder:"another user"}),{ok:!1,code:423,error:a}):(Nn({key:t,held:!0,foreign:!1,unmanaged:!0}),{ok:!0,skipped:!0,error:a})}finally{ms=null}})(),ms)):(Nn({foreign:!1,held:!0,unmanaged:!0}),{ok:!0,skipped:!0})}async function Xd(){let{key:e,token:t,held:n}=c.lock||{};if(!(!e||!t||!n))try{let s=await x("POST","/api/collab/lock-action",{key:e,action:"heartbeat",token:t,ttlSec:tr},void 0,{hub:!0});s?.token&&(c.lock.token=s.token),s?.expiresAt&&(c.lock.expiresAt=s.expiresAt)}catch(s){let a=String(s.message||s);/token mismatch|HTTP 409|409|no lock|HTTP 404|404/.test(a)&&((await yt()).ok||nr())}}function Zd(){nr(),ha=setInterval(()=>{Xd().catch(()=>{})},Qd)}function nr(){ha&&(clearInterval(ha),ha=null)}async function ga(){nr();let{key:e,token:t}=c.lock||{};if(Nn({held:!1,foreign:!1}),!!e)try{await x("POST","/api/collab/lock-action",{key:e,action:"release",token:t,ttlSec:tr},void 0,{hub:!0})}catch{}}async function Ki(){try{let e=await x("GET","/api/collab/me",void 0,void 0,{hub:!0});return c.role=e?.role||c.role||"editor",c.username=e?.username||c.username||null,e}catch{return c.role||(c.role="editor"),null}}var tr,Qd,ha,ms,hs=U(()=>{F();le();tr=60,Qd=2e4,ha=null,ms=null});async function sr(){if(gs&&!(typeof navigator>"u"||!navigator.wakeLock?.request)&&document.visibilityState==="visible"&&!nn)try{nn=await navigator.wakeLock.request("screen"),nn.addEventListener("release",()=>{nn=null,gs&&document.visibilityState==="visible"&&setTimeout(()=>{sr().catch(()=>{})},500)})}catch{nn=null}}async function zi(){let e=nn;if(nn=null,!!e)try{await e.release()}catch{}}function ba(e){gs=!!e,gs?sr().catch(()=>{}):zi().catch(()=>{})}function ar(){typeof document>"u"||document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&gs?sr().catch(()=>{}):document.visibilityState==="hidden"&&zi().catch(()=>{})})}var nn,gs,or=U(()=>{nn=null,gs=!1});function O(e){if(e==null||e==="")return null;if(typeof e=="number")return!Number.isFinite(e)||e<=0?null:e<1e12?Math.round(e*1e3):Math.round(e);if(typeof e=="string"){let t=e.trim();if(/^\d+(\.\d+)?$/.test(t))return O(Number(t));let n=Date.parse(t);return Number.isNaN(n)?null:n}return null}function Pn(e){let t=O(e);if(t==null)return"";let n=Date.now()-t;return n<0?new Date(t).toLocaleDateString():n<6e4?"just now":n<36e5?`${Math.floor(n/6e4)}m ago`:n<864e5?`${Math.floor(n/36e5)}h ago`:n<7*864e5?`${Math.floor(n/864e5)}d ago`:new Date(t).toLocaleDateString()}function Hn(e,t=!0){let n=e||"claude",a={claude:"bg-orange-500/15 text-orange-400",codex:"bg-emerald-500/15 text-emerald-400",grok:"bg-sky-500/15 text-sky-400",gemini:"bg-violet-500/15 text-violet-400",cursor:"bg-amber-500/15 text-amber-400"}[n]||"bg-base-300 text-base-content/50",o=t?n==="claude"?"CC":n==="codex"?"CX":n==="grok"?"GX":n==="gemini"?"GM":n==="cursor"?"CU":n.slice(0,2).toUpperCase():X[n]||n;return`<span class="text-[9px] px-1 py-0.5 rounded font-mono font-semibold flex-shrink-0 ${a}" title="${p(X[n]||n)}">${o}</span>`}function qn(e){if(!e)return"";let t="",n=e.split("/").filter(Boolean);return n.length<=3?e:"\u2026/"+n.slice(-2).join("/")}var _t=U(()=>{W();F()});function eu(e){let t=O(e);if(t==null)return"";let n=new Date(t);return Number.isNaN(n.getTime())?"":n.toLocaleString()}function Ji(){let e=i("notifications-badge");if(e){if(!sn){e.classList.add("hidden"),e.textContent="0";return}e.classList.remove("hidden"),e.textContent=sn>99?"99+":String(sn)}}function Yi(){let e=i("notifications-menu"),t=i("btn-notifications"),n=i("topbar");if(!e||!t||!n)return;let s=t.getBoundingClientRect(),a=n.getBoundingClientRect(),o=Math.min(416,window.innerWidth-16),r=Math.max(8,Math.min(window.innerWidth-o-8,s.right-o));e.style.top=`${Math.round(a.bottom+8)}px`,e.style.left=`${Math.round(r)}px`,e.style.width=`${Math.round(o)}px`}function bs(){let e=i("notifications-menu-list"),t=i("notifications-menu-empty");if(!(!e||!t)){if(!Pe.length){e.innerHTML="",t.classList.remove("hidden"),Ji();return}t.classList.add("hidden"),e.innerHTML=Pe.map(n=>`
|
|
9
|
+
<button type="button"
|
|
10
|
+
class="w-full text-left rounded-lg border px-3 py-2 transition-colors hover:bg-base-200/70 ${n.unread?"border-primary/35 bg-primary/5":"border-base-300 bg-base-100"}"
|
|
11
|
+
data-notification-id="${p(n.id)}"
|
|
12
|
+
data-notification-session="${p(n.sessionId||"")}"
|
|
13
|
+
data-notification-agent="${p(n.agent||"claude")}"
|
|
14
|
+
data-notification-cwd="${p(n.cwd||"")}"
|
|
15
|
+
data-notification-machine="${p(n.machineId||"")}">
|
|
16
|
+
<div class="flex items-start gap-2">
|
|
17
|
+
<span class="text-sm leading-5">\u{1F514}</span>
|
|
18
|
+
<div class="min-w-0 flex-1">
|
|
19
|
+
<div class="flex items-center gap-2">
|
|
20
|
+
<span class="text-xs font-semibold truncate">${p(n.title||"Session done")}</span>
|
|
21
|
+
${n.unread?'<span class="inline-block w-2 h-2 rounded-full bg-primary flex-shrink-0"></span>':""}
|
|
22
|
+
</div>
|
|
23
|
+
${n.body?`<div class="text-[11px] text-base-content/55 mt-0.5 line-clamp-2">${p(n.body)}</div>`:""}
|
|
24
|
+
<div class="flex items-center gap-2 mt-1 text-[10px] text-base-content/35">
|
|
25
|
+
${n.projectName?`<span class="font-mono truncate">${p(n.projectName)}</span>`:""}
|
|
26
|
+
${n.machineId?`<span class="px-1 py-0.5 rounded bg-base-300 text-base-content/55 font-mono">${p(n.machineId)}</span>`:""}
|
|
27
|
+
<span>${p(eu(n.createdAt))}</span>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</button>`).join(""),Ji()}}function an(){i("notifications-menu")?.classList.add("hidden"),i("notifications-backdrop")?.classList.add("hidden"),i("btn-notifications")?.setAttribute("aria-expanded","false")}function tu(){Yi(),i("notifications-menu")?.classList.remove("hidden"),i("notifications-backdrop")?.classList.remove("hidden"),i("btn-notifications")?.setAttribute("aria-expanded","true")}function Xi(){let e=i("notifications-menu");e&&(e.classList.contains("hidden")?tu():an())}function Qi(e){let t=new Map;for(let n of e||[])n?.id&&t.set(String(n.id),n);Pe=[...t.values()].sort((n,s)=>(O(s.createdAt)||0)-(O(n.createdAt)||0)),sn=Pe.reduce((n,s)=>n+(s.unread?1:0),0),bs()}async function va(){try{let e=await x("GET","/api/notifications?limit=80");Pe=Array.isArray(e?.notifications)?e.notifications:[],sn=Number(e?.unreadCount)||Pe.reduce((t,n)=>t+(n.unread?1:0),0),bs()}catch{Pe=[],sn=0,bs()}}async function Vi(e=null){let t=await x("POST","/api/notifications/read",e?.length?{ids:e}:{});Pe=Array.isArray(t?.notifications)?t.notifications:Pe.map(n=>!e||e.includes(n.id)?{...n,unread:!1}:n),sn=Number(t?.unreadCount)||Pe.reduce((n,s)=>n+(s.unread?1:0),0),bs()}function nu(e){if(!(typeof Notification>"u")&&document.visibilityState!=="visible"&&Notification.permission==="granted")try{let t=new Notification(e.title||"Session done",{body:e.body||e.projectName||e.sessionId||"",tag:e.id});t.onclick=()=>{window.focus(),t.close()}}catch{}}function xa(e){if(!e?.id)return;if(Pe.find(n=>n.id===e.id)){Qi([e,...Pe.filter(n=>n.id!==e.id)]);return}Qi([e,...Pe]),nu(e)}function Zi(e={}){rr=typeof e.openSession=="function"?e.openSession:null,bs(),va(),typeof Notification<"u"&&Notification.permission==="default"&&document.addEventListener("click",()=>{try{Notification.requestPermission().catch(()=>{})}catch{}},{once:!0}),b.on("click","#notifications-backdrop",t=>{t.preventDefault(),t.stopPropagation(),an()}),b.on("click","#btn-notifications-read-all",async t=>{t.preventDefault(),t.stopPropagation(),await Vi()}),b.on("click","[data-notification-id]",async(t,n)=>{let s=n.dataset.notificationId;s&&(await Vi([s]),an(),!(!rr||!n.dataset.notificationSession)&&rr(n.dataset.notificationSession,n.dataset.notificationCwd||null,null,n.dataset.notificationAgent||"claude",n.dataset.notificationMachine||null))}),document.addEventListener("click",t=>{let n=i("notifications-menu"),s=i("btn-notifications"),a=t.target;!n||n.classList.contains("hidden")||n.contains(a)||s?.contains(a)||an()}),window.addEventListener("resize",()=>{i("notifications-menu")&&!i("notifications-menu").classList.contains("hidden")&&Yi()})}var Pe,sn,rr,ya=U(()=>{W();le();_t();Pe=[],sn=0,rr=null});function vs(e,t=80){return e?e.scrollHeight-e.scrollTop-e.clientHeight<t:!0}function su(e,t){return e<0?!1:t}function au({force:e=!1,following:t=!0,userScrolling:n=!1}={}){return e?!0:n?!1:t}function wa(e){let t=!0,n=!1,s=0,a=()=>{t=vs(e),n=!1},o=u=>{t=su(u.deltaY,t),u.deltaY<0&&(n=!0)},r=u=>{s=u.touches?.[0]?.clientY||0},d=u=>{(u.touches?.[0]?.clientY||0)-s>8&&(t=!1,n=!0)};return e.addEventListener("scroll",a,{passive:!0}),e.addEventListener("wheel",o,{passive:!0}),e.addEventListener("touchstart",r,{passive:!0}),e.addEventListener("touchmove",d,{passive:!0}),{stick(u=!1){au({force:u,following:t,userScrolling:n})&&(e.scrollTop=e.scrollHeight,t=!0)},setFollowing(u){t=!!u},isFollowing(){return t},destroy(){e.removeEventListener("scroll",a),e.removeEventListener("wheel",o),e.removeEventListener("touchstart",r),e.removeEventListener("touchmove",d)}}}var ir=U(()=>{});function ou(){return X[S.peek()]||"Assistant"}function ru(e){let t=String(e||"").trim();return/remote compact task|error decoding response body/i.test(t)?"Codex \u4F1A\u8BDD\u538B\u7F29\u5931\u8D25\uFF08\u7F51\u7EDC\u4E2D\u65AD\uFF09\u3002\u518D\u53D1\u4E00\u6761\u6D88\u606F\u91CD\u8BD5\uFF0C\u6216\u5F00\u65B0\u4F1A\u8BDD\u3002":t||"\u53D1\u9001\u5931\u8D25"}function ol(e){return e?(on&&on.el===e||(on?.destroy?.(),on=wa(e),on.el=e),on):null}function He(e,t){if(!e||e.dataset.historyPainting==="1")return;ol(e).stick(!!t)}function ja(){try{Fe.length?sessionStorage.setItem(ur,JSON.stringify(Fe.slice(-30))):sessionStorage.removeItem(ur)}catch{}}function lu(){let e=$t(),t=Fe.filter(n=>n.key===e).length;t&&!nl.has(e)&&(nl.add(e),C(`\u231B Restored ${t} queued prompt${t===1?"":"s"} in this browser tab`))}function rl(e=c.sessionId,t=c.agent,n=c.machineId){return e?`${n||""}:${t||"claude"}:${e}`:""}function cu(e={}){let t=rl(e.sessionId,e.agent,e.machineId);if(!t)return 0;try{return Number(JSON.parse(localStorage.getItem(dr)||"{}")[t])||0}catch{return 0}}function du(e){let t=Number(e?.hubSeq)||0;if(!t)return!0;let n=rl(e.sessionId||c.sessionId,e.agent||c.agent,c.machineId);if(!n)return!0;let s={};try{s=JSON.parse(localStorage.getItem(dr)||"{}")||{}}catch{}let a=Number(s[n])||0;if(t<=a)return!1;s[n]=t;let o=Object.keys(s);o.length>500&&o.sort((r,d)=>Number(s[d])-Number(s[r])).slice(500).forEach(r=>delete s[r]);try{localStorage.setItem(dr,JSON.stringify(s))}catch{}return!0}function $t({sessionId:e=c.sessionId,agent:t=c.agent,machineId:n=c.machineId}={}){return e?`${n||""}:${t||"claude"}:${e}`:null}function Un(e){let t=$t(e),n=i("chat-input");!t||!n||(n.value?rn.set(t,n.value):rn.delete(t))}function Fn(e){let t=i("chat-input");t&&(t.value=rn.get($t(e))||"",Ss(t),$s(t.value))}function Wn(e){let t=$t(e);if(!t)return;let n=Fe.filter(a=>a.key===t);if(!n.length)return;Fe=Fe.filter(a=>a.key!==t),ja();let s=rn.get(t)||"";rn.set(t,[s,...n.map(a=>a.text)].filter(Boolean).join(`
|
|
32
|
+
|
|
33
|
+
`))}function Gn(){D.peek()&&(D.value=!1,ln())}function uu(){el||(el=!0,document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="visible"&&(ut=400,Rn({probe:!0}),c.ws?.readyState===WebSocket.OPEN&&c.sessionId))try{c.ws.send(JSON.stringify({type:"subscribe",sessionId:c.sessionId,agent:c.agent}))}catch{}}),window.addEventListener("online",()=>{ut=400,Rn({force:!0})}),window.addEventListener("pageshow",e=>{e.persisted?Rn({force:!0}):Rn({probe:!0})}),window.addEventListener("focus",()=>Rn({probe:!0})),navigator.connection?.addEventListener?.("change",()=>{ut=400,Rn({probe:!0})}))}function $a(){let e=i("conn-dot");if(!e)return;let t=fe.peek();e.classList.remove("bg-success","bg-warning","bg-error","bg-base-content/30","animate-pulse"),t==="open"?(e.classList.add("bg-success"),e.title="\u5DF2\u8FDE\u63A5"):t==="connecting"||t==="reconnecting"?(e.classList.add("bg-warning","animate-pulse"),e.title=t==="connecting"?"\u8FDE\u63A5\u4E2D\u2026":"\u91CD\u8FDE\u4E2D\u2026"):t==="offline"?(e.classList.add("bg-error"),e.title="\u79BB\u7EBF"):(e.classList.add("bg-base-content/30"),e.title="\u672A\u8FDE\u63A5")}function Rn(e={}){let t=c.ws?.readyState;if(e.force){ut=400,Pt({quiet:!0});return}if(t===WebSocket.OPEN){if(e.probe&&kt&&Date.now()-kt>45e3)try{c.ws.close()}catch{}else if(e.probe&&c.ws.readyState===WebSocket.OPEN)try{c.ws.send(JSON.stringify({type:"ping"}))}catch{}return}t!==WebSocket.CONNECTING&&(ut=Math.min(ut,800),Pt({quiet:!0}))}function pu(){Bn||(fe.value=typeof navigator<"u"&&navigator.onLine===!1?"offline":"reconnecting",$a(),Bn=setTimeout(()=>{Bn=null,Pt({quiet:!0})},ut),ut=Math.min(Math.round(ut*1.8),15e3))}function il(){ka&&(clearInterval(ka),ka=null)}function fu(e,t){il(),ka=setInterval(()=>{if(!(t!==ys||e.readyState!==WebSocket.OPEN)){if(kt&&Date.now()-kt>7e4){try{e.close()}catch{}return}if(!(typeof document<"u"&&document.visibilityState==="hidden")&&kt&&Date.now()-kt>4e4)try{e.send(JSON.stringify({type:"ping"}))}catch{}}},3e4)}function ln(){let e=D.peek()||!!E.peek()&&fe.peek()==="open";ba(e)}function Ia(){return(c.role||"editor")==="viewer"?"\u53EA\u8BFB\u8D26\u53F7\uFF0C\u65E0\u6CD5\u8F93\u5165":c.lock?.foreign?`\u4F1A\u8BDD\u7531 ${c.lock.holder&&c.lock.holder!=="viewer"?c.lock.holder:"\u5176\u4ED6\u7528\u6237"} \u5360\u7528\uFF08\u9501\uFF09`:"\u5F53\u524D\u65E0\u6CD5\u8F93\u5165"}function Ta(){let e=tn();c.externalSessionReadOnly=!e;let t=i("chat-input"),n=i("send-btn"),s=i("btn-attach"),a=i("session-lock-banner");t&&(t.disabled=!e,t.readOnly=!e,e?D.peek()?t.placeholder="\u56DE\u590D\u4E2D\u2026 \u53EF\u5148\u5199\u597D\u4E0B\u4E00\u6761\uFF0C\u7ED3\u675F\u540E\u81EA\u52A8\u53D1\u9001 \xB7 \u6216\u70B9 \u25A0 \u505C\u6B62":$s(t.value||""):t.placeholder=Ia()),n&&(n.disabled=!e),s&&(s.disabled=!e),a&&(e?(a.classList.add("hidden"),a.textContent=""):(a.classList.remove("hidden"),a.textContent=Ia()))}function Da(e){Ta()}function Pt(e={}){uu(),Bn&&(clearTimeout(Bn),Bn=null),e.quiet&&(cr=!0);let t=c.machineId||(typeof localStorage<"u"?localStorage.getItem("machineId"):null);tl!==t&&(ca(),tl=t);let n=++ys;try{c.ws?.close()}catch{}fe.value="connecting",$a();let s=location.protocol==="https:"?"wss":"ws",a=new URLSearchParams;c.token&&a.set("token",c.token),t&&a.set("machine",t),c.sessionId&&a.set("sessionId",c.sessionId),c.agent&&a.set("agent",c.agent);let o=cu();o&&a.set("lastSeq",String(o));let r=new WebSocket(`${s}://${location.host}/ws/chat?${a}`);c.ws=r,r.addEventListener("open",()=>{if(n===ys){if(ut=1e3,kt=Date.now(),fe.value="open",$a(),c.sessionId)try{r.send(JSON.stringify({type:"subscribe",sessionId:c.sessionId,agent:c.agent}))}catch{}la(),lu(),fu(r,n),ln(),lr&&!cr&&C(t?`\u5DF2\u91CD\u8FDE \xB7 ${t}`:"\u5DF2\u91CD\u8FDE"),lr=!1,cr=!1}}),r.addEventListener("message",d=>{if(n!==ys)return;let u;try{u=JSON.parse(d.data)}catch{return}if(du(u)){if(u.type==="pong"){kt=Date.now();return}if(u.type==="ping"){if(kt=Date.now(),r.readyState===WebSocket.OPEN)try{r.send(JSON.stringify({type:"pong"}))}catch{}return}if(u.type==="run-status"){u.running?D.value=!0:(D.peek()&&(D.value=!1),pr()),ln();return}ll(u)}}),r.addEventListener("close",()=>{n===ys&&(il(),lr=!0,fe.value=typeof navigator<"u"&&navigator.onLine===!1?"offline":"reconnecting",$a(),pu())}),r.addEventListener("error",()=>{})}function pr(){if(!Fe.length||D.peek())return;let e=$t(),t=Fe.findIndex(a=>a.key===e);if(t<0)return;let[n]=Fe.splice(t,1);ja();let s=i("chat-input");s&&(s.value=n.text,Ss(s)),setTimeout(()=>{if(n.key!==$t()||D.peek()){rn.set(n.key,n.text);return}Ls()},0)}function ws(){D.value=!1,ln(),pr()}function ll(e){if(!(e?.sessionId&&c.sessionId&&e.sessionId!==c.sessionId)){if(e&&typeof e.type=="string"&&(e.type==="note.added"||e.type==="note.updated"||e.type==="note.removed"||e.type==="queue.item.added"||e.type==="queue.item.updated"||e.type==="queue.item.removed"||e.type==="queue.item.moved"||e.type==="queue.item.sending")){window.dispatchEvent(new CustomEvent("hub-ws-message",{detail:e}));let t={"note.added":"hub:note-added","note.updated":"hub:note-updated","note.removed":"hub:note-removed"}[e.type];t&&window.dispatchEvent(new CustomEvent(t,{detail:e}))}if(e._hubReplay===!0){document.dispatchEvent(new CustomEvent("external-session-updated",{detail:e}));return}if(e.type==="batch"&&Array.isArray(e.items)){for(let t of e.items)ll(t);return}if(e.type==="session-created"){let t=_.peek();c.sessionId=e.sessionId,e.agent&&e.agent!==S.peek()&&Ne(e.agent),se(t,e.agent||S.peek(),e.sessionId),document.dispatchEvent(new CustomEvent("sessions-changed"));return}if(e.type==="external-sessions-changed"){document.dispatchEvent(new CustomEvent("sessions-changed"));return}if(e.type==="external-session-updated"){document.dispatchEvent(new CustomEvent("sessions-changed")),document.dispatchEvent(new CustomEvent("external-session-updated",{detail:e}));return}if(e.type==="notification"&&e.notification){xa(e.notification);return}if(e.type==="grok-queue-status"){Eu(e);return}if(e.type==="result"){ks(),xs(),pt();let t=e.usage;if(t){let n={input_tokens:t.inputTokens??t.input_tokens,output_tokens:t.outputTokens??t.output_tokens,cache_read_input_tokens:t.cacheReadInputTokens??t.cache_read_input_tokens,cache_creation_input_tokens:t.cacheCreationInputTokens??t.cache_creation_input_tokens,total_tokens:t.totalTokens??t.total_tokens,reasoning_tokens:t.reasoningTokens??t.reasoning_tokens,costUSD:t.costUSD??t.cost_usd};c.lastUsage=n,c.sessionId&&(c.lastUsageSessionId=c.sessionId),On(n)}e.is_error||C("\u2713 Done"),ws();return}if(e.type==="complete"){ks(),xs(),pt(),!e.aborted&&e.agent==="claude"?C("\u2713 Done"):!e.aborted&&e.agent&&e.agent!=="claude"&&!e.error||(!e.aborted&&!e.agent?C("\u2713 Done"):e.aborted&&C("\u5DF2\u505C\u6B62")),ws();return}if(e.type==="error"){ks(),xs(),(e.code===423||/locked/i.test(String(e.message||"")))&&(c.lock={...c.lock||{},held:!1,foreign:!0,holder:e.lock?.holder||c.lock?.holder||"another user"},Ta()),Ht("error","Error",ru(e.message)),ws();return}if(e.type==="shell-start"){c.shellBubble=null;return}if(e.type==="shell-output"){c.shellBubble||(c.shellBubble=Tu(e.stream==="stderr"?"shell-err":"shell")),Cu(c.shellBubble,e.data);return}if(e.type==="shell-exit"){c.shellBubble=null,C(e.code===0?"\u2713 Exit 0":`\u2717 Exit ${e.code}${e.error?": "+e.error:""}`),ws();return}if(e.type==="assistant"){xs();for(let t of e.message?.content||[])t.type==="text"&&t.text?(pt(),Ht("assistant",ou(),t.text,{ts:e.ts||Date.now()})):t.type==="tool_use"&&br(t,{ts:e.ts||Date.now()});return}if(e.type==="assistant_stream_start"){D.peek()||(D.value=!0,ln()),cl(e.ts);return}if(e.type==="assistant_delta"){D.peek()||(D.value=!0,ln()),mu(e.data||"");return}if(e.type==="assistant_stream_end"){xs();return}if(e.type==="thought_stream_start"){dl();return}if(e.type==="thought_delta"){hu(e.data||"");return}if(e.type==="thought_stream_end"){ks();return}if(e.type==="status"){let t=i("stream-status");if(t)t.textContent=e.message||"";else{let n=i("messages");n&&e.message&&(n.insertAdjacentHTML("beforeend",`<div id="stream-status" class="text-center text-[10px] text-base-content/35 py-0.5">${p(e.message)}</div>`),He(n))}return}if(e.type==="permission_resolved"){let t=e.requestId||e.request_id;t&&i(`perm-${t}`)?.remove();return}(e.type==="permission_request"||e.request_id&&e.tool_name)&&ju(e)}}function cl(e){let t=i("messages");if(!t||(pt(),ks(),Xe&&t.contains(Xe)))return;let n=Ca(e||Date.now()),s=Ma(e||Date.now());t.insertAdjacentHTML("beforeend",`
|
|
34
|
+
<div class="msg-row assistant px-2 live-stream" data-ts="${p(s)}">
|
|
35
|
+
<div class="max-w-[88%] rounded-2xl rounded-tl-sm px-3 py-2 text-sm bg-base-200 break-words md">
|
|
36
|
+
<div class="msg-stream-body whitespace-pre-wrap"></div>
|
|
37
|
+
</div>
|
|
38
|
+
${n?`<div class="msg-ts" title="${p(s)}">${p(n)}</div>`:""}
|
|
39
|
+
</div>`),Xe=t.lastElementChild,Ue=Xe.querySelector(".msg-stream-body"),i("stream-status")?.remove(),He(t)}function mu(e){e&&(Ue||cl(Date.now()),Ue&&(Ue.textContent+=e,He(i("messages"))))}function xs(){if(!Xe||!Ue){Xe=null,Ue=null;return}let e=Ue.textContent||"";e.trim()?(Ue.classList.remove("whitespace-pre-wrap"),Ue.classList.add("md"),Ue.innerHTML=La(e),bl(Xe),hl(Xe,e)):Xe.remove(),Xe=null,Ue=null,i("stream-status")?.remove()}function dl(){let e=i("messages");e&&(Nt&&e.contains(Nt)||(e.insertAdjacentHTML("beforeend",`
|
|
40
|
+
<div class="msg-row assistant px-2 thought-stream">
|
|
41
|
+
<div class="max-w-[88%] rounded-lg border border-base-300/60 bg-base-200/50 px-2.5 py-1.5 text-[11px] text-base-content/45">
|
|
42
|
+
<div class="font-medium text-base-content/35 mb-0.5">thinking\u2026</div>
|
|
43
|
+
<div class="thought-body font-mono whitespace-pre-wrap max-h-24 overflow-y-auto opacity-80"></div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>`),Nt=e.lastElementChild,dt=Nt.querySelector(".thought-body"),He(e)))}function hu(e){e&&(dt||dl(),dt&&(dt.textContent+=e,dt.scrollTop=dt.scrollHeight,He(i("messages"))))}function ks(){if(Nt&&dt){let e=(dt.textContent||"").length;Nt.innerHTML=`
|
|
46
|
+
<div class="text-[10px] text-base-content/30 px-1 select-none">\u{1F4AD} thought ${e?`(${e} chars)`:""}</div>`}Nt=null,dt=null}function bu(e){let[t,...n]=e.slice(1).trim().split(/\s+/),s=n.join(" ");switch(t.toLowerCase()){case"agent":{if(!s)return C(`Current agent: ${S.peek()} \xB7 agents: claude | codex | grok | gemini | cursor`),!0;let a=s.toLowerCase();return["claude","codex","grok","gemini","cursor"].includes(a)?(a!==S.peek()?(c.sessionId=null,Ne(a),se(Oe(a)),document.dispatchEvent(new CustomEvent("agent-changed")),C(`Agent \u2192 ${X[a]} \xB7 model ${_.peek()} \xB7 new session`)):C(`Agent already ${X[a]}`),!0):(C(`Unknown agent "${s}" \xB7 valid: claude | codex | grok | gemini | cursor`),!0)}case"model":{if(!s){let d=S.peek(),u=Be(d).map(l=>l.value).join(" | ");return C(`Current model: ${_.peek()} (${d})${u?`
|
|
47
|
+
Available: ${u}`:""}`),!0}let a=gu[s.toLowerCase()]||s,o=S.peek()||"claude",r=Be(o).some(d=>d.value===a);return r||Jt(o,a),se(a),C(`Model set to ${a}${r?"":" (saved as custom \u2605)"}`),document.dispatchEvent(new CustomEvent("agent-changed")),!0}case"effort":{let a=Qt(S.peek(),_.peek());return s?a.includes(s.toLowerCase())?(te.value=s.toLowerCase(),C(`Effort set to ${s.toLowerCase()}`),!0):(C(`Unknown effort level "${s}" \xB7 valid: ${a.join(" | ")}`),!0):(C(`Current effort: ${te.peek()||"(default)"} \xB7 levels: ${a.join(" | ")}`),!0)}case"clear":return zn(),c.sessionId=null,c.lastUsage=null,C("Cleared \xB7 new session"),!0;case"usage":return vu(),!0;case"help":return C(`Available slash commands:
|
|
48
|
+
/agent [claude|codex|grok|gemini|cursor]
|
|
49
|
+
/model [haiku|sonnet|opus|<model-id>]
|
|
50
|
+
/effort [low|medium|high|xhigh|max]
|
|
51
|
+
/usage
|
|
52
|
+
/clear
|
|
53
|
+
/help`),!0;default:return!1}}function Ie(e){if(e==null||Number.isNaN(Number(e)))return"\u2014";let t=Number(e);return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${(t/1e3).toFixed(1)}k`:String(Math.round(t))}async function vu(){let e=S.peek()||"claude",t=_.peek()||"\u2014",n=c.sessionId,s=[`Agent: ${X[e]||e}`,`Model: ${t}`,`Session: ${n?n.slice(0,8)+"\u2026":"(new \u2014 send a message first)"}`];if(c.lastUsage&&(!n||c.lastUsageSessionId===n)){let a=c.lastUsage;s.push(`Last turn: \u2191${Ie(a.input_tokens)} \u2193${Ie(a.output_tokens)}`+(a.cache_read_input_tokens?` \xB7 ${Ie(a.cache_read_input_tokens)} cached`:"")+(a.reasoning_tokens?` \xB7 ${Ie(a.reasoning_tokens)} reason`:"")+(a.total_tokens?` \xB7 \u03A3${Ie(a.total_tokens)}`:"")+(a.costUSD!=null?` \xB7 $${Number(a.costUSD).toFixed(4)}`:""))}if(!n){C(s.join(`
|
|
54
|
+
`)),mr("\u25C8 /usage \xB7 no session yet");return}C("Loading usage\u2026");try{let a=new URLSearchParams({sessionId:n,agent:e}),r=(await x("GET",`/api/usage?${a}`)).context||{};if(r.model&&(s[1]=`Model: ${r.model}`),r.title&&s.push(`Title: ${r.title}`),r.tokensUsed!=null||r.windowTokens!=null||r.usagePercent!=null){let u=r.tokensUsed!=null?Ie(r.tokensUsed):"\u2014",l=r.windowTokens!=null?Ie(r.windowTokens):"\u2014",f=r.usagePercent!=null?`${r.usagePercent}%`:"\u2014";s.push(`Context window: ${u} / ${l} (${f})`)}if(r.turnCount!=null&&s.push(`Turns: ${r.turnCount}`),r.toolCallCount!=null&&s.push(`Tools: ${r.toolCallCount}`),r.sessionDurationSeconds!=null){let u=Math.floor(r.sessionDurationSeconds/60),l=Math.round(r.sessionDurationSeconds%60);s.push(`Duration: ${u}m ${l}s`)}if(r.sessionTotals){let u=r.sessionTotals;s.push(`Session totals: \u2191${Ie(u.input_tokens)} \u2193${Ie(u.output_tokens)}`+(u.cache_read_input_tokens?` \xB7 ${Ie(u.cache_read_input_tokens)} cached`:"")+(u.total_tokens?` \xB7 \u03A3${Ie(u.total_tokens)}`:"")+(u.costUSD?` \xB7 $${Number(u.costUSD).toFixed(4)}`:""))}if(r.lastTurn&&!c.lastUsage){let u=r.lastTurn;s.push(`Last completed turn: \u2191${Ie(u.input_tokens)} \u2193${Ie(u.output_tokens)}`+(u.cache_read_input_tokens?` \xB7 ${Ie(u.cache_read_input_tokens)} cached`:"")+(u.costUSD!=null?` \xB7 $${Number(u.costUSD).toFixed(4)}`:""))}r.note&&s.push(r.note);let d=i("messages");if(d){let u=[...d.children];for(let l=u.length-1;l>=0;l--)if(u[l].textContent==="Loading usage\u2026"){u[l].remove();break}}C(s.join(`
|
|
55
|
+
`)),(r.tokensUsed!=null||r.windowTokens!=null)&&hr({tokensUsed:r.tokensUsed,windowTokens:r.windowTokens,usagePercent:r.usagePercent,model:r.model||t,turnCount:r.turnCount,toolCallCount:r.toolCallCount}),r.sessionTotals?On(r.sessionTotals):r.lastTurn?On(r.lastTurn):c.lastUsage&&On(c.lastUsage)}catch(a){let o=i("messages");if(o){let r=[...o.children];for(let d=r.length-1;d>=0;d--)if(r[d].textContent==="Loading usage\u2026"){r[d].remove();break}}C(`${s.join(`
|
|
56
|
+
`)}
|
|
57
|
+
(usage fetch failed: ${a.message})`)}}function Ls(){let e=i("chat-input"),t=e?.value.trim();if(!t||!E.peek())return;if(!tn()){C(Ia()),yt().then(()=>Ta()).catch(()=>{});return}if(c.sessionId&&!c.lock?.held&&!c.lock?.unmanaged){yt().then(s=>{if(!s?.ok&&!s?.skipped){Ta(),C(Ia());return}Ls()}).catch(()=>Ls());return}if(D.peek()){if(S.peek()==="grok"&&c.sessionId){let s="grok",a=te.peek()||Qe(s,_.peek())||"low",o=lt({type:"command",cmd:"turn.start",agent:s,command:t,sessionId:c.sessionId,lockToken:c.lock?.token||void 0,options:{agent:s,cwd:E.peek().path,sessionId:c.sessionId,configDir:c.configDir,model:_.peek(),lockToken:c.lock?.token||void 0,effort:a,...de.peek()&&{permissionMode:de.peek()},...de.peek()==="bypassPermissions"&&{allowDangerouslySkipPermissions:!0}}});ml(t),e.value="",Ss(e),$s(""),Sa(),C(o?"\u5DF2\u52A0\u5165 Grok \u670D\u52A1\u7AEF\u961F\u5217\uFF0C\u5237\u65B0\u9875\u9762\u4ECD\u4F1A\u663E\u793A":"\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u6D88\u606F\u5C06\u5728\u91CD\u8FDE\u540E\u53D1\u9001");return}Fe.push({key:$t(),text:t}),ja(),e.value="",Ss(e),$s(""),Sa(),C(`\u5DF2\u6392\u961F\u4E0B\u4E00\u6761\uFF0C\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u540E\u53D1\u9001\uFF1A${t.length>80?t.slice(0,80)+"\u2026":t}`);return}if(e.value="",rn.delete($t()),Ss(e),$s(""),Sa(),t.startsWith("/")&&bu(t))return;D.value=!0,ln();let n=Date.now();if(pl(t))Ht("shell","$ Shell",t.slice(1).trim(),{ts:n}),lt({type:"command",cmd:"shell.exec",command:t.slice(1).trim(),cwd:E.peek().path})||C("\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u547D\u4EE4\u5DF2\u5165\u961F\uFF0C\u91CD\u8FDE\u540E\u53D1\u9001");else{pt(),Ht("user","You",t,{ts:n,forceStick:!0});let s=S.peek()||"claude",a=te.peek()||Qe(s,_.peek())||(s==="grok"?"low":""),o=de.peek();c.sessionId&&se(_.peek(),s,c.sessionId),lt({type:"command",cmd:"turn.start",agent:s,command:t,sessionId:c.sessionId,lockToken:c.lock?.token||void 0,options:{agent:s,cwd:E.peek().path,sessionId:c.sessionId,configDir:c.configDir,model:_.peek(),lockToken:c.lock?.token||void 0,...a&&{effort:a},...o&&{permissionMode:o},...o==="bypassPermissions"&&{allowDangerouslySkipPermissions:!0}}})||C("\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u6D88\u606F\u5DF2\u5165\u961F\uFF0C\u91CD\u8FDE\u540E\u53D1\u9001")}}function ul(){c.sessionId&<({type:"command",cmd:"turn.interrupt",sessionId:c.sessionId}),Fe=Fe.filter(e=>e.key!==$t()),ja(),Iu(),ws()}function $s(e){let t=pl(e),n=i("chat-input"),s=i("send-btn");if(!n||!s)return;n.classList.toggle("textarea-warning",t),n.style.fontFamily=t?"monospace":"",s.classList.toggle("btn-warning",t),s.classList.toggle("btn-primary",!t),s.textContent=t?"Run":"Send";let a=X[S.peek()]||"agent",o=typeof window<"u"&&window.matchMedia("(max-width: 640px)").matches;t?n.placeholder=o?"Shell \u547D\u4EE4\u2026":"Shell command (without !)\u2026":n.placeholder=o?`\u95EE ${a}\u2026`:`Ask ${a}\u2026 or !cmd for shell`}function pl(e){let t=String(e||"").trimStart();return t.startsWith("!")&&!/^!\[[^\]]*\]\([^)]+\)/.test(t)}function xu(){return typeof window<"u"&&window.matchMedia("(max-width: 640px)").matches,72}function Ss(e){e.style.height="auto",e.style.height=Math.min(e.scrollHeight,xu())+"px"}function Ca(e){let t=O(e);if(t==null)return"";let n=new Date(t);if(Number.isNaN(n.getTime()))return"";let s=new Date,a=n.toDateString()===s.toDateString(),o=n.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});return a?o:`${n.toLocaleDateString(void 0,{month:"numeric",day:"numeric"})} ${o}`}function Ma(e){let t=O(e);return t==null?"":new Date(t).toISOString()}function ku(e,t,n){if(e==="system")return t;let s=Ca(n),a=Ma(n),o=s?`<div class="msg-ts" title="${p(a)}">${p(s)}</div>`:"";return`<div class="msg-row ${e==="user"?"user":e==="shell"||e==="shell-err"?"assistant":e} px-2" data-ts="${p(a)}">${t}${o}</div>`}function $u(e,t,n){let s='<button class="msg-expand-btn text-[10px] text-primary/70 mt-1.5 block cursor-pointer hover:text-primary">\u25BC Show more</button>',a;switch(e){case"user":{let r=/!\[.*?\]\(.*?\)/.test(t)?La(t):null,d=t.length>yu,u=d?`<div class="msg-body">${r??p(t.trimEnd())}</div>${s}`:r??p(t.trimEnd());a=`<div class="max-w-[80%] rounded-2xl rounded-tr-sm px-3 py-2 text-sm bg-primary/15 border border-primary/20 text-base-content break-words${d?" msg-card":""}${r?" md":""}"${r?"":' style="white-space:pre-wrap"'}>${u}</div>`;break}case"assistant":{let o=t.length>wu,r=o?`<div class="msg-body">${La(t)}</div>${s}`:La(t);a=`<div class="msg-assistant-content max-w-[min(92%,52rem)] rounded-2xl rounded-tl-sm px-3.5 py-2.5 text-sm bg-base-200 border border-base-300/40 break-words md leading-relaxed${o?" msg-card":""}">${r}</div>`;break}case"error":a=`<div class="max-w-[88%] rounded-2xl rounded-tl-sm px-3 py-2 text-sm bg-error/10 border border-error/20 text-error break-words" style="white-space:pre-wrap">${p(t)}</div>`;break;case"shell":case"shell-err":a=`<div class="w-full max-w-[96%] rounded-lg code-surface px-3 py-2 text-sm font-mono ${e==="shell-err"?"text-error":""} break-words" style="white-space:pre-wrap">${p(t)}</div>`;break;case"system":return`<div class="text-center text-[11px] text-base-content/30 py-0.5 select-none">${p(t)}</div>`;default:a=`<div class="rounded-lg px-3 py-2 text-sm bg-base-300 break-words" style="white-space:pre-wrap">${p(t)}</div>`}return ku(e,a,n)}function Ht(e,t,n,s={}){let a=i("messages");if(!a)return;let o=O(s.ts)??(e==="system"?null:Date.now());a.insertAdjacentHTML("beforeend",$u(e,n,o)),bl(a.lastElementChild),e==="assistant"&&hl(a.lastElementChild,n,s),He(a,!!s.forceStick)}function C(e){Ht("system","",e)}function Sa(){for(let e of Aa)if(e.previewUrl)try{URL.revokeObjectURL(e.previewUrl)}catch{}Aa.length=0,Su()}function Kn(){Sa()}function Su(){let e=i("chat-attach-bar");if(e){if(!Aa.length){e.classList.add("hidden"),e.innerHTML="";return}e.classList.remove("hidden"),e.innerHTML=Aa.map((t,n)=>`
|
|
58
|
+
<div class="chat-thumb relative" title="${p(t.ref||t.path)}">
|
|
59
|
+
${t.previewUrl?`<img src="${t.previewUrl}" alt="${p(t.label||"img")}">`:`<span class="chat-thumb-path">${p(t.label||t.name||"file")}</span>`}
|
|
60
|
+
<span class="chat-thumb-label">${p(t.label||t.kind||"")}</span>
|
|
61
|
+
<button type="button" class="chat-thumb-x" data-rm-attach="${n}" aria-label="remove">\u2715</button>
|
|
62
|
+
</div>`).join("")}}function wt(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function mr(e){let t=i("messages");t&&(t.insertAdjacentHTML("beforeend",`<div class="token-bar select-none">
|
|
63
|
+
<span class="token-bar-mark">\u25C8</span><span class="token-bar-text">${p(e)}</span>
|
|
64
|
+
</div>`),He(t))}function On(e){if(!e)return;let t=e.input_tokens??e.inputTokens??0,n=e.output_tokens??e.outputTokens??0,s=e.total_tokens??e.totalTokens??t+n,a=e.cache_read_input_tokens??e.cachedReadTokens?` \xB7 ${wt(e.cache_read_input_tokens??e.cachedReadTokens)} cached`:"",o=e.cache_creation_input_tokens??e.cacheCreationInputTokens?` \xB7 ${wt(e.cache_creation_input_tokens??e.cacheCreationInputTokens)} cache-write`:"",r=e.reasoning_tokens??e.reasoningTokens?` \xB7 ${wt(e.reasoning_tokens??e.reasoningTokens)} reason`:"",d=e.costUSD??e.cost_usd,u=d!=null?` \xB7 $${Number(d).toFixed(4)}`:"",l=s?` \xB7 \u03A3${wt(s)}`:"";mr(`\u2191${wt(t)} \u2193${wt(n)}${a}${o}${r}${l}${u}`)}function hr(e){if(!e)return;let t=e.tokensUsed??e.contextTokensUsed,n=e.windowTokens??e.contextWindowTokens,s=e.usagePercent??e.contextWindowUsage;if(t==null&&n==null&&s==null)return;let a=[];t!=null&&n!=null?a.push(`context ${wt(t)} / ${wt(n)}`):t!=null&&a.push(`context ${wt(t)}`),s!=null&&a.push(`${s}%`),e.model&&a.push(e.model),e.turnCount!=null&&a.push(`${e.turnCount} turns`),e.toolCallCount!=null&&a.push(`${e.toolCallCount} tools`),mr(`\u25A3 ${a.join(" \xB7 ")}`)}function fl(){let e=i("messages");e&&(e.dataset.historyPainting="1",e.innerHTML="",Ye=null,fr.clear())}function gr(e=null){let t=i("messages");t&&(delete t.dataset.historyPainting,e==null?He(t,!0):(t.scrollTop=Math.max(0,e),ol(t).setFollowing(vs(t))))}function zn(){let e=i("messages"),t=i("permission-requests");e&&(e.innerHTML="",delete e.dataset.historyPainting),t&&(t.innerHTML=""),c.shellBubble=null,Ye=null,Xe=Ue=null,Nt=dt=null,fr.clear(),Ea.clear()}function Lu(e,t=c.sessionId){return`${t||""}
|
|
65
|
+
${String(e||"")}`}function ml(e,t=c.sessionId){let n=Lu(e,t);!e||Ea.has(n)||(Ea.add(n),Ht("user","You",e,{ts:Date.now(),forceStick:!0}),i("messages")?.lastElementChild?.classList.add("queued-user-msg"))}function Eu(e){if((e.sessionId||c.sessionId)!==c.sessionId)return;let t=Array.isArray(e.items)?e.items.filter(n=>typeof n=="string"&&n.trim()):[];for(let n of t)ml(n,e.sessionId||c.sessionId);t.length&&C(`\u231B Grok queue \xB7 ${t.length} prompt${t.length===1?"":"s"} waiting`)}function Iu(){let e=i("messages");e&&(e.querySelectorAll(".queued-user-msg").forEach(t=>{t.classList.remove("queued-user-msg"),t.classList.add("cancelled-queued-user-msg")}),Ea.clear())}function hl(e,t,n={}){if(!e||!t||e.querySelector(".msg-actions"))return;let s=`a${++iu}`;fr.set(s,{text:t,historyIndex:Number.isInteger(n.historyIndex)?n.historyIndex:null,sessionId:c.sessionId,agent:c.agent||S.peek()||"claude",machineId:c.machineId||null});let a=!["gemini","cursor"].includes(c.agent||S.peek()||"claude"),o=document.createElement("div");o.className="msg-actions",o.innerHTML=`
|
|
66
|
+
<button type="button" class="msg-action-btn" data-copy-message="${p(s)}" title="Copy answer">Copy</button>
|
|
67
|
+
${a?`<button type="button" class="msg-action-btn" data-fork-message="${p(s)}" title="Start a branch from this answer">Fork</button>`:""}`;let r=e.querySelector(".msg-ts");e.insertBefore(o,r||null)}function Tu(e){let t=i("messages");if(!t)return null;let n=e==="shell-err"?" text-error":"";return t.insertAdjacentHTML("beforeend",`<div class="mx-2 rounded-lg code-surface px-3 py-2 text-sm font-mono${n} whitespace-pre-wrap break-words"></div>`),He(t),t.lastElementChild}function Cu(e,t){e&&(e.textContent+=t,He(e.closest("#messages")))}function Mu(e){let t=typeof e.input=="object"?JSON.stringify(e.input,null,2):String(e.input||""),s=((typeof e.input=="object"?Object.values(e.input).find(a=>typeof a=="string"&&a.trim()):t)||"").replace(/\n/g," ").slice(0,_e.peek()==="full"?120:80);return{inputStr:t,preview:s}}function sl(e,{inBatch:t=!1}={}){let{inputStr:n,preview:s}=Mu(e);return`<div class="tool-card${t?" tool-batch-item":""} cursor-pointer select-none px-2 py-1">
|
|
68
|
+
<div class="flex items-center gap-1.5 text-xs font-mono">
|
|
69
|
+
<span class="text-warning">\u26A1</span>
|
|
70
|
+
<span class="text-warning font-semibold">${p(e.name||"tool")}</span>
|
|
71
|
+
<span class="text-base-content/50 truncate flex-1">${p(s)}</span>
|
|
72
|
+
<span class="tool-chevron text-[10px] text-base-content/40">\u25B6</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="tool-detail">${p(n)}</div>
|
|
75
|
+
</div>`}function Au(e){let t=[...new Set(e.names)],n=t.slice(0,4).join(", ")+(t.length>4?"\u2026":""),s=e.el.querySelector(".tool-batch-summary");s&&(s.innerHTML=`<span class="text-warning">\u26A1</span>
|
|
76
|
+
<span class="font-semibold text-base-content/70">${e.count} tool${e.count===1?"":"s"}</span>
|
|
77
|
+
<span class="text-base-content/40 truncate flex-1">${p(n)}</span>
|
|
78
|
+
<span class="tool-chevron text-[10px] text-base-content/40">\u25B6</span>`)}function pt(){Ye=null}function br(e,t={}){let n=i("messages");if(!n)return;let s=_e.peek()||"normal",a=O(t.ts);if(s==="clean"){if(!Ye||!n.contains(Ye.el)){let u=Ca(a),l=Ma(a);n.insertAdjacentHTML("beforeend",`
|
|
79
|
+
<div class="msg-row assistant px-2" data-ts="${p(l)}">
|
|
80
|
+
<div class="tool-batch w-full max-w-[96%] px-2 py-1.5">
|
|
81
|
+
<div class="tool-batch-summary flex items-center gap-1.5 text-xs font-mono"></div>
|
|
82
|
+
<div class="tool-batch-list"></div>
|
|
83
|
+
</div>
|
|
84
|
+
${u?`<div class="msg-ts" title="${p(l)}">${p(u)}</div>`:""}
|
|
85
|
+
</div>`),Ye={el:n.lastElementChild.querySelector(".tool-batch"),names:[],count:0}}Ye.names.push(e.name||"tool"),Ye.count++,Ye.el.querySelector(".tool-batch-list")?.insertAdjacentHTML("beforeend",sl(e,{inBatch:!0})),Au(Ye),He(n);return}Ye=null;let o=Ca(a),r=Ma(a);n.insertAdjacentHTML("beforeend",`
|
|
86
|
+
<div class="msg-row assistant px-2" data-ts="${p(r)}">
|
|
87
|
+
<div class="w-full max-w-[96%]">${sl(e)}</div>
|
|
88
|
+
${o?`<div class="msg-ts" title="${p(r)}">${p(o)}</div>`:""}
|
|
89
|
+
</div>`),He(n)}function gl(){let e=i("messages");e&&e.setAttribute("data-density",_e.peek()||"normal")}function ju(e){let t=e.request_id||e.requestId;if(!t||i(`perm-${t}`))return;let n=e.tool_input?JSON.stringify(e.tool_input).slice(0,200):"";i("permission-requests")?.insertAdjacentHTML("beforeend",`
|
|
90
|
+
<div id="perm-${t}" class="perm-banner mx-3 mb-2 rounded-lg border border-warning/25 bg-warning/8 p-3">
|
|
91
|
+
<div class="text-xs text-warning font-semibold mb-1">\u26A0\uFE0F Permission Required</div>
|
|
92
|
+
<div class="font-mono text-xs text-base-content/60 break-all mb-2">
|
|
93
|
+
<strong class="text-base-content">${p(e.tool_name||"")}</strong> ${p(n)}
|
|
94
|
+
</div>
|
|
95
|
+
<div class="flex gap-2">
|
|
96
|
+
<button class="btn btn-success btn-xs" data-perm-id="${t}" data-perm-allow="1">Allow</button>
|
|
97
|
+
<button class="btn btn-error btn-xs" data-perm-id="${t}" data-perm-allow="0">Deny</button>
|
|
98
|
+
</div>
|
|
99
|
+
</div>`),He(i("messages"))}function Du(){if(al||typeof marked>"u")return;let e=s=>String(s??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),t=(s,a)=>{let o=String(a||"").trim().split(/\s+/)[0]||"",r=o||"text",d=o?`language-${p(o)}`:"";return`<div class="code-block">
|
|
100
|
+
<div class="code-block-header">
|
|
101
|
+
<span class="code-block-lang">${p(r)}</span>
|
|
102
|
+
<button type="button" class="code-copy" data-copy="1" title="Copy code">Copy</button>
|
|
103
|
+
</div>
|
|
104
|
+
<pre><code class="hljs ${d}">${e(s)}</code></pre>
|
|
105
|
+
</div>`},n={code(s,a){return s&&typeof s=="object"&&s.text!=null?t(s.text,s.lang||a):t(s,a)},table(s,a){return s&&typeof s=="object"&&!Array.isArray(s)&&s.header?!1:`<div class="table-wrap"><table><thead>${s}</thead><tbody>${a}</tbody></table></div>`},html(s){return e(s)}};try{if(typeof marked.use=="function")marked.use({gfm:!0,breaks:!0,renderer:n});else if(typeof marked.setOptions=="function"){let s=new marked.Renderer;s.code=n.code,s.table=n.table,marked.setOptions({gfm:!0,breaks:!0,renderer:s})}}catch(s){console.warn("[md] marked setup failed",s)}al=!0}function La(e){if(typeof marked>"u")return p(e);try{return Du(),Ve(e,{fallback:()=>p(e)})}catch{return p(e)}}function _u(e){!e||typeof hljs>"u"||(e.querySelectorAll("pre code:not(.hljs)").forEach(t=>{try{hljs.highlightElement(t)}catch{}}),e.querySelectorAll("pre code.hljs").forEach(t=>{t.classList.add("hljs")}))}function bl(e){_u(e),xt(e),vt(e)}var on,ys,Bn,ut,kt,ka,el,lr,tl,cr,dr,fr,iu,Ea,ur,Fe,nl,rn,Xe,Ue,Nt,dt,gu,yu,wu,Aa,Ye,al,_a=U(()=>{W();er();F();le();hs();or();ya();_n();Zt();en();ir();_t();_t();on=null;ys=0,Bn=null,ut=1e3,kt=0,ka=null,el=!1,lr=!1,tl=null,cr=!1,dr="hubStreamCursors",fr=new Map,iu=0,Ea=new Set,ur="pendingUserTexts",Fe=(()=>{try{let e=JSON.parse(sessionStorage.getItem(ur)||"[]");return Array.isArray(e)?e.filter(t=>t?.key&&t?.text).slice(-30):[]}catch{return[]}})(),nl=new Set,rn=new Map;Xe=null,Ue=null,Nt=null,dt=null;gu={haiku:"claude-haiku-4-5",sonnet:"claude-sonnet-4-6",opus:"claude-opus-4-5",sonnet4:"claude-sonnet-4-6",haiku4:"claude-haiku-4-5"};yu=200,wu=500;Aa=[];Ye=null;al=!1});function xl(e,t){vl=e,vr=t,window.addEventListener("hashchange",()=>{if(xr){xr=!1;return}wl(location.hash.slice(1)||"/")}),De(Y,n=>{c.sessionId&&Es()})}function yr(e){let[t,n=""]=String(e||"").split("?",2),s=t.match(/^\/session\/([^/]+)(?:\/([^/]+))?$/);if(!s)return null;let a=new URLSearchParams(n);try{return{id:decodeURIComponent(s[1]),tab:s[2]?decodeURIComponent(s[2]):null,machineId:a.get("machine")||null,agent:a.get("agent")||null}}catch{return null}}function yl(){wl(location.hash.slice(1)||"/")}function wl(e){let t=String(e||"").split("?")[0];if(t==="/settings"){document.dispatchEvent(new CustomEvent("router:settings"));return}if(t==="/notes"){document.dispatchEvent(new CustomEvent("router:notes"));return}let n=yr(e);if(!n){document.dispatchEvent(new CustomEvent("router:home"));return}let{id:s,tab:a,machineId:o,agent:r}=n;!vl||!vr||(s!==c.sessionId?document.dispatchEvent(new CustomEvent("router:session",{detail:{id:s,tab:a,machineId:o,agent:r}})):a&&a!==Y.peek()&&vr(a))}function wr(e){xr=!0,location.hash=e}function Es(){if(!c.sessionId)return;let e=new URLSearchParams;c.machineId&&e.set("machine",c.machineId),c.agent&&e.set("agent",c.agent);let t=e.size?`?${e}`:"";wr(`/session/${encodeURIComponent(c.sessionId)}/${encodeURIComponent(Y.peek())}${t}`)}function kl(){if(!c.sessionId)return null;let e=new URL(location.href),t=new URLSearchParams;c.machineId&&t.set("machine",c.machineId),c.agent&&t.set("agent",c.agent);let n=t.size?`?${t}`:"";return e.hash=`/session/${encodeURIComponent(c.sessionId)}/${encodeURIComponent(Y.peek())}${n}`,e.toString()}var Wm,vl,vr,xr,Na=U(()=>{W();F();Wm=$i({"/":()=>{},"/session/*":()=>{},"/session/*/*":()=>{},"*":()=>{}}),vl=null,vr=null,xr=!1});async function Pa(){try{return await Jn.get("sessions")??null}catch{return null}}async function $l(e){try{await Jn.set("sessions",e,{ttl:Nu})}catch{}}async function Sl(){try{return await Jn.get("workspaces")??null}catch{return null}}async function Is(e){try{await Jn.set("workspaces",e,{ttl:3600*1e3})}catch{}}async function Ll(e){try{return Ts(await Jn.get(`transcript:${e}`))}catch{return null}}async function El(e,t){try{await Jn.set(`transcript:${e}`,Ts(t),{ttl:1440*60*1e3})}catch{}}function Ts(e){if(!e?.msgs)return e??null;let t=Math.max(0,e.msgs.length-80);return{...e,msgs:e.msgs.slice(t),meta:{...e.meta,oldestIndex:(e.meta?.oldestIndex||0)+t,truncated:t>0||!!e.meta?.truncated}}}var Jn,Nu,Cs=U(()=>{W();Jn=Si("claude-ui"),Nu=300*1e3});var Cr={};ls(Cr,{closeNotes:()=>_l,initNotes:()=>Tr,openNotes:()=>Ra});function Ra(){Nl();let e=document.getElementById("notes-page");if(!e)return;e.hidden=!1,document.getElementById("welcome")?.classList.add("hidden");let t=document.getElementById("project-view");t&&(t.classList.add("hidden"),t.style.display="none"),document.documentElement.classList.remove("notes-open"),(location.hash||"")!=="#/notes"&&(location.hash="/notes"),un({keepList:!0})}function _l({restore:e=!0}={}){let t=document.getElementById("notes-page");if(!t)return;t.hidden=!0,document.documentElement.classList.remove("notes-open"),Ze=null,St=!1;let n=document.getElementById("notes-add-form");if(n&&(n.hidden=!0),!!e)if(c.sessionId){let s=document.getElementById("project-view");s&&(s.classList.remove("hidden"),s.style.cssText="display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden")}else{let s=document.getElementById("welcome");s&&(s.classList.remove("hidden"),s.style.display="")}}function Nl(){if(Al)return;Al=!0,(document.getElementById("main")||document.getElementById("root")).insertAdjacentHTML("beforeend",Gu()),document.addEventListener("router:notes",()=>Ra()),document.getElementById("notes-page").addEventListener("click",s=>{if(s.target.closest("[data-notes-close]")){_l(),(location.hash||"")==="#/notes"&&history.back();return}let o=s.target.closest("[data-notes-add]");if(o){s.preventDefault(),St=!St;let m=document.getElementById("notes-add-form");m&&(m.hidden=!St),o.textContent=St?"\u6536\u8D77":"+ \u65B0\u589E",St&&document.getElementById("notes-add-text")?.focus();return}if(s.target.closest("[data-notes-submit]")){s.preventDefault(),jl();return}let d=s.target.closest("[data-notes-edit]");if(d){s.preventDefault(),Ku(d.dataset.notesEdit);return}if(s.target.closest("[data-notes-save]")){s.preventDefault(),Ju();return}if(s.target.closest("[data-notes-cancel]")){if(s.preventDefault(),Ze)zu();else{St=!1;let m=document.getElementById("notes-add-form");m&&(m.hidden=!0);let g=document.querySelector("[data-notes-add]");g&&(g.textContent="+ \u65B0\u589E")}return}let f=s.target.closest("[data-notes-remove]");if(f){s.preventDefault();let m=f.dataset.notesRemove;confirm("\u5220\u9664\u8FD9\u6761\u8BB0\u5F55?")&&Pl(m)}});let n=document.getElementById("notes-add-text");n&&n.addEventListener("keydown",s=>{(s.metaKey||s.ctrlKey)&&s.key==="Enter"&&(s.preventDefault(),jl())})}function Gu(){return`
|
|
106
|
+
<section id="notes-page" class="notes-page" hidden>
|
|
107
|
+
<header class="notes-header">
|
|
108
|
+
<div>
|
|
109
|
+
<h2>\u8BB0\u4E8B</h2>
|
|
110
|
+
<p id="notes-count" class="notes-count">\u591A\u7AEF\u5B9E\u65F6\u540C\u6B65</p>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="notes-header-actions">
|
|
113
|
+
<button class="btn btn-sm btn-ghost border border-base-300" data-notes-add>+ \u65B0\u589E</button>
|
|
114
|
+
<button class="btn btn-sm btn-ghost border border-base-300" data-notes-close>\u5173\u95ED</button>
|
|
115
|
+
</div>
|
|
116
|
+
</header>
|
|
117
|
+
<form id="notes-add-form" class="notes-add" hidden>
|
|
118
|
+
<textarea id="notes-add-text" placeholder="\u8BB0\u4E00\u6761\u2026 (Cmd/Ctrl+Enter \u63D0\u4EA4)" rows="3" maxlength="8000"></textarea>
|
|
119
|
+
<div class="notes-form-actions">
|
|
120
|
+
<button class="btn btn-sm btn-primary" data-notes-submit>\u4FDD\u5B58</button>
|
|
121
|
+
<button class="btn btn-sm btn-ghost" type="button" data-notes-cancel>\u53D6\u6D88</button>
|
|
122
|
+
</div>
|
|
123
|
+
</form>
|
|
124
|
+
<ul id="notes-list" class="notes-list">
|
|
125
|
+
<li class="notes-empty">\u52A0\u8F7D\u4E2D\u2026</li>
|
|
126
|
+
</ul>
|
|
127
|
+
</section>`}async function un({keepList:e=!1}={}){let t=document.getElementById("notes-list");if(t){(!e||!dn)&&(t.innerHTML='<li class="notes-empty">\u52A0\u8F7D\u4E2D\u2026</li>');try{dn=(await x("GET","/api/notes?limit=200",void 0,void 0,{hub:!0}))?.items||[],Ir()}catch(n){t.innerHTML=`<li class="notes-empty notes-error">\u52A0\u8F7D\u5931\u8D25:${n?.message||n}</li>`}}}function Ir(){let e=document.getElementById("notes-list");if(!e)return;let t=document.getElementById("notes-count");t&&(t.textContent=dn?.length?`${dn.length} \u6761\u8BB0\u4E8B \xB7 \u591A\u7AEF\u5B9E\u65F6\u540C\u6B65`:"\u591A\u7AEF\u5B9E\u65F6\u540C\u6B65");let n=document.getElementById("notes-add-form");if(n&&(n.hidden=!St),!dn||dn.length===0){e.innerHTML='<li class="notes-empty">\u8FD8\u6CA1\u6709\u8BB0\u4E8B\u3002\u70B9\u4E0A\u9762\u7684\u300C\u65B0\u589E\u300D\uFF0C\u6216\u8005\u5728 Meta Agent \u91CC\u8F93\u5165\u300C\u8BB0: xxx\u300D</li>';return}e.innerHTML="";for(let s of dn){let a=document.createElement("li");a.className="notes-item",a.dataset.id=s.id,Ze===s.id?a.innerHTML=`
|
|
128
|
+
<textarea class="notes-edit-text" rows="4">${Dl(s.text)}</textarea>
|
|
129
|
+
<div class="notes-item-actions">
|
|
130
|
+
<button class="btn btn-sm btn-primary" data-notes-save>\u4FDD\u5B58</button>
|
|
131
|
+
<button class="btn btn-sm btn-ghost" data-notes-cancel>\u53D6\u6D88</button>
|
|
132
|
+
</div>`:a.innerHTML=`
|
|
133
|
+
<div class="notes-text">${Dl(s.text)}</div>
|
|
134
|
+
<div class="notes-item-foot">
|
|
135
|
+
<span class="notes-meta">${Qu(s.createdAt)}</span>
|
|
136
|
+
<div class="notes-item-actions">
|
|
137
|
+
<button class="btn btn-ghost btn-xs" data-notes-edit="${s.id}" title="\u7F16\u8F91">\u7F16\u8F91</button>
|
|
138
|
+
<button class="btn btn-ghost btn-xs text-error" data-notes-remove="${s.id}" title="\u5220\u9664">\u5220\u9664</button>
|
|
139
|
+
</div>
|
|
140
|
+
</div>`,e.appendChild(a)}}function Ku(e){Ze=e,Ir()}function zu(){Ze=null,Ir()}async function Ju(){let e=document.getElementById("notes-list");if(!e)return;let t=e.querySelector(`li[data-id="${Vu(Ze)}"]`);if(!t)return;let n=t.querySelector(".notes-edit-text");if(!n)return;let s=(n.value||"").trim();if(!s){confirm("\u6587\u672C\u4E3A\u7A7A,\u5220\u9664\u8FD9\u6761\u8BB0\u5F55?")&&await Pl(Ze);return}try{await x("PATCH",`/api/notes/${Ze}`,{text:s},void 0,{hub:!0}),Ze=null,await un({keepList:!0})}catch(a){alert("\u4FDD\u5B58\u5931\u8D25:"+(a?.message||a))}}async function jl(){let e=document.getElementById("notes-add-text");if(!e)return;let t=(e.value||"").trim();if(!t){e.focus();return}try{await x("POST","/api/notes",{text:t},void 0,{hub:!0}),e.value="",St=!1;let n=document.getElementById("notes-add-form");n&&(n.hidden=!0);let s=document.querySelector("[data-notes-add]");s&&(s.textContent="+ \u65B0\u589E"),await un({keepList:!0})}catch(n){alert("\u4FDD\u5B58\u5931\u8D25:"+(n?.message||n))}}async function Pl(e){try{await x("DELETE",`/api/notes/${e}`,void 0,void 0,{hub:!0}),Ze===e&&(Ze=null),await un({keepList:!0})}catch(t){alert("\u5220\u9664\u5931\u8D25:"+(t?.message||t))}}function Qu(e){if(!e)return"";let t=new Date(e),n=s=>String(s).padStart(2,"0");return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function Vu(e){return typeof CSS<"u"&&CSS.escape?CSS.escape(e):String(e).replace(/[^a-zA-Z0-9_-]/g,t=>"\\"+t)}function Dl(e){return String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Tr(){Nl()}var dn,Ze,Al,St,As=U(()=>{le();F();dn=null,Ze=null,Al=!1,St=!1;typeof window<"u"&&(window.addEventListener("hub:note-added",()=>{document.getElementById("notes-page")?.hidden||un()}),window.addEventListener("hub:note-updated",()=>{document.getElementById("notes-page")?.hidden||un()}),window.addEventListener("hub:note-removed",()=>{document.getElementById("notes-page")?.hidden||un()}))});function Yn(e){return Ve(e,{fallback:t=>p(t).replace(/\n/g,"<br>")})}function Xn(e){e&&(typeof hljs<"u"&&e.querySelectorAll("pre code").forEach(t=>{try{hljs.highlightElement(t)}catch{}}),xt(e),vt(e))}async function jr(e,t,n){let s=ct({"Content-Type":"application/json"},{hub:!0}),a=await fetch(e,{method:"POST",headers:s,body:JSON.stringify(t||{})});if(!a.ok){let l=await a.json().catch(()=>({}));throw new Error(l.error||`HTTP ${a.status}`)}let o=a.body.getReader(),r=new TextDecoder,d="",u="message";for(;;){let{done:l,value:f}=await o.read();if(l)break;d+=r.decode(f,{stream:!0});let m=d.split(`
|
|
141
|
+
`);d=m.pop()||"";for(let g of m)if(g.startsWith("event:"))u=g.slice(6).trim();else if(g.startsWith("data:")){let w=g.slice(5).trim();if(!w)continue;let y;try{y=JSON.parse(w)}catch{continue}n[u]?.(y),!n[u]&&n.tool&&(u==="tool_call"&&n.tool({name:y.name,args:y.args,id:y.callId,phase:"start"}),u==="tool_result"&&n.tool({id:y.callId,phase:y.ok===!1?"error":"done",result:y.ok===!1?y.error:y.result})),n.any?.(u,y),u="message"}else g.trim()===""&&(u="message")}}function Yu(){return`
|
|
142
|
+
<div id="meta-agent-panel" class="meta-agent-panel hidden" aria-hidden="true">
|
|
143
|
+
<div class="meta-agent-backdrop" data-ma-close="1"></div>
|
|
144
|
+
<div class="meta-agent-sheet">
|
|
145
|
+
<header class="meta-agent-header">
|
|
146
|
+
<div class="flex items-center gap-2 min-w-0">
|
|
147
|
+
<span class="text-base font-bold">\u2726 Meta Agent</span>
|
|
148
|
+
<span class="text-[10px] text-base-content/40 hidden sm:inline">\u62A5\u544A \xB7 \u95EE\u7B54 \xB7 VLM \xB7 \u4EE3\u7801</span>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="flex items-center gap-1">
|
|
151
|
+
<button type="button" id="ma-btn-chat" class="btn btn-xs btn-ghost border border-primary/40 text-primary">\u5BF9\u8BDD</button>
|
|
152
|
+
<button type="button" id="ma-btn-history" class="btn btn-xs btn-ghost border border-base-300" title="\u5386\u53F2\u5BF9\u8BDD">\u5386\u53F2</button>
|
|
153
|
+
<button type="button" id="ma-btn-notes" class="btn btn-xs btn-ghost border border-base-300" title="\u5DE5\u4F5C\u8BB0\u4E8B">\u8BB0\u4E8B</button>
|
|
154
|
+
<button type="button" id="ma-btn-report" class="btn btn-xs btn-ghost border border-base-300">\u62A5\u544A</button>
|
|
155
|
+
<button type="button" id="ma-btn-config" class="btn btn-xs btn-ghost border border-base-300" title="AI \u914D\u7F6E">\u2699</button>
|
|
156
|
+
<button type="button" id="ma-btn-close" class="btn btn-xs btn-ghost" data-ma-close="1">\u2715</button>
|
|
157
|
+
</div>
|
|
158
|
+
</header>
|
|
159
|
+
|
|
160
|
+
<div id="ma-mode-chat" class="meta-agent-body flex flex-col min-h-0 flex-1">
|
|
161
|
+
<div class="flex items-center gap-1 px-2 py-1 border-b border-base-300 flex-shrink-0 overflow-x-auto">
|
|
162
|
+
<button type="button" id="ma-new-chat" class="btn btn-ghost btn-xs">\uFF0B \u65B0\u5BF9\u8BDD</button>
|
|
163
|
+
<button type="button" id="ma-open-history" class="btn btn-ghost btn-xs" title="\u5386\u53F2\u5217\u8868">\u2630 \u5386\u53F2</button>
|
|
164
|
+
<span id="ma-session-title" class="text-[11px] text-base-content/55 truncate flex-1 min-w-0 px-1"></span>
|
|
165
|
+
<button type="button" id="ma-del-session" class="btn btn-ghost btn-xs text-error" title="\u5220\u9664\u5F53\u524D\u4F1A\u8BDD">\u{1F5D1}</button>
|
|
166
|
+
<button type="button" id="ma-quick-today" class="btn btn-ghost btn-xs text-[10px]">\u4ECA\u5929\u505A\u4E86\u5565</button>
|
|
167
|
+
<button type="button" id="ma-quick-projects" class="btn btn-ghost btn-xs text-[10px]">\u9879\u76EE\u6982\u51B5</button>
|
|
168
|
+
</div>
|
|
169
|
+
<div id="ma-resume-bar" class="hidden px-3 py-1.5 border-b border-primary/30 bg-primary/10 text-[11px] flex items-center gap-2 flex-shrink-0">
|
|
170
|
+
<span id="ma-resume-text" class="flex-1 min-w-0 truncate text-base-content/70"></span>
|
|
171
|
+
<button type="button" id="ma-resume-focus" class="btn btn-primary btn-xs">\u7EE7\u7EED\u804A</button>
|
|
172
|
+
</div>
|
|
173
|
+
<div id="ma-messages" class="flex-1 overflow-y-auto p-3 flex flex-col gap-2"></div>
|
|
174
|
+
<div id="ma-attach-bar" class="hidden px-3 pt-1 flex flex-wrap gap-1"></div>
|
|
175
|
+
<div class="flex gap-2 items-end px-3 py-2 border-t border-base-300 bg-base-200 flex-shrink-0">
|
|
176
|
+
<label class="btn btn-ghost btn-sm px-2 cursor-pointer" title="\u6DFB\u52A0\u56FE\u7247 (VLM)" style="height:40px">
|
|
177
|
+
\u{1F5BC}
|
|
178
|
+
<input type="file" id="ma-image-input" accept="image/*" multiple class="hidden">
|
|
179
|
+
</label>
|
|
180
|
+
<textarea id="ma-input" rows="1" placeholder="\u7EE7\u7EED\u63D0\u95EE\u2026 (\u2318\u21B5 \u53D1\u9001) \xB7 \u5386\u53F2\u4F1A\u8BDD\u4F1A\u5E26\u7740\u4E0A\u4E0B\u6587"
|
|
181
|
+
class="textarea textarea-bordered flex-1 text-sm resize-none leading-relaxed"
|
|
182
|
+
style="min-height:40px;max-height:120px"
|
|
183
|
+
name="meta-agent-message"
|
|
184
|
+
autocomplete="off"
|
|
185
|
+
autocorrect="off"
|
|
186
|
+
autocapitalize="off"
|
|
187
|
+
spellcheck="false"
|
|
188
|
+
data-1p-ignore="true"
|
|
189
|
+
data-lpignore="true"
|
|
190
|
+
data-form-type="other"
|
|
191
|
+
data-bwignore="true"></textarea>
|
|
192
|
+
<button type="button" id="ma-send" class="btn btn-primary btn-sm" style="height:40px">\u53D1\u9001</button>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div id="ma-mode-history" class="meta-agent-body hidden flex-col min-h-0 flex-1">
|
|
197
|
+
<div class="flex items-center gap-2 px-3 py-2 border-b border-base-300 flex-shrink-0">
|
|
198
|
+
<input id="ma-history-search" type="search" placeholder="\u641C\u7D22\u6807\u9898 / \u9884\u89C8\u2026"
|
|
199
|
+
class="input input-xs input-bordered flex-1 text-xs" autocomplete="off">
|
|
200
|
+
<button type="button" id="ma-history-refresh" class="btn btn-ghost btn-xs">\u21BB</button>
|
|
201
|
+
<button type="button" id="ma-history-new" class="btn btn-primary btn-xs">\uFF0B \u65B0\u5BF9\u8BDD</button>
|
|
202
|
+
</div>
|
|
203
|
+
<div id="ma-history-list" class="flex-1 overflow-y-auto p-2 flex flex-col gap-1"></div>
|
|
204
|
+
<p class="text-[10px] text-base-content/40 px-3 py-2 border-t border-base-300 flex-shrink-0">
|
|
205
|
+
\u70B9\u51FB\u4F1A\u8BDD\u53EF\u67E5\u770B\u5B8C\u6574\u8BB0\u5F55\uFF1B\u53D1\u9001\u65B0\u6D88\u606F\u5373 resume\uFF08\u4FDD\u7559 tool / VLM \u4E0A\u4E0B\u6587\uFF09\u3002
|
|
206
|
+
</p>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<div id="ma-mode-notes" class="meta-agent-body hidden flex min-h-0 flex-1">
|
|
210
|
+
<div class="w-[44%] min-w-[180px] max-w-[240px] border-r border-base-300 flex flex-col">
|
|
211
|
+
<div class="flex items-center gap-2 px-3 py-2 border-b border-base-300 flex-shrink-0">
|
|
212
|
+
<input id="ma-notes-search" type="search" placeholder="\u641C\u7D22\u8BB0\u4E8B\u2026"
|
|
213
|
+
class="input input-xs input-bordered flex-1 text-xs" autocomplete="off">
|
|
214
|
+
<button type="button" id="ma-notes-refresh" class="btn btn-ghost btn-xs">\u21BB</button>
|
|
215
|
+
<button type="button" id="ma-notes-new" class="btn btn-primary btn-xs">\uFF0B</button>
|
|
216
|
+
</div>
|
|
217
|
+
<div id="ma-notes-list" class="flex-1 overflow-y-auto p-2 flex flex-col gap-1"></div>
|
|
218
|
+
</div>
|
|
219
|
+
<div class="flex-1 min-w-0 flex flex-col">
|
|
220
|
+
<div class="px-3 py-2 border-b border-base-300 text-[11px] text-base-content/45 flex items-center gap-2 flex-wrap">
|
|
221
|
+
<span>\u8BB0\u4E8B\u4FDD\u5B58\u5728 Hub\uFF0C\u53EF\u88AB Meta Agent \u68C0\u7D22\u3002</span>
|
|
222
|
+
<span id="ma-note-links" class="truncate"></span>
|
|
223
|
+
</div>
|
|
224
|
+
<div class="p-3 flex flex-col gap-3 flex-1 overflow-y-auto">
|
|
225
|
+
<label class="form-control">
|
|
226
|
+
<span class="label-text text-xs">\u6807\u9898</span>
|
|
227
|
+
<input id="ma-note-title" class="input input-sm input-bordered text-sm" placeholder="\u4F8B\u5982\uFF1A\u53D1\u5E03\u524D\u9057\u7559\u95EE\u9898">
|
|
228
|
+
</label>
|
|
229
|
+
<label class="form-control flex-1">
|
|
230
|
+
<span class="label-text text-xs">\u5185\u5BB9</span>
|
|
231
|
+
<textarea id="ma-note-content" class="textarea textarea-bordered text-sm min-h-[220px]" placeholder="\u8BB0\u5F55\u51B3\u7B56\u3001\u98CE\u9669\u3001\u5F85\u529E\u3001\u6392\u67E5\u7EBF\u7D22\u2026"></textarea>
|
|
232
|
+
</label>
|
|
233
|
+
<div class="flex flex-wrap items-center gap-3 text-xs">
|
|
234
|
+
<label class="flex items-center gap-1 cursor-pointer">
|
|
235
|
+
<input type="checkbox" id="ma-note-pin" class="checkbox checkbox-xs">
|
|
236
|
+
\u7F6E\u9876
|
|
237
|
+
</label>
|
|
238
|
+
<label class="flex items-center gap-1 cursor-pointer">
|
|
239
|
+
<input type="checkbox" id="ma-note-link-project" class="checkbox checkbox-xs">
|
|
240
|
+
\u5173\u8054\u5F53\u524D\u9879\u76EE
|
|
241
|
+
</label>
|
|
242
|
+
<label class="flex items-center gap-1 cursor-pointer">
|
|
243
|
+
<input type="checkbox" id="ma-note-link-session" class="checkbox checkbox-xs">
|
|
244
|
+
\u5173\u8054\u5F53\u524D session
|
|
245
|
+
</label>
|
|
246
|
+
</div>
|
|
247
|
+
<div class="flex items-center justify-between gap-2">
|
|
248
|
+
<span id="ma-note-status" class="text-xs text-base-content/45"></span>
|
|
249
|
+
<div class="flex items-center gap-2">
|
|
250
|
+
<button type="button" id="ma-note-ask" class="btn btn-ghost btn-sm">\u5FEB\u6377\u63D0\u95EE</button>
|
|
251
|
+
<button type="button" id="ma-note-delete" class="btn btn-ghost btn-sm text-error">\u5220\u9664</button>
|
|
252
|
+
<button type="button" id="ma-note-save" class="btn btn-primary btn-sm">\u4FDD\u5B58\u8BB0\u4E8B</button>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<div id="ma-mode-report" class="meta-agent-body hidden flex-col min-h-0 flex-1">
|
|
260
|
+
<div class="flex items-center gap-2 px-3 py-2 border-b border-base-300 flex-shrink-0 flex-wrap">
|
|
261
|
+
<select id="ma-report-days" class="select select-xs select-bordered">
|
|
262
|
+
<option value="1">\u4ECA\u5929</option>
|
|
263
|
+
<option value="3">\u8FD1 3 \u5929</option>
|
|
264
|
+
<option value="7">\u8FD1 7 \u5929</option>
|
|
265
|
+
</select>
|
|
266
|
+
<button type="button" id="ma-gen-report" class="btn btn-primary btn-xs">\u751F\u6210\u62A5\u544A</button>
|
|
267
|
+
<button type="button" id="ma-load-reports" class="btn btn-ghost btn-xs">\u5386\u53F2</button>
|
|
268
|
+
<label class="flex items-center gap-1 text-[11px] ml-auto cursor-pointer select-none">
|
|
269
|
+
<input type="checkbox" id="ma-auto-report" class="checkbox checkbox-xs">
|
|
270
|
+
\u81EA\u52A8\u65E5\u62A5
|
|
271
|
+
</label>
|
|
272
|
+
<select id="ma-auto-hour" class="select select-xs select-bordered w-16" title="\u81EA\u52A8\u751F\u6210\u65F6\u523B">
|
|
273
|
+
${Array.from({length:24},(e,t)=>`<option value="${t}">${String(t).padStart(2,"0")}:00</option>`).join("")}
|
|
274
|
+
</select>
|
|
275
|
+
</div>
|
|
276
|
+
<div id="ma-report-list" class="hidden border-b border-base-300 max-h-28 overflow-y-auto px-2 py-1"></div>
|
|
277
|
+
<div id="ma-report-body" class="flex-1 overflow-y-auto p-4">
|
|
278
|
+
<div class="text-sm text-base-content/45 text-center py-10">
|
|
279
|
+
\u70B9\u51FB\u300C\u751F\u6210\u62A5\u544A\u300D\u6C47\u603B\u4F1A\u8BDD\u4E0E\u9879\u76EE\u6D3B\u52A8\uFF0C\u6216\u5728\u5BF9\u8BDD\u91CC\u95EE\u300C\u6211\u4ECA\u5929\u505A\u4E86\u4EC0\u4E48\u300D\u3002
|
|
280
|
+
</div>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<div id="ma-mode-config" class="meta-agent-body hidden flex-col min-h-0 flex-1 overflow-y-auto p-4 gap-3">
|
|
285
|
+
<p class="text-xs text-base-content/50">OpenAI \u517C\u5BB9 API\uFF08DeepSeek / OpenAI / \u672C\u5730\u7F51\u5173\u7B49\uFF09\u3002Key \u4FDD\u5B58\u5728\u670D\u52A1\u7AEF <code>.ai_config.json</code>\u3002</p>
|
|
286
|
+
<label class="form-control">
|
|
287
|
+
<span class="label-text text-xs">API URL</span>
|
|
288
|
+
<input id="ma-cfg-url" class="input input-sm input-bordered font-mono text-xs" placeholder="https://api.deepseek.com/chat/completions">
|
|
289
|
+
</label>
|
|
290
|
+
<label class="form-control">
|
|
291
|
+
<span class="label-text text-xs">API Key</span>
|
|
292
|
+
<input id="ma-cfg-key" type="password" class="input input-sm input-bordered" placeholder="\u7559\u7A7A\u5219\u4E0D\u4FEE\u6539">
|
|
293
|
+
</label>
|
|
294
|
+
<label class="form-control">
|
|
295
|
+
<span class="label-text text-xs">\u4E3B\u6A21\u578B</span>
|
|
296
|
+
<input id="ma-cfg-model" class="input input-sm input-bordered font-mono text-xs" placeholder="deepseek-chat">
|
|
297
|
+
</label>
|
|
298
|
+
<div class="divider text-xs my-1">VLM \u591A\u6A21\u6001\uFF08\u53EF\u7559\u7A7A\u5171\u7528\u4E0A\u65B9\uFF09</div>
|
|
299
|
+
<label class="form-control">
|
|
300
|
+
<span class="label-text text-xs">VLM URL</span>
|
|
301
|
+
<input id="ma-cfg-vlm-url" class="input input-sm input-bordered font-mono text-xs" placeholder="\u53EF\u9009">
|
|
302
|
+
</label>
|
|
303
|
+
<label class="form-control">
|
|
304
|
+
<span class="label-text text-xs">VLM Key</span>
|
|
305
|
+
<input id="ma-cfg-vlm-key" type="password" class="input input-sm input-bordered" placeholder="\u53EF\u9009">
|
|
306
|
+
</label>
|
|
307
|
+
<label class="form-control">
|
|
308
|
+
<span class="label-text text-xs">VLM \u6A21\u578B</span>
|
|
309
|
+
<input id="ma-cfg-vlm-model" class="input input-sm input-bordered font-mono text-xs" placeholder="gpt-4o-mini / \u2026">
|
|
310
|
+
</label>
|
|
311
|
+
<label class="form-control">
|
|
312
|
+
<span class="label-text text-xs">System Prompt</span>
|
|
313
|
+
<textarea id="ma-cfg-system" class="textarea textarea-bordered textarea-sm text-xs min-h-[80px]"></textarea>
|
|
314
|
+
</label>
|
|
315
|
+
<div class="flex gap-2">
|
|
316
|
+
<button type="button" id="ma-cfg-save" class="btn btn-primary btn-sm">\u4FDD\u5B58</button>
|
|
317
|
+
<span id="ma-cfg-status" class="text-xs text-base-content/50 self-center"></span>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>`}function Te(e){qt=e;let t=i("ma-mode-chat"),n=i("ma-mode-history"),s=i("ma-mode-notes"),a=i("ma-mode-report"),o=i("ma-mode-config");for(let[d,u]of[[t,"chat"],[n,"history"],[s,"notes"],[a,"report"],[o,"config"]]){if(!d)continue;let l=e===u;d.classList.toggle("hidden",!l),d.classList.toggle("flex",l)}let r=(d,u)=>{let l=i(d);l&&(l.classList.toggle("border-primary/40",u),l.classList.toggle("text-primary",u))};r("ma-btn-chat",e==="chat"),r("ma-btn-history",e==="history"),r("ma-btn-notes",e==="notes"),r("ma-btn-report",e==="report"),e==="history"&&hn(),e==="notes"&&fn()}function Ds(){let e=i("ma-session-title"),t=i("ma-resume-bar"),n=i("ma-resume-text");if(!we){e&&(e.textContent="\u65B0\u5BF9\u8BDD"),t?.classList.add("hidden");return}let s=qe?.title||we.slice(0,8),a=Ga(qe?.updatedAt);if(e&&(e.textContent=a?`${s} \xB7 ${a}`:s),t&&n){t.classList.remove("hidden");let o=qe?.messageCount;n.textContent=o?`\u5DF2\u52A0\u8F7D\u5386\u53F2 \xB7 ${o} \u6761\u6D88\u606F \xB7 \u53D1\u9001\u5373\u53EF\u7EE7\u7EED`:"\u5DF2\u52A0\u8F7D\u5386\u53F2\u4F1A\u8BDD \xB7 \u53D1\u9001\u5373\u53EF\u7EE7\u7EED"}}function Dr(e="chat"){let t=i("meta-agent-panel");if(t){if(t.classList.remove("hidden"),t.setAttribute("aria-hidden","false"),Wa=!0,Te(e),e==="chat"){Lt();let n=localStorage.getItem(Rt);!we&&n?Et(n,{silent:!0}).catch(()=>{localStorage.removeItem(Rt)}):Ds()}e==="history"&&Lt().then(()=>hn()),e==="report"&&Jl(),e==="config"&&Ql(),setTimeout(()=>{qt==="chat"&&i("ma-input")?.focus(),qt==="history"&&i("ma-history-search")?.focus()},50)}}function Wl(){let e=i("meta-agent-panel");e&&(e.classList.add("hidden"),e.setAttribute("aria-hidden","true"),Wa=!1)}function Gl(){Wa?Wl():Dr(qt==="config"?"chat":qt)}function ee(e,t,n={}){let s=i("ma-messages");if(!s)return null;let a=document.createElement("div");return a.className=`ma-msg ma-msg-${e}`,e==="user"?a.innerHTML=`<div class="ma-bubble user">${p(t)}</div>`:e==="assistant"?(a.innerHTML=`<div class="ma-bubble assistant md">${Yn(t)}</div>`,Xn(a)):e==="reasoning"?(a.innerHTML='<details class="ma-reasoning" open><summary>\u601D\u8003\u8FC7\u7A0B</summary><pre style="white-space:pre-wrap"></pre></details>',a.querySelector("pre").textContent=t):e==="error"?a.innerHTML=`<div class="ma-bubble error">${p(t)}</div>`:e==="system"?a.innerHTML=`<div class="ma-sys">${p(t)}</div>`:e==="tool"&&(a.innerHTML=`<details class="ma-tool" data-tool-id="${p(n.id||"")}">
|
|
322
|
+
<summary><span class="ma-tool-name">${p(n.name||"tool")}</span>
|
|
323
|
+
<span class="ma-tool-phase">${p(n.phase||"")}</span></summary>
|
|
324
|
+
<pre class="ma-tool-args" style="white-space:pre-wrap">${p(JSON.stringify(n.args||{},null,2))}</pre>
|
|
325
|
+
</details>`),s.appendChild(a),s.scrollTop=s.scrollHeight,a}function ql(e,t){let n=e?.querySelector(".ma-bubble");n&&(n.innerHTML=Yn(t),Xn(n),i("ma-messages").scrollTop=i("ma-messages").scrollHeight)}function Ar(e,t,n){let s=i("ma-messages");if(!s)return;let a=s.querySelector(`[data-tool-id="${CSS.escape(e)}"]`);if(!a)return;a.classList.toggle("done",t==="done"),a.classList.toggle("error",t==="error");let o=a.querySelector(".ma-tool-phase");if(o&&(o.textContent=t),n!==void 0&&t!=="start"){let r=a.querySelector(".ma-tool-result");r||(r=document.createElement("pre"),r.className="ma-tool-result",r.style.whiteSpace="pre-wrap",a.appendChild(r)),r.textContent=JSON.stringify(n,null,2)}}function Xu(e){let t=i("ma-messages");if(!t)return;let n=document.createElement("div");n.className="ma-approval",n.dataset.approvalId=e.id;let s=e.args?.command??"";n.innerHTML=`
|
|
326
|
+
<div class="ma-approval-label">\u26A0 Agent \u60F3\u8981\u6267\u884C\u547D\u4EE4\uFF0C\u662F\u5426\u5141\u8BB8\uFF1F</div>
|
|
327
|
+
<pre class="ma-approval-cmd">${p(s)}</pre>
|
|
328
|
+
<div class="ma-approval-actions">
|
|
329
|
+
<button type="button" class="btn btn-xs btn-error" data-approve="0">\u62D2\u7EDD</button>
|
|
330
|
+
<button type="button" class="btn btn-xs btn-success" data-approve="1">\u5141\u8BB8\u6267\u884C</button>
|
|
331
|
+
</div>`,n.querySelectorAll("[data-approve]").forEach(a=>{a.addEventListener("click",async()=>{let o=a.dataset.approve==="1";n.querySelectorAll("button").forEach(r=>{r.disabled=!0}),n.querySelector(".ma-approval-label").textContent=o?"\u2713 \u5DF2\u5141\u8BB8\uFF0C\u6B63\u5728\u6267\u884C\u2026":"\u2717 \u5DF2\u62D2\u7EDD";try{await x("POST","/api/ai/approve",{id:e.id,approved:o})}catch(r){n.querySelector(".ma-approval-label").textContent=`\u786E\u8BA4\u5931\u8D25\uFF1A${r.message}`}})}),t.appendChild(n),t.scrollTop=t.scrollHeight}function Zu(){return Hl+=1,`img${Hl}`}function ep(e,t){if(!e)return;let n=e.selectionStart??e.value.length,s=e.selectionEnd??e.value.length;e.value=e.value.slice(0,n)+t+e.value.slice(s),e.selectionStart=e.selectionEnd=n+t.length,e.dispatchEvent(new Event("input"))}async function Rl(e,t){let n=ct({"x-filename":t||`paste-${Date.now()}.png`},{hub:!0});delete n["Content-Type"];let s=await fetch("/api/upload-image",{method:"POST",headers:n,body:e});if(!s.ok){let l=await s.json().catch(()=>({}));throw new Error(l.error||`Upload failed: ${s.status}`)}let{path:a}=await s.json();if(!a)throw new Error("upload returned no path");let o=Zu(),r=`[${o}](${a})`,d=i("ma-input");ep(d,(d?.value&&!d.value.endsWith(`
|
|
332
|
+
`)&&d.value.length?`
|
|
333
|
+
`:"")+r+`
|
|
334
|
+
`);let u="";try{u=URL.createObjectURL(e)}catch{}return pn.push({path:a,previewUrl:u,label:o,ref:r}),_r(),{path:a,ref:r,label:o}}function _r(){let e=i("ma-attach-bar");if(e){if(!pn.length){e.classList.add("hidden"),e.innerHTML="";return}e.classList.remove("hidden"),e.innerHTML=pn.map((t,n)=>`
|
|
335
|
+
<div class="ma-thumb relative" title="${p(t.ref||t.path)}">
|
|
336
|
+
${t.previewUrl?`<img src="${t.previewUrl}" alt="${p(t.label||"img")}">`:`<span class="ma-thumb-path">${p(t.label||"img")}</span>`}
|
|
337
|
+
<span class="ma-thumb-label">${p(t.label||"")}</span>
|
|
338
|
+
<button type="button" class="ma-thumb-x" data-rm-img="${n}">\u2715</button>
|
|
339
|
+
</div>`).join(""),e.querySelectorAll("[data-rm-img]").forEach(t=>{t.addEventListener("click",()=>{let n=parseInt(t.dataset.rmImg,10),s=pn[n];if(s?.previewUrl)try{URL.revokeObjectURL(s.previewUrl)}catch{}let a=i("ma-input");a&&s?.ref&&(a.value=a.value.split(s.ref).join("").replace(/\n{3,}/g,`
|
|
340
|
+
|
|
341
|
+
`),a.dispatchEvent(new Event("input"))),pn.splice(n,1),_r()})})}}function Ga(e){if(!e)return"";let t=new Date(e);if(Number.isNaN(t.getTime()))return"";let n=String(t.getMonth()+1).padStart(2,"0"),s=String(t.getDate()).padStart(2,"0"),a=String(t.getHours()).padStart(2,"0"),o=String(t.getMinutes()).padStart(2,"0");return`${n}-${s} ${a}:${o}`}async function Lt(){try{Ua=(await x("GET","/api/ai/sessions")).sessions||[]}catch{Ua=[]}return Ua}function Kl(){let e=E.peek(),t=c.sessionId?`${c.agent||S.peek()||"claude"}:${c.sessionId.slice(0,8)}`:"";return{project:e?.path||"",sessionId:c.sessionId||"",agent:c.agent||S.peek()||"claude",summary:[e?.name?`\u9879\u76EE ${e.name}`:"",t?`\u4F1A\u8BDD ${t}`:""].filter(Boolean).join(" \xB7 ")}}function js(){mn=null,Fl=null,i("ma-note-title").value="",i("ma-note-content").value="",i("ma-note-pin").checked=!1,i("ma-note-link-project").checked=!!E.peek()?.path,i("ma-note-link-session").checked=!!c.sessionId,i("ma-note-status").textContent="\u65B0\u8BB0\u4E8B",i("ma-note-delete").disabled=!0,i("ma-note-links").textContent=Kl().summary||"\u672A\u5173\u8054\u4E0A\u4E0B\u6587"}function zl(e){mn=e?.id||null,Fl=e||null,i("ma-note-title").value=e?.title||"",i("ma-note-content").value=e?.content||"",i("ma-note-pin").checked=!!e?.pinned,i("ma-note-link-project").checked=!!e?.cwd,i("ma-note-link-session").checked=!!e?.sessionId,i("ma-note-status").textContent=e?.updatedAt?`\u4E0A\u6B21\u66F4\u65B0 ${Ga(e.updatedAt)}`:"",i("ma-note-delete").disabled=!e?.id;let t=[];e?.cwd&&t.push(`\u9879\u76EE ${e.cwd.split("/").pop()}`),e?.sessionId&&t.push(`\u4F1A\u8BDD ${e.agent||"claude"}:${e.sessionId.slice(0,8)}`),i("ma-note-links").textContent=t.join(" \xB7 ")||"\u672A\u5173\u8054\u4E0A\u4E0B\u6587"}function tp(){let e=i("ma-note-title")?.value?.trim()||"",t=i("ma-note-content")?.value?.trim()||"";if(!e&&!t){i("ma-note-status").textContent="\u5148\u9009\u4E00\u6761\u8BB0\u4E8B\u6216\u8F93\u5165\u5185\u5BB9";return}let n=[];i("ma-note-link-project")?.checked&&E.peek()?.path&&n.push(`\u9879\u76EE\u8DEF\u5F84\uFF1A${E.peek().path}`),i("ma-note-link-session")?.checked&&c.sessionId&&n.push(`\u5173\u8054\u4F1A\u8BDD\uFF1A${c.agent||S.peek()||"claude"} / ${c.sessionId}`);let s=["\u57FA\u4E8E\u4E0B\u9762\u8FD9\u6761\u5DE5\u4F5C\u8BB0\u4E8B\u56DE\u7B54\uFF0C\u5E76\u7ED3\u5408\u76F8\u5173\u4F1A\u8BDD\u4E0E\u9879\u76EE\u4E0A\u4E0B\u6587\uFF1A",`\u6807\u9898\uFF1A${e||"\u672A\u547D\u540D"}`,t?`\u5185\u5BB9\uFF1A
|
|
342
|
+
${t}`:"",n.length?n.join(`
|
|
343
|
+
`):"","","\u8BF7\u5148\u603B\u7ED3\u8FD9\u6761\u8BB0\u4E8B\u7684\u6838\u5FC3\uFF0C\u518D\u7ED9\u51FA\u4E0B\u4E00\u6B65\u5EFA\u8BAE\u548C\u53EF\u80FD\u98CE\u9669\u3002"].filter(Boolean).join(`
|
|
344
|
+
`);Te("chat"),i("ma-input").value=s,i("ma-input").dispatchEvent(new Event("input")),i("ma-input").focus()}async function Vn(){let e=(Ul||"").trim();return Fa=(await x("GET",`/api/ai/notes?limit=80${e?`&q=${encodeURIComponent(e)}`:""}`)).notes||[],Fa}function fn(){let e=i("ma-notes-list");if(e){if(!Fa.length){e.innerHTML='<div class="text-center text-xs text-base-content/40 py-10">\u8FD8\u6CA1\u6709\u8BB0\u4E8B\u3002</div>';return}e.innerHTML=Fa.map(t=>{let n=t.id===mn,s=[t.scope==="project"?"\u9879\u76EE":t.scope==="session"?"\u4F1A\u8BDD":"\u901A\u7528",t.pinned?"\u7F6E\u9876":""].filter(Boolean).join(" \xB7 ");return`
|
|
345
|
+
<button type="button" class="ma-note-item ${n?"active":""}" data-note-id="${p(t.id)}">
|
|
346
|
+
<div class="text-left">
|
|
347
|
+
<div class="font-medium text-xs truncate">${p(t.title||"\u672A\u547D\u540D")}</div>
|
|
348
|
+
<div class="text-[10px] text-base-content/45 mt-0.5 line-clamp-2">${p(t.content||"")}</div>
|
|
349
|
+
<div class="text-[10px] text-base-content/35 mt-1">${p(s)}${s?" \xB7 ":""}${p(Ga(t.updatedAt)||"")}</div>
|
|
350
|
+
</div>
|
|
351
|
+
</button>`}).join(""),e.querySelectorAll("[data-note-id]").forEach(t=>{t.addEventListener("click",async()=>{try{let n=await x("GET",`/api/ai/notes/${t.dataset.noteId}`);zl(n),fn()}catch(n){i("ma-note-status").textContent=n.message}})})}}async function np(){let e=i("ma-note-title")?.value?.trim()||"",t=i("ma-note-content")?.value?.trim()||"";if(!e||!t){i("ma-note-status").textContent="\u6807\u9898\u548C\u5185\u5BB9\u90FD\u4E0D\u80FD\u4E3A\u7A7A";return}let n=Kl(),s={id:mn||void 0,title:e,content:t,pinned:!!i("ma-note-pin")?.checked,cwd:i("ma-note-link-project")?.checked?n.project:"",sessionId:i("ma-note-link-session")?.checked?n.sessionId:"",agent:i("ma-note-link-session")?.checked?n.agent:""};i("ma-note-status").textContent="\u4FDD\u5B58\u4E2D\u2026";let a=await x("POST","/api/ai/notes",s);zl(a),await Vn(),fn()}async function sp(){if(!mn){js();return}confirm("\u5220\u9664\u8FD9\u6761\u8BB0\u4E8B\uFF1F\u4E0D\u53EF\u6062\u590D\u3002")&&(await x("DELETE",`/api/ai/notes/${mn}`),js(),await Vn(),fn())}function hn(){let e=i("ma-history-list");if(!e)return;let t=(Ol||"").trim().toLowerCase(),n=Ua;if(t&&(n=n.filter(s=>`${s.title||""} ${s.preview||""} ${s.id||""}`.toLowerCase().includes(t))),!n.length){e.innerHTML=`<div class="text-center text-xs text-base-content/40 py-10">
|
|
352
|
+
${t?"\u6CA1\u6709\u5339\u914D\u7684\u4F1A\u8BDD":"\u8FD8\u6CA1\u6709\u5386\u53F2\u5BF9\u8BDD\u3002\u53D1\u4E00\u6761\u6D88\u606F\u540E\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u3002"}
|
|
353
|
+
</div>`;return}e.innerHTML=n.map(s=>{let a=s.id===we,o=Ga(s.updatedAt)||"",r=s.messageCount||0;return`
|
|
354
|
+
<div class="ma-hist-item ${a?"active":""}" data-hist-id="${p(s.id)}">
|
|
355
|
+
<div class="flex items-start gap-2">
|
|
356
|
+
<button type="button" class="ma-hist-open flex-1 min-w-0 text-left" data-hist-open="${p(s.id)}">
|
|
357
|
+
<div class="font-medium text-xs truncate">${p(s.title||s.id.slice(0,8))}</div>
|
|
358
|
+
<div class="text-[10px] text-base-content/45 mt-0.5 line-clamp-2">${p(s.preview||"\uFF08\u65E0\u9884\u89C8\uFF09")}</div>
|
|
359
|
+
<div class="text-[10px] text-base-content/35 mt-1">${p(o)}${r?` \xB7 ${r} \u6761`:""}${a?" \xB7 \u5F53\u524D":""}</div>
|
|
360
|
+
</button>
|
|
361
|
+
<div class="flex flex-col gap-0.5 flex-shrink-0">
|
|
362
|
+
<button type="button" class="btn btn-ghost btn-xs px-1" data-hist-resume="${p(s.id)}" title="\u6253\u5F00\u5E76\u7EE7\u7EED">\u21B5</button>
|
|
363
|
+
<button type="button" class="btn btn-ghost btn-xs px-1 text-error" data-hist-del="${p(s.id)}" title="\u5220\u9664">\u2715</button>
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</div>`}).join(""),e.querySelectorAll("[data-hist-open]").forEach(s=>{s.addEventListener("click",async()=>{await Et(s.dataset.histOpen),Te("chat"),i("ma-input")?.focus()})}),e.querySelectorAll("[data-hist-resume]").forEach(s=>{s.addEventListener("click",async a=>{a.stopPropagation(),await Et(s.dataset.histResume),Te("chat"),i("ma-input")?.focus()})}),e.querySelectorAll("[data-hist-del]").forEach(s=>{s.addEventListener("click",async a=>{a.stopPropagation();let o=s.dataset.histDel;if(confirm("\u5220\u9664\u8BE5\u5386\u53F2\u4F1A\u8BDD\uFF1F\u4E0D\u53EF\u6062\u590D\u3002"))try{await x("DELETE",`/api/ai/sessions/${o}`),we===o&&(we=null,qe=null,localStorage.removeItem(Rt),Et(null)),await Lt(),hn()}catch(r){alert(r.message)}})})}function Bl(e){return typeof e=="string"?e:Array.isArray(e)&&e.map(t=>typeof t=="string"?t:t?.type==="text"?t.text||"":t?.type==="image_url"?"[\u56FE\u7247]":"").filter(Boolean).join(`
|
|
367
|
+
`)||"[\u2026]"}function ap(e){let t=i("ma-messages");if(t){if(t.innerHTML="",!e?.length){ee("system","\u6B64\u4F1A\u8BDD\u6682\u65E0\u6D88\u606F\u3002");return}for(let n of e){if(n.role==="user"){ee("user",Bl(n.content));continue}if(n.role==="assistant"){if(n.reasoning&&(ee("reasoning",n.reasoning).querySelector("details").open=!1),n.content&&ee("assistant",typeof n.content=="string"?n.content:Bl(n.content)),n.tool_calls?.length)for(let s of n.tool_calls){let a=s.function?.name||s.name||"tool",o={};try{o=JSON.parse(s.function?.arguments||s.arguments||"{}")}catch{}ee("tool","",{name:a,args:o,phase:"history",id:s.id||a})}continue}if(n.role==="tool"){let s=n.content;try{s=JSON.parse(n.content)}catch{}let a=n.tool_call_id||"";if(a)Ar(a,typeof s=="string"&&s.startsWith("error:")?"error":"done",s);else{ee("tool","",{name:"tool_result",args:{},phase:"done",id:`tr_${Math.random().toString(36).slice(2,8)}`});let o=t.querySelectorAll(".ma-tool"),r=o[o.length-1];if(r){r.classList.add("done");let d=r.querySelector(".ma-tool-result");d||(d=document.createElement("pre"),d.className="ma-tool-result",d.style.whiteSpace="pre-wrap",r.appendChild(d)),d.textContent=typeof s=="string"?s.slice(0,500):JSON.stringify(s,null,2)}}}}t.scrollTop=t.scrollHeight}}async function op(){if(!we){await Et(null);return}if(confirm("\u5220\u9664\u5F53\u524D Meta Agent \u4F1A\u8BDD\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u6062\u590D\u3002"))try{await x("DELETE",`/api/ai/sessions/${we}`),we=null,qe=null,localStorage.removeItem(Rt),await Lt(),await Et(null),qt==="history"&&hn()}catch(e){ee("error",e.message)}}async function Et(e,t={}){if(!e){we=null,qe=null,localStorage.removeItem(Rt);let n=i("ma-messages");return n&&(n.innerHTML=""),ee("system","\u65B0\u5BF9\u8BDD \u2014 \u8D34\u56FE \u2192 [imgN](\u8DEF\u5F84)\uFF1B\u9700\u8981\u770B\u56FE\u65F6\u8C03\u7528 VLM\u3002\u5386\u53F2\u5728\u300C\u5386\u53F2\u300D\u9875\uFF0C\u53EF\u968F\u65F6 resume\u3002"),Ds(),null}try{let n=await x("GET",`/api/ai/sessions/${e}`);return we=n.id,qe={id:n.id,title:n.title,updatedAt:n.updatedAt,messageCount:(n.messages||[]).length},localStorage.setItem(Rt,n.id),ap(n.messages||[]),t.silent||ee("system","\u2191 \u5386\u53F2\u5DF2\u52A0\u8F7D\u3002\u5728\u4E0B\u65B9\u7EE7\u7EED\u8F93\u5165\u5373\u53EF resume\uFF08\u670D\u52A1\u7AEF\u4FDD\u7559\u5B8C\u6574 tool / VLM \u4E0A\u4E0B\u6587\uFF09\u3002"),Ds(),qt==="history"&&hn(),n}catch(n){throw t.silent||ee("error",n.message),n}}async function Oa(){if(Qn)return;let e=i("ma-input"),t=(e?.value||"").trim();if(!t)return;Qn=!0,i("ma-send").disabled=!0,ee("user",t),e.value="",e.style.height="";for(let o of pn)if(o.previewUrl)try{URL.revokeObjectURL(o.previewUrl)}catch{}pn=[],_r();let n=null,s="",a=null;try{await jr("/api/ai/chat",{message:t,sessionId:we},{session:o=>{we=o.id,qe={...qe||{},id:o.id,title:o.title||qe?.title||t.slice(0,40),updatedAt:Date.now()},localStorage.setItem(Rt,o.id),Ds()},round_start:()=>{n=null,a&&(a.querySelector("details").open=!1),a=null},reasoning:o=>{a||(a=ee("reasoning","")),a.querySelector("pre").textContent=o.content||""},tool_call:o=>{ee("tool","",{name:o.name,args:o.args,phase:"\u6267\u884C\u4E2D",id:o.callId})},tool_result:o=>Ar(o.callId,o.ok===!1?"error":"done",o.ok===!1?o.error:o.result),content:o=>{s=o.content||"",n||(n=ee("assistant","")),ql(n,s)},tool:o=>{o.phase==="start"?ee("tool","",{name:o.name,args:o.args,phase:"start",id:o.id}):Ar(o.id,o.phase,o.result)},approval:o=>Xu(o),done:o=>{o.sessionId&&(we=o.sessionId,localStorage.setItem(Rt,o.sessionId)),(o.title||o.sessionId)&&(qe={id:we,title:o.title||qe?.title||"\u5BF9\u8BDD",updatedAt:Date.now(),messageCount:(qe?.messageCount||0)+2}),o.content&&(n||(n=ee("assistant","")),ql(n,o.content)),a&&(a.querySelector("details").open=!1),Ds(),Lt()},error:o=>{ee("error",o.message||"error")}})}catch(o){ee("error",o.message)}finally{Qn=!1,i("ma-send").disabled=!1}}async function rp(){if(Qn)return;Qn=!0;let e=parseInt(i("ma-report-days")?.value||"1",10),t=i("ma-report-body");t.innerHTML=`<div class="text-sm text-base-content/50 py-6 text-center">\u6B63\u5728\u6C47\u603B\u8FD1 ${e} \u5929\u6D3B\u52A8\u2026</div>`,i("ma-gen-report").disabled=!0;let n="",s=document.createElement("div");s.className="ma-report-tools flex flex-col gap-1 mb-3";try{await jr("/api/ai/report",{days:e},{content:a=>{n=a.content||"",t.innerHTML="",t.appendChild(s);let o=document.createElement("div");o.className="md ma-report-md",o.innerHTML=Yn(n),Xn(o),t.appendChild(o)},tool:a=>{if(a.phase==="start"){let o=document.createElement("div");o.className="ma-tool",o.dataset.toolId=a.id||a.name,o.innerHTML=`<span class="ma-tool-name">${p(a.name)}</span> <span class="ma-tool-phase">start</span>`,s.appendChild(o)}else{let o=s.querySelector(`[data-tool-id="${CSS.escape(a.id||a.name)}"]`);o&&(o.classList.add(a.phase==="error"?"error":"done"),o.querySelector(".ma-tool-phase").textContent=a.phase)}},done:a=>{if(a.content){t.innerHTML="",t.appendChild(s);let o=document.createElement("div");o.className="md ma-report-md",o.innerHTML=Yn(a.content),Xn(o),t.appendChild(o)}},error:a=>{t.innerHTML=`<div class="alert alert-error text-sm">${p(a.message)}</div>`}})}catch(a){t.innerHTML=`<div class="alert alert-error text-sm">${p(a.message)}</div>`}finally{Qn=!1,i("ma-gen-report").disabled=!1}}async function Jl(){try{let e=new Date,t=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`,n=await x("GET",`/api/ai/reports/${t}`);if(n?.markdown){let s=i("ma-report-body");s.innerHTML=`
|
|
368
|
+
<div class="text-[10px] text-base-content/40 mb-2">${p(n.title||t)} \xB7 ${p(n.generatedAt||"")}</div>
|
|
369
|
+
<div class="md ma-report-md">${Yn(n.markdown)}</div>`,Xn(s)}}catch{}}async function ip(){let e=i("ma-report-list");try{let t=await x("GET","/api/ai/reports");e.classList.remove("hidden");let n=t.reports||[];if(!n.length){e.innerHTML='<div class="text-xs text-base-content/40 px-2 py-1">\u6682\u65E0\u5386\u53F2\u62A5\u544A</div>';return}e.innerHTML=n.map(s=>`
|
|
370
|
+
<button type="button" class="ma-report-item w-full text-left px-2 py-1 rounded hover:bg-base-200 text-xs"
|
|
371
|
+
data-day="${p(s.day)}">
|
|
372
|
+
<span class="font-semibold">${p(s.day)}</span>
|
|
373
|
+
<span class="text-base-content/45 ml-1">${p(s.title||"")}</span>
|
|
374
|
+
</button>`).join(""),e.querySelectorAll("[data-day]").forEach(s=>{s.addEventListener("click",async()=>{try{let a=await x("GET",`/api/ai/reports/${s.dataset.day}`),o=i("ma-report-body");o.innerHTML=`
|
|
375
|
+
<div class="text-[10px] text-base-content/40 mb-2">${p(a.title||a.day)} \xB7 ${p(a.generatedAt||"")}</div>
|
|
376
|
+
<div class="md ma-report-md">${Yn(a.markdown)}</div>`,Xn(o)}catch(a){i("ma-report-body").innerHTML=`<div class="alert alert-error text-sm">${p(a.message)}</div>`}})})}catch(t){e.classList.remove("hidden"),e.innerHTML=`<div class="text-xs text-error px-2">${p(t.message)}</div>`}}async function Ql(){try{let e=await x("GET","/api/ai/config");i("ma-cfg-url").value=e.url||"",i("ma-cfg-model").value=e.model||"",i("ma-cfg-key").placeholder=e.hasKey?"\u5DF2\u914D\u7F6E \xB7 \u7559\u7A7A\u4E0D\u4FEE\u6539":"API Key",i("ma-cfg-key").value="",i("ma-cfg-vlm-url").value=e.vlm_url||"",i("ma-cfg-vlm-model").value=e.vlm_model||"",i("ma-cfg-vlm-key").value="",i("ma-cfg-vlm-key").placeholder=e.hasVlmKey?"\u5DF2\u914D\u7F6E \xB7 \u7559\u7A7A\u4E0D\u4FEE\u6539":"\u53EF\u9009",i("ma-cfg-system").value=e.system||"",i("ma-auto-report")&&(i("ma-auto-report").checked=!!e.auto_report),i("ma-auto-hour")&&(i("ma-auto-hour").value=String(e.auto_report_hour??18)),_s(e)}catch(e){i("ma-cfg-status").textContent=e.message}}async function lp(){let e=i("ma-cfg-status");e.textContent="\u4FDD\u5B58\u4E2D\u2026";try{let t={url:i("ma-cfg-url").value.trim(),model:i("ma-cfg-model").value.trim(),vlm_url:i("ma-cfg-vlm-url").value.trim(),vlm_model:i("ma-cfg-vlm-model").value.trim(),system:i("ma-cfg-system").value,auto_report:!!i("ma-auto-report")?.checked,auto_report_hour:parseInt(i("ma-auto-hour")?.value||"18",10)},n=i("ma-cfg-key").value.trim(),s=i("ma-cfg-vlm-key").value.trim();n&&(t.key=n),s&&(t.vlm_key=s);let a=await x("PUT","/api/ai/config",t);e.textContent=a.hasKey?"\u5DF2\u4FDD\u5B58 \u2713":"\u5DF2\u4FDD\u5B58\uFF08\u672A\u8BBE\u7F6E Key\uFF09",i("ma-cfg-key").value="",i("ma-cfg-vlm-key").value="",_s(a)}catch(t){e.textContent=t.message}}function _s(e){if(Ba&&(clearInterval(Ba),Ba=null),!e?.auto_report)return;let t=e.auto_report_hour??18;Ba=setInterval(async()=>{if(!c.token)return;let n=new Date;if(n.getHours()!==t)return;let s=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`;if(Mr!==s&&!(n.getMinutes()>10))try{Mr=s,localStorage.setItem("ai_last_auto_report",s),await jr("/api/ai/report",{days:e.auto_report_days||1},{done:()=>{console.info("[meta-agent] auto report saved for",s)},error:a=>console.warn("[meta-agent] auto report",a.message)})}catch(a){console.warn("[meta-agent] auto report failed",a),Mr="",localStorage.removeItem("ai_last_auto_report")}},60*1e3)}function Vl(){i("meta-agent-panel")||(document.getElementById("root")?.insertAdjacentHTML("beforeend",Yu()),document.querySelectorAll("[data-ma-close]").forEach(e=>{e.addEventListener("click",Wl)}),i("ma-btn-chat")?.addEventListener("click",()=>Te("chat")),i("ma-btn-history")?.addEventListener("click",async()=>{await Lt(),Te("history")}),i("ma-btn-notes")?.addEventListener("click",async()=>{await Vn(),mn||js(),Te("notes")}),i("ma-open-history")?.addEventListener("click",async()=>{await Lt(),Te("history")}),i("ma-btn-report")?.addEventListener("click",()=>{Te("report"),Jl()}),i("ma-btn-config")?.addEventListener("click",()=>{Te("config"),Ql()}),i("ma-send")?.addEventListener("click",Oa),i("ma-input")?.addEventListener("keydown",e=>{(e.metaKey||e.ctrlKey)&&e.key==="Enter"&&(e.preventDefault(),Oa())}),i("ma-input")?.addEventListener("input",()=>{let e=i("ma-input");e.style.height="auto",e.style.height=Math.min(e.scrollHeight,120)+"px"}),i("ma-new-chat")?.addEventListener("click",()=>{Et(null),Te("chat")}),i("ma-del-session")?.addEventListener("click",op),i("ma-resume-focus")?.addEventListener("click",()=>{i("ma-input")?.focus()}),i("ma-history-refresh")?.addEventListener("click",async()=>{await Lt(),hn()}),i("ma-history-new")?.addEventListener("click",()=>{Et(null),Te("chat")}),i("ma-history-search")?.addEventListener("input",e=>{Ol=e.target.value||"",hn()}),i("ma-quick-today")?.addEventListener("click",()=>{Te("chat"),i("ma-input").value="\u6839\u636E\u6211\u6700\u8FD1\u7684\u4F1A\u8BDD\uFF0C\u603B\u7ED3\u4ECA\u5929\u6211\u505A\u4E86\u4EC0\u4E48\uFF1F\u6309\u9879\u76EE\u5217\u51FA\u4EAE\u70B9\u4E0E\u672A\u5B8C\u6210\u4E8B\u9879\u3002",Oa()}),i("ma-quick-projects")?.addEventListener("click",()=>{Te("chat"),i("ma-input").value="\u5217\u51FA\u6700\u8FD1 14 \u5929\u6D3B\u8DC3\u7684\u9879\u76EE\uFF0C\u6BCF\u4E2A\u9879\u76EE\u4E00\u53E5\u8BDD\u8BF4\u660E\u6700\u8FD1\u5728\u505A\u4EC0\u4E48\u3002",Oa()}),i("ma-gen-report")?.addEventListener("click",rp),i("ma-load-reports")?.addEventListener("click",ip),i("ma-notes-refresh")?.addEventListener("click",async()=>{await Vn(),fn()}),i("ma-notes-new")?.addEventListener("click",()=>{js(),fn(),i("ma-note-title")?.focus()}),i("ma-notes-search")?.addEventListener("input",async e=>{Ul=e.target.value||"",await Vn(),fn()}),i("ma-note-save")?.addEventListener("click",async()=>{try{await np()}catch(e){i("ma-note-status").textContent=e.message}}),i("ma-note-delete")?.addEventListener("click",async()=>{try{await sp()}catch(e){i("ma-note-status").textContent=e.message}}),i("ma-note-ask")?.addEventListener("click",tp),i("ma-cfg-save")?.addEventListener("click",lp),i("ma-auto-report")?.addEventListener("change",async()=>{try{let e=await x("PUT","/api/ai/config",{auto_report:!!i("ma-auto-report").checked,auto_report_hour:parseInt(i("ma-auto-hour")?.value||"18",10)});_s(e)}catch{}}),i("ma-auto-hour")?.addEventListener("change",async()=>{try{let e=await x("PUT","/api/ai/config",{auto_report:!!i("ma-auto-report")?.checked,auto_report_hour:parseInt(i("ma-auto-hour").value||"18",10)});_s(e)}catch{}}),i("ma-image-input")?.addEventListener("change",async e=>{let t=[...e.target.files||[]],n=i("ma-input");n&&(n.disabled=!0);try{for(let s of t)if(s.type.startsWith("image/")){if(s.size>12*1024*1024){ee("error",`${s.name} \u8FC7\u5927 (>12MB)`);continue}await Rl(s,s.name||`upload-${Date.now()}.png`)}}catch(s){ee("error",`\u56FE\u7247\u4E0A\u4F20\u5931\u8D25: ${s.message}`)}finally{e.target.value="",n&&(n.disabled=!1,n.focus())}}),document.addEventListener("paste",async e=>{if(!Wa||qt!=="chat")return;let t=i("ma-input"),n=i("meta-agent-panel"),s=document.activeElement;if(!n||!s||!n.contains(s))return;let o=[...e.clipboardData?.items||[]].filter(r=>r.type.startsWith("image/"));if(o.length){e.preventDefault(),t&&(t.disabled=!0);try{for(let r of o){let d=r.getAsFile();if(!d)continue;let u=(r.type.split("/")[1]||"png").replace(/[^a-z0-9]/gi,"")||"png";await Rl(d,`paste-${Date.now()}.${u}`)}}catch(r){ee("error",`\u7C98\u8D34\u56FE\u7247\u5931\u8D25: ${r.message}`)}finally{t&&(t.disabled=!1,t.focus())}}}),Et(null,{silent:!0}),js())}function Ns(){c.token&&(M.peek()&&!ps()||(Lt(),Vn().catch(()=>{}),x("GET","/api/ai/config").then(_s).catch(()=>{})))}var Wa,qt,Qn,we,qe,pn,Hl,Ba,Mr,Ua,Ol,Fa,Ul,mn,Fl,Rt,Ps=U(()=>{W();le();F();_n();en();Zt();Wa=!1,qt="chat",Qn=!1,we=null,qe=null,pn=[],Hl=0,Ba=null,Mr=localStorage.getItem("ai_last_auto_report")||"",Ua=[],Ol="",Fa=[],Ul="",mn=null,Fl=null,Rt="ma_last_session_id"});function Nr(e){return Array.isArray(e)?e:e&&Array.isArray(e.results)?e.results:e&&Array.isArray(e.sessions)?e.sessions:[]}function bn(){let e=Nr(ne.peek()),t=j.peek();M.peek()&&t&&(e=e.filter(s=>s&&(!s.machineId||s.machineId===t)));let n=ye.peek();return n&&n!=="all"&&(e=e.filter(s=>s&&(s.agent||"claude")===n)),e}function Zl(e){let t=e.getFullYear(),n=String(e.getMonth()+1).padStart(2,"0"),s=String(e.getDate()).padStart(2,"0");return`${t}-${n}-${s}`}function cp(e,t){let n=[],a=new Date(e,t,1).getDay(),r=new Date(e,t+1,0).getDate(),d=new Date(e,t,0).getDate();for(let l=a-1;l>=0;l--)n.push({date:new Date(e,t-1,d-l),isCurrentMonth:!1});for(let l=1;l<=r;l++)n.push({date:new Date(e,t,l),isCurrentMonth:!0});let u=7-n.length%7;if(u<7)for(let l=1;l<=u;l++)n.push({date:new Date(e,t+1,l),isCurrentMonth:!1});return n}function ec(e,t){let n=new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime(),s=n+1440*60*1e3;return t.filter(a=>{let o=O(a.updatedAt);return o!=null&&o>=n&&o<s})}function tc(e){return e==null||isNaN(e)?"0":e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}K`:String(e)}function vn(e){let t=i("calendar-grid");if(!t)return;e=Nr(e??bn());let n=i("calendar-month-year");if(n){let f=new Date(Ka,gn,1);n.textContent=f.toLocaleDateString([],{month:"long",year:"numeric"})}let s=e.length,a=new Set(e.map(f=>f.cwd).filter(Boolean)).size,o=e.reduce((f,m)=>f+(Number(m.totalTokens)||0),0),r=i("stats-total-sessions"),d=i("stats-total-projects"),u=i("stats-total-tokens");r&&(r.textContent=String(s)),d&&(d.textContent=String(a)),u&&(u.textContent=tc(o));let l=cp(Ka,gn);Hs||(Hs=Zl(new Date)),t.innerHTML=l.map(f=>{let m=f.date,g=Zl(m),y=ec(m,e).length,H=m.toDateString()===new Date().toDateString(),me=g===Hs,z="",ue="text-base-content/65",q="border border-transparent",J="cursor-default",he=f.isCurrentMonth?"":"opacity-25";y>0?(J="cursor-pointer",y<=2?(z="bg-primary/15",ue="text-primary font-bold",q="border border-primary/30"):y<=5?(z="bg-primary/30",ue="text-primary font-bold",q="border border-primary/50"):(z="bg-primary/60",ue="text-primary-content font-bold",q="border border-primary/80")):(z="bg-base-300/25",f.isCurrentMonth&&(J="hover:bg-base-300/50")),H?q="border-2 border-primary":me&&(q="border-2 border-accent");let Ae=m.getDate()===1?`<span class="absolute top-0.5 left-1 text-[8px] opacity-60 uppercase">${m.toLocaleDateString([],{month:"short"})}</span>`:"";return`
|
|
377
|
+
<div class="aspect-square rounded-xl flex flex-col items-center justify-center p-2 relative transition-all min-h-[50px] md:min-h-[60px] ${z} ${ue} ${q} ${J} ${he}"
|
|
378
|
+
data-cal-date="${g}" title="${m.toDateString()}: ${y} session(s)">
|
|
379
|
+
${Ae}
|
|
380
|
+
<span class="text-sm font-semibold">${m.getDate()}</span>
|
|
381
|
+
${y>0?`<span class="text-[10px] mt-0.5 opacity-80 font-medium whitespace-nowrap">${y}s</span>`:""}
|
|
382
|
+
</div>`}).join(""),dp(e),Hr()}function dp(e){let t=i("selected-day-title"),n=i("selected-day-sessions");if(!t||!n)return;let[s,a,o]=Hs.split("-").map(Number),r=new Date(s,a-1,o);t.textContent=`Activity on ${r.toLocaleDateString([],{weekday:"short",month:"short",day:"numeric",year:"numeric"})}`,e=Nr(e);let d=ec(r,e),u=d.reduce((f,m)=>f+(Number(m.totalTokens)||0),0),l=i("stats-selected-tokens");if(l&&(l.textContent=tc(u)),!d.length){n.innerHTML='<div class="text-center text-xs text-base-content/40 my-auto py-6">No sessions active on this day</div>';return}d.sort((f,m)=>(O(m.updatedAt)||0)-(O(f.updatedAt)||0)),n.innerHTML=d.map(f=>{let m=O(f.updatedAt),g=m!=null?new Date(m).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):"";return`
|
|
383
|
+
<div class="flex items-center gap-2.5 p-2.5 rounded-lg bg-base-300/40 hover:bg-base-300 border border-base-300/50 cursor-pointer text-left transition-all ${c.sessionId===f.sessionId?"border-primary bg-primary/5":""}"
|
|
384
|
+
data-session-id="${p(f.sessionId)}"
|
|
385
|
+
data-session-cwd="${p(f.cwd||"")}"
|
|
386
|
+
data-session-config-dir="${p(f.configDir||"")}"
|
|
387
|
+
data-session-agent="${p(f.agent||"claude")}"
|
|
388
|
+
data-session-machine="${p(f.machineId||"")}">
|
|
389
|
+
<div class="flex-shrink-0">${Hn(f.agent)}</div>
|
|
390
|
+
<div class="flex-1 min-w-0">
|
|
391
|
+
<div class="text-xs font-semibold truncate text-base-content/90">${p(bt(f))}</div>
|
|
392
|
+
<div class="text-[10px] text-base-content/40 truncate mt-0.5">${p(f.projectName||qn(f.cwd)||"No workspace")}</div>
|
|
393
|
+
</div>
|
|
394
|
+
<div class="text-[9px] text-base-content/45 font-mono whitespace-nowrap bg-base-300 px-1.5 py-0.5 rounded">${g}</div>
|
|
395
|
+
</div>`}).join("")}function za(e){return`${e.machineId||""}:${e.agent||"claude"}:${e.sessionId}`}function Pr(){try{let e=JSON.parse(localStorage.getItem(sc)||"[]");return Array.isArray(e)?e.filter(t=>t&&t.sessionId):[]}catch{return[]}}function ac(e){try{localStorage.setItem(sc,JSON.stringify(e))}catch{}}function oc(e){if(!e?.sessionId)return;let t=za(e),n={...e,lastOpenedAt:Date.now()},s=Pr().filter(a=>za(a)!==t);s.unshift(n),ac(s.slice(0,nc)),Hr(),Rr()}function rc(e){if(!e?.sessionId)return;let t=za(e);ac(Pr().filter(n=>za(n)!==t)),Hr(),Rr()}function ic(e){return Pr().sort((t,n)=>(O(n.lastOpenedAt)||0)-(O(t.lastOpenedAt)||0)).slice(0,e)}function Hr(){let e=i("recent-sessions-list");if(!e)return;let t=ic(6);if(!t.length){e.innerHTML='<div class="col-span-full text-center text-xs text-base-content/40 py-4">No recent sessions</div>';return}e.innerHTML=t.map(n=>{let s=Pn(n.updatedAt);return`
|
|
396
|
+
<div class="flex items-center gap-2.5 p-3 rounded-xl bg-base-200 hover:bg-base-300 border border-base-300/80 cursor-pointer text-left transition-all ${c.sessionId===n.sessionId?"border-primary bg-primary/5":""}"
|
|
397
|
+
data-session-id="${p(n.sessionId)}"
|
|
398
|
+
data-session-cwd="${p(n.cwd||"")}"
|
|
399
|
+
data-session-config-dir="${p(n.configDir||"")}"
|
|
400
|
+
data-session-agent="${p(n.agent||"claude")}"
|
|
401
|
+
data-session-machine="${p(n.machineId||"")}">
|
|
402
|
+
<div class="flex-shrink-0">${Hn(n.agent)}</div>
|
|
403
|
+
<div class="flex-1 min-w-0">
|
|
404
|
+
<div class="text-xs font-bold truncate text-base-content/95">${p(bt(n))}</div>
|
|
405
|
+
<div class="text-[10px] text-base-content/40 truncate mt-1">${p(n.projectName||qn(n.cwd)||"No workspace")}</div>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="text-[9px] text-base-content/40 whitespace-nowrap self-start mt-0.5">${s}</div>
|
|
408
|
+
</div>`}).join("")}function xn(){let e=i("recent-menu");e&&(e.classList.add("hidden"),e.classList.remove("recent-menu-open"),e.style.top="",e.style.left="",e.style.right="",e.style.width="",e.style.maxHeight=""),i("recent-menu-backdrop")?.classList.add("hidden")}function qr(){let e=i("recent-menu"),t=i("topbar");if(!e||!t)return;let n=t.getBoundingClientRect(),a=Math.round(n.bottom+6),o=window.matchMedia("(max-width: 640px)").matches?8:null;if(e.style.top=`${a}px`,o!=null)e.style.left=`${o}px`,e.style.right=`${o}px`;else{let u=i("btn-recent-sessions")?.getBoundingClientRect();if(u){let l=Math.min(320,window.innerWidth-16),f=u.left;f+l>window.innerWidth-8&&(f=window.innerWidth-l-8),f<8&&(f=8),e.style.left=`${Math.round(f)}px`,e.style.right="auto",e.style.width=`${l}px`}}let r=Math.max(160,window.innerHeight-a-12);e.style.maxHeight=`${Math.min(r,Math.round(window.innerHeight*.7))}px`}function up(){let e=i("recent-menu");e&&(Rr(),e.classList.remove("hidden"),e.classList.add("recent-menu-open"),qr(),i("recent-menu-backdrop")?.classList.remove("hidden"))}function lc(){let e=i("recent-menu");e&&(e.classList.contains("hidden")?up():xn())}function Rr(){let e=i("recent-menu-list"),t=i("recent-menu-empty"),n=i("recent-menu-count");if(!e)return;let s=ic(nc);if(n&&(n.textContent=s.length?`${s.length}`:""),!s.length){e.innerHTML="",t?.classList.remove("hidden");return}t?.classList.add("hidden"),e.innerHTML=s.map(a=>{let o=Pn(a.updatedAt),r=c.sessionId===a.sessionId&&(!a.machineId||!c.machineId||a.machineId===c.machineId),d=a.machineId?`<span class="text-[9px] font-mono text-base-content/35 truncate max-w-[4.5rem]" title="${p(a.machineId)}">@${p(a.machineId)}</span>`:"";return`
|
|
409
|
+
<div class="recent-menu-item w-full text-left px-2 py-1.5 rounded-md flex items-start gap-2
|
|
410
|
+
${r?"bg-primary/15 text-primary":"hover:bg-base-200"}">
|
|
411
|
+
<button type="button" class="flex min-w-0 flex-1 items-start gap-2 text-left" aria-label="\u6253\u5F00 ${p(bt(a))}"
|
|
412
|
+
data-session-id="${p(a.sessionId)}"
|
|
413
|
+
data-session-cwd="${p(a.cwd||"")}"
|
|
414
|
+
data-session-config-dir="${p(a.configDir||"")}"
|
|
415
|
+
data-session-agent="${p(a.agent||"claude")}"
|
|
416
|
+
data-session-machine="${p(a.machineId||"")}">
|
|
417
|
+
<span class="flex-shrink-0 mt-0.5">${Hn(a.agent)}</span>
|
|
418
|
+
<span class="flex-1 min-w-0">
|
|
419
|
+
<span class="block text-xs font-semibold truncate leading-snug">${p(bt(a))}</span>
|
|
420
|
+
<span class="block text-[10px] text-base-content/40 truncate mt-0.5">${p(a.projectName||qn(a.cwd)||"\u2014")}</span>
|
|
421
|
+
</span>
|
|
422
|
+
<span class="flex flex-col items-end gap-0.5 flex-shrink-0 self-start">
|
|
423
|
+
<span class="text-[9px] text-base-content/40 whitespace-nowrap">${p(o)}</span>
|
|
424
|
+
${d}
|
|
425
|
+
${r?'<span class="text-[9px] opacity-70">\u5F53\u524D</span>':""}
|
|
426
|
+
</span>
|
|
427
|
+
</button>
|
|
428
|
+
<button type="button" class="recent-remove btn btn-ghost btn-xs min-h-7 h-7 w-7 px-0 flex-shrink-0 text-base-content/45 hover:text-error"
|
|
429
|
+
title="\u4ECE\u6700\u8FD1\u4F1A\u8BDD\u79FB\u9664" aria-label="\u4ECE\u6700\u8FD1\u4F1A\u8BDD\u79FB\u9664 ${p(bt(a))}"
|
|
430
|
+
data-dismiss-recent-session="${p(a.sessionId)}"
|
|
431
|
+
data-dismiss-recent-agent="${p(a.agent||"claude")}"
|
|
432
|
+
data-dismiss-recent-machine="${p(a.machineId||"")}">\xD7</button>
|
|
433
|
+
</div>`}).join("")}function cc(e){Hs=e}function Br(e){gn+=e,gn<0?(gn=11,Ka--):gn>11&&(gn=0,Ka++)}var Ka,gn,Hs,nc,sc,Or=U(()=>{W();F();_t();Ka=new Date().getFullYear(),gn=new Date().getMonth(),Hs=null;nc=15,sc="recentSessionsV1"});var to={};ls(to,{loadAgentsMeta:()=>es,loadAllSessions:()=>We,loadMemoryTab:()=>eo,loadWorkspaces:()=>Zn,markActiveSessionRow:()=>pp,mdToHtml:()=>bc,openMemoryFile:()=>Kr,promptCustomModel:()=>Ya,refreshEffortSelect:()=>Va,refreshModelSelect:()=>et,renderProjectGroups:()=>hc,renderSessionList:()=>Gr,renderTimeline:()=>gc,runActivitySearch:()=>Xa,scheduleActivitySearch:()=>Za,sessionItemHtml:()=>Wr,syncSidebarChrome:()=>qs});function dc(e){return!Array.isArray(e)||!e.length?"":e.map(t=>`${t.sessionId}:${t.updatedAt||0}:${t.turnCount||0}:${t.agent||""}`).join("|")}function pp(e,t){let n=t||"claude";document.querySelectorAll("#session-list .session-row").forEach(s=>{let a=s.dataset.sessionId===e&&(s.dataset.sessionAgent||"claude")===n;s.classList.toggle("border-primary",a),s.classList.toggle("bg-primary/5",a),s.classList.toggle("border-transparent",!a);let o=s.querySelector(".session-title-text");o&&(o.classList.toggle("text-primary",a),o.classList.toggle("font-medium",a),o.classList.toggle("text-base-content/85",!a))})}function uc(e){return Array.isArray(e)?e:e&&Array.isArray(e.results)?e.results:e&&Array.isArray(e.sessions)?e.sessions:[]}function fp(e,t){return e?.parentSessionId?K(e.parentAgent||t.agent,e.parentSessionId,e.parentMachineId??t.machineId):""}function mp(e){let t=Array.isArray(e)?e:[],n=new Map(t.map(u=>[K(u.agent,u.sessionId,u.machineId),u])),s=new Map,a=[];for(let u of t){let l=T.peek()?.[K(u.agent,u.sessionId,u.machineId)]?.branch,f=fp(l,u);if(f&&n.has(f)&&f!==K(u.agent,u.sessionId,u.machineId)){let m=s.get(f)||[];m.push(u),s.set(f,m)}else a.push(u)}let o=(u,l)=>(l.updatedAt||0)-(u.updatedAt||0);a.sort(o);for(let u of s.values())u.sort(o);let r=[],d=(u,l,f=new Set)=>{let m=K(u.agent,u.sessionId,u.machineId);if(!f.has(m)){f.add(m),r.push(l?{...u,_branchDepth:l}:u);for(let g of s.get(m)||[])d(g,l+1,f)}};for(let u of a)d(u,0);return r}async function hp(){if(!Ur){Ur=!0;try{Qa++,await We()}finally{Ur=!1}}}function gp({hubIndex:e=!1,offset:t=0}={}){let n=new URLSearchParams;n.set("limit",String(Ja)),t&&n.set("offset",String(t)),(M.peek()||e)&&n.set("index","1");let s=n.toString();return s?`/api/sessions?${s}`:"/api/sessions"}async function We({waitFresh:e=!0,hubIndex:t=!1}={}){let n=j.peek()||null;n!==pc&&(pc=n,Qa=1);let s=++fc,a=uc(await Pa()).slice(0,Ja*Qa);if(a.length){let r=j.peek();if(M.peek()&&r){let d=a.filter(u=>!u.machineId||u.machineId===r);ne.value=d.length?d:a}else ne.value=a}let o=async()=>{let r=[];for(let u=0;u<Qa;u++){let l=gp({hubIndex:t,offset:u*Ja}),f=await x("GET",l,void 0,void 0,{machineId:n||void 0});if(s!==fc)return ne.peek();let m=uc(f);if(r.push(...m),Fr=m.length===Ja,!Fr)break}let d=new Map(r.map(u=>[`${u.machineId||""}:${u.agent}:${u.sessionId}`,u]));return r.splice(0,r.length,...d.values()),dc(r)!==dc(ne.peek())&&(ne.value=r,$l(r)),r};if(e||!a.length)try{await o()}catch(r){if(!a.length){let d=i("session-list");d&&(d.innerHTML=`<div class="px-3 py-3 text-xs text-error">${p(r.message)}</div>`)}}else o().catch(()=>{})}async function Zn({waitFresh:e=!0}={}){let t=await Sl();t&&(pe.value=t);let n=async()=>{let s=await x("GET","/api/workspaces");pe.value=s,Is(s)};if(e||!t)try{await n()}catch{}else n().catch(()=>{})}function Wr(e,{showProject:t=!1}={}){let n=c.sessionId===e.sessionId&&(c.agent||S.peek())===(e.agent||"claude"),s=T.peek()?.[K(e.agent,e.sessionId,e.machineId)]||{},a=!!(s.title&&String(s.title).trim()),o=e.snippet&&$e.peek()?e.snippet:bt(e),r=!!s.favorite,d=!!s.hidden,u=!!(s.notes&&String(s.notes).trim()),l=s.branch?.parentSessionId?s.branch:null,f=Math.max(0,Math.min(4,Number(e._branchDepth)||0)),m=Number(e.turnCount)||0,g=m>0&&m<=Wo,w=t?`<div class="text-[10px] text-base-content/40 font-mono truncate" title="${p(e.cwd||"")}">${p(e.projectName||qn(e.cwd)||"\u2014")}</div>`:"",y=[g?`<span class="session-thin-badge" title="Only ${m} turn${m===1?"":"s"}">thin\xB7${m}</span>`:"",a?`<span class="session-renamed-badge" title="Custom name (original: ${p(e.display||"")})">renamed</span>`:"",d?'<span class="session-hidden-badge" title="Hidden">hidden</span>':"",u?`<span class="session-note-dot" title="${p(s.notes)}">\u{1F4DD}</span>`:"",l?`<span class="session-branch-badge" title="Forked from ${p(l.parentAgent||e.agent)}:${p(l.parentSessionId)}">\u2387 fork</span>`:""].filter(Boolean).join(""),H=e.machineId?`<span class="text-[9px] px-1 py-0.5 rounded bg-base-300 text-base-content/50 font-mono flex-shrink-0" title="Machine">${p(e.machineId)}</span>`:"",me=a?`${o}
|
|
434
|
+
(original: ${e.display||e.sessionId})`:e.display||"",z=l?`<div class="session-branch-line" title="Forked from ${p(l.parentAgent||e.agent)} \xB7 ${p(l.parentSessionId)}">\u21B3 ${p(l.parentAgent||e.agent)} \xB7 ${p(l.parentSessionId.slice(0,8))}</div>`:"";return`<div class="session-row ${f?"session-branch":""} px-2.5 py-1.5 cursor-pointer hover:bg-base-300 border-l-2
|
|
435
|
+
${n?"border-primary bg-primary/5":"border-transparent"} ${r?"session-fav":""} ${d?"session-hidden-row":""} ${g?"session-thin":""}"
|
|
436
|
+
style="--branch-depth:${f}"
|
|
437
|
+
data-session-id="${p(e.sessionId)}"
|
|
438
|
+
data-session-cwd="${p(e.cwd||"")}"
|
|
439
|
+
data-session-config-dir="${p(e.configDir||"")}"
|
|
440
|
+
data-session-agent="${p(e.agent||"claude")}"
|
|
441
|
+
data-session-machine="${p(e.machineId||"")}"
|
|
442
|
+
data-session-display="${p(e.display||"")}">
|
|
443
|
+
<div class="flex items-start gap-1.5">
|
|
444
|
+
<button type="button" class="session-fav-btn flex-shrink-0 leading-none mt-0.5 ${r?"is-fav":""}"
|
|
445
|
+
data-fav-toggle="1"
|
|
446
|
+
data-fav-session-id="${p(e.sessionId)}"
|
|
447
|
+
data-fav-session-agent="${p(e.agent||"claude")}"
|
|
448
|
+
data-fav-session-machine="${p(e.machineId||"")}"
|
|
449
|
+
title="${r?"Unfavorite":"Favorite"}">${r?"\u2605":"\u2606"}</button>
|
|
450
|
+
${Hn(e.agent)}
|
|
451
|
+
<div class="min-w-0 flex-1">
|
|
452
|
+
<div class="session-title-wrap flex items-center gap-1 min-w-0"
|
|
453
|
+
data-rename-session-id="${p(e.sessionId)}"
|
|
454
|
+
data-rename-session-agent="${p(e.agent||"claude")}"
|
|
455
|
+
data-rename-session-machine="${p(e.machineId||"")}"
|
|
456
|
+
data-rename-session-display="${p(e.display||"")}">
|
|
457
|
+
<div class="session-title-text text-[11px] leading-snug truncate flex-1 min-w-0 ${n?"text-primary font-medium":"text-base-content/85"} ${a?"session-title-renamed":""}"
|
|
458
|
+
title="${p(me)}">${p(o)}</div>
|
|
459
|
+
<button type="button" class="session-rename-btn flex-shrink-0"
|
|
460
|
+
data-rename-session="1"
|
|
461
|
+
title="Rename session">\u270E</button>
|
|
462
|
+
<button type="button" class="session-hide-btn flex-shrink-0 ${d?"is-hidden":""}"
|
|
463
|
+
data-hide-toggle="1"
|
|
464
|
+
data-hide-session-id="${p(e.sessionId)}"
|
|
465
|
+
data-hide-session-agent="${p(e.agent||"claude")}"
|
|
466
|
+
data-hide-session-machine="${p(e.machineId||"")}"
|
|
467
|
+
title="${d?"Unhide session":"Hide session"}">${d?"\u{1F441}":"\u{1F648}"}</button>
|
|
468
|
+
</div>
|
|
469
|
+
${w}
|
|
470
|
+
${z}
|
|
471
|
+
${y||H?`<div class="flex items-center gap-1 mt-0.5 flex-wrap">${H}${y}</div>`:""}
|
|
472
|
+
</div>
|
|
473
|
+
<span class="text-[9px] text-base-content/30 flex-shrink-0 mt-0.5">${Pn(e.updatedAt)}</span>
|
|
474
|
+
</div>
|
|
475
|
+
</div>`}async function es(){try{let e=await x("GET","/api/agents");return Kt.value=e,et(),e}catch(e){return console.warn("[agents] failed to load model list",e),null}}function Va(){let e=i("sel-effort");if(!e)return;let t=S.peek()||"claude",n=_.peek(),s=Qt(t,n),a=te.peek()||"";if(!a){let r=Qe(t,n);r&&s.includes(r)&&(a=r,te.value=r)}let o=['<option value="">effort: off</option>'].concat(s.map(r=>`<option value="${p(r)}" ${r===a?"selected":""}>${p(r)}</option>`));if(e.innerHTML=o.join(""),a&&!s.includes(a)){let r=Qe(t,n);r&&s.includes(r)?(te.value=r,e.value=r):(te.value="",e.value="")}else e.value=a}function et(){let e=i("sel-model");if(!e)return;let t=S.peek()||"claude",n=Be(t),s=_.peek();if(s&&!n.some(o=>o.value===s)&&(n=[{value:s,label:`${s} \u2605`,custom:!0},...n]),e.innerHTML=n.map(o=>`<option value="${p(o.value)}" ${o.value===s?"selected":""}>${p(o.label)}</option>`).join(""),n.some(o=>o.value===s))e.value=s;else{let o=Oe(t)||n[0]?.value;se(o),e.value=o,s=o}let a=i("sel-agent");a&&(a.value=t),Va()}function Ya({editCurrent:e=!1}={}){let t=S.peek()||"claude",n=e&&_.peek()||"",s=e?`Edit model id for ${t}:`:`Add model id for ${t} (saved in this browser):`,a=window.prompt(s,n);if(a==null)return;let o=a.trim();o&&(e&&n&&n!==o&&ra(t).includes(n)&&zo(t,n),Jt(t,o),se(o),et())}function hc(e){if(!Array.isArray(e)||!e.length)return`<div class="px-3 py-6 text-center text-xs text-base-content/40">
|
|
476
|
+
No projects in this range.<br>
|
|
477
|
+
<span class="text-base-content/30">Try \u201CAll\u201D time or another agent.</span>
|
|
478
|
+
</div>`;let t=Cn.value,n=Mn.value,s=!!$e.value.trim(),a=e[0]?.cwd||"(no path)";return e.map(o=>{let r=o.cwd||"(no path)",d=!1;n.has(r)?d=!1:t.has(r)?d=!0:d=s||r===a||e.length<=3;let u=o.machineId?`<span class="text-[9px] font-mono text-base-content/40 flex-shrink-0">@${p(o.machineId)}</span>`:"",l=`
|
|
479
|
+
<div class="project-header px-2.5 py-2 cursor-pointer hover:bg-base-300/80 select-none border-b border-base-300/40"
|
|
480
|
+
data-folder="${p(r)}" data-project-cwd="${p(o.cwd||"")}" data-project-machine="${p(o.machineId||"")}">
|
|
481
|
+
<div class="flex items-center gap-1.5">
|
|
482
|
+
<span class="text-[10px] text-base-content/40 w-3 flex-shrink-0">${d?"\u25BE":"\u25B8"}</span>
|
|
483
|
+
<span class="text-[12px] font-semibold truncate flex-1" title="${p(o.cwd||"")}">${p(o.projectName)}</span>
|
|
484
|
+
${u}
|
|
485
|
+
<span class="text-[9px] text-base-content/30 flex-shrink-0">${Pn(o.updatedAt)}</span>
|
|
486
|
+
</div>
|
|
487
|
+
</div>`,m=mp(o.sessions).slice(0,40),g=o.sessions.length>40?`<div class="px-3 py-1 text-[10px] text-base-content/30">+${o.sessions.length-40} more</div>`:"",w=d?`<div class="pb-1 border-b border-base-300/30">${m.map(y=>Wr(y)).join("")}${g}</div>`:"";return l+w}).join("")}function gc(e){if(!Array.isArray(e)||!e.length)return`<div class="px-3 py-6 text-center text-xs text-base-content/40">
|
|
488
|
+
No recent activity.<br>
|
|
489
|
+
<span class="text-base-content/30">Widen the time range or clear filters.</span>
|
|
490
|
+
</div>`;let t=new Map;for(let n of e){let a=(n.updatedAt?new Date(n.updatedAt):new Date).toLocaleDateString(void 0,{weekday:"short",month:"short",day:"numeric"});t.has(a)||t.set(a,[]),t.get(a).push(n)}return[...t.entries()].map(([n,s])=>`
|
|
491
|
+
<div class="px-2.5 pt-2.5 pb-1 text-[10px] uppercase tracking-wide text-base-content/35 font-medium sticky top-0 bg-base-200/95 backdrop-blur-sm z-[1]">${p(n)}</div>
|
|
492
|
+
${s.map(a=>Wr(a,{showProject:!0})).join("")}
|
|
493
|
+
`).join("")}function Gr(){let e=ht.value,t=Array.isArray(Dt.value)?Dt.value:[],n=Array.isArray(Vt.value)?Vt.value:[];return(e==="timeline"?gc(t):hc(n))+(Fr?'<button class="btn btn-sm btn-ghost w-full" data-load-more-sessions>\u52A0\u8F7D\u66F4\u591A\u4F1A\u8BDD</button>':"")}function qs(){document.querySelectorAll("[data-view]").forEach(o=>{let r=o.dataset.view===ht.peek();o.classList.toggle("bg-primary/15",r),o.classList.toggle("text-primary",r),o.classList.toggle("font-medium",r),o.classList.toggle("text-base-content/50",!r)}),document.querySelectorAll("[data-agent-filter]").forEach(o=>{o.classList.toggle("active",o.dataset.agentFilter===ye.peek())});let e=i("time-range");e&&e.value!==oa.peek()&&(e.value=oa.peek());let t=i("search-status");if(!t)return;let n=rt.peek(),s=Array.isArray(n?.results)?n.results:null,a=($e.peek()||"").trim();if(gt.peek())t.classList.remove("hidden"),t.textContent="Searching content\u2026";else if(a&&s)t.classList.remove("hidden"),t.textContent=`${s.length} hit${s.length===1?"":"s"}${n.deep===!1?"":" (incl. content)"}`;else if(a)t.classList.remove("hidden"),t.textContent="Local filter only \u2014 type to deep-search";else{let o=Dt.peek(),r=Vt.peek(),d=Array.isArray(o)?o.length:0,u=Array.isArray(r)?r.length:0;t.classList.remove("hidden"),t.textContent=ht.peek()==="projects"?`${u} project${u===1?"":"s"} \xB7 ${d} session${d===1?"":"s"}`:`${d} recent session${d===1?"":"s"}`}}async function Xa(e){let t=(e||"").trim();if(!t){rt.value=null,gt.value=!1;return}gt.value=!0;try{let n=new URLSearchParams({q:t,days:"0",limit:"50",deep:"1"});ye.peek()&&ye.peek()!=="all"&&n.set("agent",ye.peek());let s=await x("GET",`/api/activity?${n}`);$e.peek().trim()===t&&(rt.value={q:t.toLowerCase(),results:s.results||[],deep:!0})}catch(n){$e.peek().trim()===t&&(rt.value={q:t.toLowerCase(),results:[],error:n.message})}finally{gt.value=!1}}function Za(e){clearTimeout(mc);let t=(e||"").trim();if(!t){rt.value=null,gt.value=!1;return}mc=setTimeout(()=>Xa(t),350)}function bc(e){if(!e)return"";if(typeof marked>"u")return`<pre class="whitespace-pre-wrap text-xs">${p(e)}</pre>`;try{return Ve(e,{fallback:t=>`<pre class="whitespace-pre-wrap text-xs">${p(t)}</pre>`})}catch{return`<pre class="whitespace-pre-wrap text-xs">${p(e)}</pre>`}}async function eo(){let e=i("memory-area");if(e){if(!c.sessionId){e.innerHTML='<div class="p-4 text-xs text-base-content/40">Open or resume a session to view its memory.</div>';return}e.innerHTML='<div class="p-4 text-xs text-base-content/40">Loading\u2026</div>';try{let t=c.agent||S.peek()||"claude",n=new URLSearchParams({agent:t}),a=(await x("GET",`/api/sessions/${c.sessionId}/memory?${n}`)).files||[];if(!a.length){e.innerHTML='<div class="p-4 text-base-content/40 text-xs">No memory files available for this agent/session.</div>';return}e.innerHTML=`<div class="p-3 text-[11px] text-base-content/45">${p(t)} \xB7 ${a.length} memory file${a.length===1?"":"s"} \xB7 click to open</div>
|
|
494
|
+
<div class="px-3 pb-4 flex flex-col gap-1">${a.map(o=>`<button type="button" class="memory-file text-left px-3 py-2 rounded-lg border border-base-300 hover:border-primary hover:bg-primary/5" data-memory-file="${p(o.id)}" data-memory-agent="${p(t)}"><span class="font-mono text-xs">${p(o.name)}</span><span class="ml-2 text-[10px] text-base-content/40">${p(o.scope||"")}</span></button>`).join("")}<div id="memory-file-content"></div></div>`}catch(t){e.innerHTML=`<div class="p-4 text-error text-xs">${p(t?.message??String(t))}</div>`}}}async function Kr(e,t){let n=i("memory-file-content");if(!(!n||!c.sessionId||!e)){n.innerHTML='<div class="p-3 text-xs text-base-content/40">Loading file\u2026</div>';try{let s=new URLSearchParams({agent:t||c.agent||S.peek()||"claude",file:e}),a=await x("GET",`/api/sessions/${c.sessionId}/memory/file?${s}`);n.innerHTML=`<div class="mt-2 border border-base-300 rounded-lg overflow-hidden"><div class="px-3 py-1.5 bg-base-300/50 text-xs font-mono">${p(a.name)}</div><div class="px-3 py-2 md">${bc(a.content)}</div></div>`}catch(s){n.innerHTML=`<div class="mt-2 p-3 text-error text-xs">${p(s?.message??String(s))}</div>`}}}var Ja,Qa,pc,fc,Fr,Ur,mc,It=U(()=>{W();F();le();Cs();_t();en();Ja=200,Qa=1,pc=null,fc=0,Fr=!1,Ur=!1;document.addEventListener("click",e=>{e.target.closest?.("[data-load-more-sessions]")&&hp().catch(console.warn)});mc=null});function vc(e,t){no=e||"",so=t||""}async function xc(e){let t=i("project-notes-bar");if(t)try{let n=await x("GET",`/api/projects/notes?root=${encodeURIComponent(e)}`);no=n.goal||"",so=n.notes||"",ts(),t.style.display="flex"}catch(n){console.error("Error fetching project notes:",n),t.style.display="none"}}function ts(){let e=i("project-notes-bar");if(!e)return;let t=no||"No goal yet \u2014 click Edit",n=so||"";e.innerHTML=`
|
|
495
|
+
<div class="flex items-start gap-2 w-full">
|
|
496
|
+
<div class="flex-1 min-w-0">
|
|
497
|
+
<div class="truncate">
|
|
498
|
+
<span class="font-bold text-base-content/40 uppercase mr-1">Goal:</span>
|
|
499
|
+
<span id="project-goal-text" class="text-base-content/80 cursor-pointer hover:underline" title="Click to edit">${p(t)}</span>
|
|
500
|
+
</div>
|
|
501
|
+
${n?`<div class="mt-0.5 text-base-content/55 line-clamp-2 whitespace-pre-wrap" id="project-notes-text" title="${p(n)}"><span class="font-bold text-base-content/35 uppercase mr-1">Notes:</span>${p(n)}</div>`:'<div class="mt-0.5 text-base-content/35 italic text-[11px]" id="project-notes-text">No project notes</div>'}
|
|
502
|
+
</div>
|
|
503
|
+
<button id="btn-edit-project-notes" class="btn btn-ghost btn-xs px-1.5 hover:bg-base-300 flex-shrink-0">Edit</button>
|
|
504
|
+
</div>
|
|
505
|
+
`}function yc(){let e=i("project-notes-bar");e&&(e.innerHTML=`
|
|
506
|
+
<div class="flex flex-col gap-1.5 w-full">
|
|
507
|
+
<div class="flex items-center gap-2">
|
|
508
|
+
<span class="text-[10px] font-bold text-base-content/40 uppercase w-12 flex-shrink-0">Goal</span>
|
|
509
|
+
<input id="project-goal-input" type="text" class="input input-xs input-bordered flex-1 text-xs"
|
|
510
|
+
placeholder="One-line project goal\u2026" value="${p(no)}">
|
|
511
|
+
</div>
|
|
512
|
+
<div class="flex items-start gap-2">
|
|
513
|
+
<span class="text-[10px] font-bold text-base-content/40 uppercase w-12 flex-shrink-0 mt-1">Notes</span>
|
|
514
|
+
<textarea id="project-notes-input" rows="2" class="textarea textarea-xs textarea-bordered flex-1 text-xs leading-snug"
|
|
515
|
+
placeholder="Longer project notes (stack, links, status\u2026)">${p(so)}</textarea>
|
|
516
|
+
</div>
|
|
517
|
+
<div class="flex items-center gap-1 justify-end">
|
|
518
|
+
<button id="btn-save-project-notes" class="btn btn-primary btn-xs px-2">Save</button>
|
|
519
|
+
<button id="btn-cancel-project-notes" class="btn btn-ghost btn-xs px-2">Cancel</button>
|
|
520
|
+
</div>
|
|
521
|
+
</div>
|
|
522
|
+
`,i("project-goal-input")?.focus())}async function Rs(){try{let e=await x("GET","/api/sessions/meta");T.value=e||{}}catch(e){console.warn("session meta load failed",e)}}function tt(){let e=i("session-notes-bar");if(!e)return;let t=c.sessionId,n=c.agent||S.peek()||"claude";if(!t){e.style.display="none",e.innerHTML="";return}if(e.querySelector(".session-rename-input"))return;let s=An(n,t),a=(s.notes||"").trim(),o=!!s.favorite,r=!!s.hidden,d=s.branch?.parentSessionId?s.branch:null,l=(s.title||"").trim()||t.slice(0,8);e.style.display="flex",e.innerHTML=`
|
|
523
|
+
<div class="flex-1 min-w-0 flex items-center gap-2">
|
|
524
|
+
<button type="button" class="session-fav-btn ${o?"is-fav":""}" data-fav-toggle="1"
|
|
525
|
+
data-fav-session-id="${p(t)}" data-fav-session-agent="${p(n)}"
|
|
526
|
+
title="${o?"Unfavorite":"Favorite"}">${o?"\u2605":"\u2606"}</button>
|
|
527
|
+
<span id="session-title-display"
|
|
528
|
+
class="session-title-inline max-w-[40%] truncate font-semibold text-base-content/85"
|
|
529
|
+
title="${p(l)}">${p(l)}</span>
|
|
530
|
+
<button type="button" class="session-rename-btn flex-shrink-0 opacity-70 hover:opacity-100"
|
|
531
|
+
data-rename-bar="1" title="Rename session">\u270E</button>
|
|
532
|
+
<div class="session-title-actions flex items-center gap-0.5 flex-shrink-0">
|
|
533
|
+
<button type="button" id="btn-new-session-current" class="session-bar-icon" title="\u65B0\u5EFA\u4F1A\u8BDD" aria-label="\u65B0\u5EFA\u4F1A\u8BDD"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="8"/><path d="M12 8v8M8 12h8"/></svg></button>
|
|
534
|
+
<button type="button" class="session-hide-btn flex-shrink-0 ${r?"is-hidden":""}"
|
|
535
|
+
data-hide-toggle="1"
|
|
536
|
+
data-hide-session-id="${p(t)}"
|
|
537
|
+
data-hide-session-agent="${p(n)}"
|
|
538
|
+
title="${r?"\u53D6\u6D88\u9690\u85CF\u4F1A\u8BDD":"\u9690\u85CF\u4F1A\u8BDD"}" aria-label="${r?"\u53D6\u6D88\u9690\u85CF\u4F1A\u8BDD":"\u9690\u85CF\u4F1A\u8BDD"}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><path d="M3 3l18 18"/><path d="M10.6 10.7a2 2 0 0 0 2.7 2.7"/><path d="M9.9 5.1A10.5 10.5 0 0 1 12 4.9c5.4 0 9 5.1 9 7.1a10.9 10.9 0 0 1-3 4.2M6.2 6.3C4.1 7.8 3 10.2 3 12c0 2 3.6 7.1 9 7.1 1.2 0 2.3-.2 3.3-.6"/></svg></button>
|
|
539
|
+
<button type="button" id="btn-share-session-current" class="session-bar-icon" title="\u590D\u5236\u5F53\u524D\u4F1A\u8BDD\u5206\u4EAB\u94FE\u63A5" aria-label="\u5206\u4EAB\u4F1A\u8BDD"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><path d="M12 15V3"/><path d="m8 7 4-4 4 4"/><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-7"/></svg></button>
|
|
540
|
+
<button type="button" id="btn-collapse-chat-chrome" class="session-bar-icon" title="\u6298\u53E0\u9876\u90E8\u5185\u5BB9" aria-label="\u6298\u53E0\u9876\u90E8\u5185\u5BB9"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><path d="M7 10l5 5 5-5"/><path d="M5 5h14"/></svg></button>
|
|
541
|
+
</div>
|
|
542
|
+
<span class="font-bold text-base-content/40 uppercase flex-shrink-0">Note:</span>
|
|
543
|
+
<span class="truncate text-base-content/70 ${a?"":"italic text-base-content/40"}"
|
|
544
|
+
id="session-notes-text" title="${p(a||"Add a note for this session")}">${p(a||"No session note")}</span>
|
|
545
|
+
${d?`<span class="session-branch-current" title="Forked from ${p(d.parentAgent||n)} \xB7 ${p(d.parentSessionId)}">\u2387 from ${p(d.parentSessionId.slice(0,8))}</span>`:""}
|
|
546
|
+
</div>
|
|
547
|
+
<button id="btn-edit-session-notes" class="btn btn-ghost btn-xs px-1.5">Note</button>
|
|
548
|
+
`}function wc(){let e=i("session-notes-bar");if(!e||!c.sessionId)return;let t=c.agent||S.peek()||"claude",n=An(t,c.sessionId);e.innerHTML=`
|
|
549
|
+
<input id="session-notes-input" type="text" class="input input-xs input-bordered flex-1 text-xs"
|
|
550
|
+
placeholder="Note for this session\u2026" value="${p(n.notes||"")}">
|
|
551
|
+
<button id="btn-save-session-notes" class="btn btn-primary btn-xs px-2">Save</button>
|
|
552
|
+
<button id="btn-cancel-session-notes" class="btn btn-ghost btn-xs px-2">Cancel</button>
|
|
553
|
+
`;let s=i("session-notes-input");s?.focus(),s?.select()}function ao(){return{favorite:!1,notes:"",title:"",hidden:!1,branch:null}}function oo(e,t){return{favorite:t.favorite!==void 0?!!t.favorite:!!e.favorite,notes:t.notes!==void 0?String(t.notes||""):String(e.notes||""),title:t.title!==void 0?String(t.title||"").trim():String(e.title||"").trim(),hidden:t.hidden!==void 0?!!t.hidden:!!e.hidden,branch:t.branch!==void 0?t.branch||null:e.branch||null,updatedAt:Date.now()}}function kc(e){return!e?.favorite&&!e?.hidden&&!(e?.notes||"").trim()&&!(e?.title||"").trim()&&!e?.branch}async function $c(e,t,{machineId:n}={}){let s=n||c.machineId||null,a=K(t,e,s),o=T.peek()?.[a]||ao(),r=!o.favorite;T.value={...T.peek(),[a]:{...o,favorite:r,updatedAt:Date.now()}};try{let d=await x("PUT","/api/sessions/meta",{sessionId:e,agent:t,favorite:r,machineId:s||void 0},void 0,{machineId:s||void 0});T.value={...T.peek(),[a]:oo(o,{favorite:d.favorite??r,notes:d.notes,title:d.title,hidden:d.hidden})}}catch(d){T.value={...T.peek(),[a]:o},alert(`Favorite failed: ${d.message}`)}c.sessionId===e&&tt()}async function Sc(e,t,{machineId:n}={}){if(!e)return!1;let s=n||c.machineId||null,a=K(t,e,s),o=T.peek()?.[a]||ao(),r=!o.hidden;T.value={...T.peek(),[a]:{...o,hidden:r,updatedAt:Date.now()}};try{let d=await x("PUT","/api/sessions/meta",{sessionId:e,agent:t,hidden:r,machineId:s||void 0},void 0,{machineId:s||void 0}),u=oo(o,{favorite:d.favorite,notes:d.notes,title:d.title,hidden:d.hidden??r});if(kc(u)){let l={...T.peek()};delete l[a],T.value=l}else T.value={...T.peek(),[a]:u}}catch(d){return T.value={...T.peek(),[a]:o},alert(`Hide failed: ${d.message}`),!1}return c.sessionId===e&&tt(),!0}async function zr(e,t,n,{machineId:s}={}){let a=s||c.machineId||null,o=K(t,e,a),r=T.peek()?.[o]||ao();try{let d=await x("PUT","/api/sessions/meta",{sessionId:e,agent:t,notes:n,machineId:a||void 0},void 0,{machineId:a||void 0});T.value={...T.peek(),[o]:oo(r,{favorite:d.favorite,notes:d.notes??n,title:d.title,hidden:d.hidden})}}catch(d){return alert(`Save note failed: ${d.message}`),!1}return!0}async function bp(e,t,n,{machineId:s}={}){if(!e)return!1;let a=s||c.machineId||null,o=K(t,e,a),r=T.peek()?.[o]||ao(),d=String(n||"").trim().slice(0,200);T.value={...T.peek(),[o]:{...r,title:d,updatedAt:Date.now()}};try{let u=await x("PUT","/api/sessions/meta",{sessionId:e,agent:t,title:d,machineId:a||void 0},void 0,{machineId:a||void 0}),l=oo(r,{favorite:u.favorite,notes:u.notes,title:u.title!==void 0?u.title:d,hidden:u.hidden});if(kc(l)){let f={...T.peek()};delete f[o],T.value=f}else T.value={...T.peek(),[o]:l}}catch(u){return T.value={...T.peek(),[o]:r},alert(`Rename failed: ${u.message}`),!1}return c.sessionId===e&&tt(),!0}function Jr({sessionId:e,agent:t="claude",machineId:n=null,fallbackDisplay:s="",mountEl:a}={}){if(!e||!a)return;document.querySelectorAll(".session-rename-input").forEach(g=>{g.dispatchEvent(new CustomEvent("session-rename-cancel",{bubbles:!0}))});let r=(An(t,e,n).title||"").trim()||s||e.slice(0,8),d=a.innerHTML,u=a.className;a.classList.add("session-rename-active"),a.innerHTML=`<input type="text" class="session-rename-input input input-xs input-bordered w-full min-w-0 text-xs font-mono"
|
|
554
|
+
value="${p(r)}"
|
|
555
|
+
placeholder="Session name (empty = original)"
|
|
556
|
+
maxlength="200"
|
|
557
|
+
data-rename-input="1"
|
|
558
|
+
data-rename-session-id="${p(e)}"
|
|
559
|
+
data-rename-session-agent="${p(t)}"
|
|
560
|
+
data-rename-session-machine="${p(n||"")}"
|
|
561
|
+
autocomplete="off" spellcheck="false" />`;let l=a.querySelector(".session-rename-input");if(!l)return;let f=!1,m=async g=>{if(f)return;f=!0;let w=g?l.value:r;if(a.className=u,!g){a.innerHTML=d;return}await bp(e,t,w,{machineId:n}),document.querySelectorAll(".session-rename-input").forEach(y=>y.remove()),c.sessionId===e&&tt(),T.value={...T.peek()}};l.addEventListener("keydown",g=>{g.stopPropagation(),g.key==="Enter"?(g.preventDefault(),m(!0)):g.key==="Escape"&&(g.preventDefault(),m(!1))}),l.addEventListener("click",g=>g.stopPropagation()),l.addEventListener("mousedown",g=>g.stopPropagation()),l.addEventListener("session-rename-cancel",()=>m(!1)),l.addEventListener("blur",()=>{setTimeout(()=>m(!0),0)}),requestAnimationFrame(()=>{l.focus(),l.select()})}var no,so,Bs=U(()=>{W();F();le();no="",so=""});var Ic={};ls(Ic,{closeMachineMenu:()=>kn,enterMachine:()=>Vr,hideMachinePicker:()=>io,refreshMachinesList:()=>yn,renderMachineMenuList:()=>Os,renderMachinePickerList:()=>ro,showMachinePicker:()=>wn,startMachinePolling:()=>Qr,syncTopbarMachine:()=>Bt});async function yn(){try{let e=await x("GET","/api/machines");ie.value=Array.isArray(e)?e:[]}catch{try{let e=await da();e?.machines&&(ie.value=e.machines)}catch{}}return ie.peek()||[]}function ro(){let e=i("machine-picker-list"),t=i("machine-picker-empty");if(!e)return;let n=ie.peek()||[];if(!n.length){e.innerHTML="",t?.classList.remove("hidden");return}t?.classList.add("hidden"),e.innerHTML=n.map(s=>{let a=s.online!==!1,o=[s.hostname,s.platform].filter(Boolean).join(" \xB7 ");return`
|
|
562
|
+
<button type="button" class="machine-pick-card w-full text-left px-4 py-3 rounded-xl border border-base-300
|
|
563
|
+
hover:border-primary hover:bg-primary/5 transition-colors ${a?"":"opacity-50"}"
|
|
564
|
+
data-pick-machine="${p(s.id)}" ${a?"":"disabled"}>
|
|
565
|
+
<div class="flex items-center gap-2">
|
|
566
|
+
<span class="w-2 h-2 rounded-full flex-shrink-0 ${a?"bg-success":"bg-error"}"></span>
|
|
567
|
+
<span class="font-semibold text-sm font-mono">${p(s.id)}</span>
|
|
568
|
+
</div>
|
|
569
|
+
${o?`<div class="text-xs text-base-content/45 mt-1 pl-4">${p(o)}</div>`:""}
|
|
570
|
+
</button>`}).join("")}function wn(){let e=i("machine-picker");if(!e)return;e.classList.remove("hidden"),Ee(),it.value=!1,ro();let t=i("machine-picker-status");if(t){let n=(ie.peek()||[]).filter(s=>s.online!==!1).length;t.textContent=`${n} online`}}function io(){i("machine-picker")?.classList.add("hidden"),Ee(),it.value=!0}function kn(){i("machine-menu")?.classList.add("hidden")}function Os(){let e=i("machine-menu-list"),t=i("machine-menu-empty");if(!e)return;let n=ie.peek()||[],s=j.peek()||"";if(!n.length){e.innerHTML="",t?.classList.remove("hidden");return}t?.classList.add("hidden"),e.innerHTML=n.map(a=>{let o=a.online!==!1,r=a.id===s,d=[a.hostname,a.platform].filter(Boolean).join(" \xB7 "),u=a.connectedAt?new Date(a.connectedAt).toLocaleTimeString():"";return`
|
|
571
|
+
<button type="button"
|
|
572
|
+
class="machine-menu-item w-full text-left px-2 py-1.5 rounded-md text-xs
|
|
573
|
+
${r?"bg-primary/15 text-primary":"hover:bg-base-200"}
|
|
574
|
+
${o?"":"opacity-50"}"
|
|
575
|
+
data-pick-machine="${p(a.id)}"
|
|
576
|
+
${o?"":"disabled"}>
|
|
577
|
+
<div class="flex items-center gap-1.5">
|
|
578
|
+
<span class="w-1.5 h-1.5 rounded-full flex-shrink-0 ${o?"bg-success":"bg-error"}"></span>
|
|
579
|
+
<span class="font-mono font-semibold truncate flex-1">${p(a.id)}</span>
|
|
580
|
+
${r?'<span class="text-[9px] opacity-70">\u5F53\u524D</span>':""}
|
|
581
|
+
<span class="text-[9px] ${o?"text-success":"text-error"}">${o?"online":"offline"}</span>
|
|
582
|
+
</div>
|
|
583
|
+
${d||u?`<div class="text-[10px] text-base-content/40 pl-3.5 mt-0.5 truncate">${p(d)}${u?" \xB7 "+p(u):""}</div>`:""}
|
|
584
|
+
</button>`}).join("")}function Bt(){let e=i("machine-menu-wrap"),t=i("topbar-machine-label"),n=i("topbar-machine-dot");if(!M.peek()){e?.classList.add("hidden");return}e?.classList.remove("hidden");let s=j.peek()||"",o=(ie.peek()||[]).find(d=>d.id===s),r=o?o.online!==!1:!1;t&&(t.textContent=s||"\u9009\u62E9\u673A\u5668"),n&&(n.classList.toggle("bg-success",!!s&&r),n.classList.toggle("bg-warning",!!s&&!r),n.classList.toggle("bg-base-content/30",!s)),Os()}function Qr(){Lc||(Lc=setInterval(async()=>{if(!M.peek()||!c.token)return;await yn(),Bt();let e=j.peek();if(e){let t=(ie.peek()||[]).find(n=>n.id===e);if(t&&t.online===!1){let n=i("topbar-machine-label");n&&(n.textContent=`${e} (offline)`)}}},15e3)),Ec||(Ec=setInterval(()=>{document.visibilityState!=="visible"||!M.peek()||!c.token||!j.peek()||We({waitFresh:!1,hubIndex:!0}).catch(()=>{})},2e3))}async function Vr(e,{forceReload:t=!1}={}){if(!e)return;let n=j.peek(),s=n&&n!==e;if(Le(e),io(),kn(),Bt(),s||t){try{c.ws?.close()}catch{}c.ws=null,c.sessionId=null,xe(()=>{E.value=null,ke.value=null,oe.value=null});try{let{filesRoot:o,gitRoot:r,filesPath:d}=await Promise.resolve().then(()=>(F(),_i));o.value="",r.value="",d.value=""}catch{}if(s){let{goHome:o}=await Promise.resolve().then(()=>(ns(),Yr));o()}}let a=i("topbar-project");a&&!E.peek()&&(a.textContent=`Machine \xB7 ${e}`),Ns(),await Promise.all([We(),Zn(),Rs(),es().catch(()=>{})]),it.value=!0}var Lc,Ec,Us=U(()=>{W();F();le();It();Bs();Ps();Dn();Lc=null,Ec=null});var Yr={};ls(Yr,{goHome:()=>po,openProject:()=>Xr,resumeSession:()=>nt,switchTab:()=>Tt});function uo(e){for(let t of["files-machine-hint","git-machine-hint"]){let n=i(t);n&&(e?(n.textContent=`@${e}`,n.classList.remove("hidden"),n.title=`Paths are on machine ${e}`):(n.textContent="",n.classList.add("hidden"),n.title=""))}}function Xr(e){Fs=null,ga(),Da(!1),Un(),Wn(),Kn(),Gn();let t=e?.path||"";xe(()=>{E.value=e,ke.value=t,t&&(re.value=t,Se.value=t,V.value="",oe.value=null)}),c.sessionId=null,i("topbar-project").textContent=t||"Project";let n=i("files-root-input");n&&t&&(n.value=t);let s=i("git-root-input");s&&t&&(s.value=t),uo(e?.machineId||j.peek()||c.machineId),i("welcome").classList.add("hidden");let a=i("project-view");a.classList.remove("hidden"),a.style.display="flex",zn(),Fn({sessionId:null}),Pt(),Tt("chat")}function po(){Fs=null,ga(),Da(!1),Un(),Wn(),Kn(),Gn(),E.value=null,ke.value=null,re.value="",Se.value="",V.value="",oe.value=null,c.sessionId=null,Fn({sessionId:null}),uo(null),document.documentElement.classList.remove("boot-restore");let e=i("topbar-project");e&&(e.textContent="Select a session"),Promise.resolve().then(()=>(As(),Cr)).then(({closeNotes:s})=>s({restore:!1})).catch(()=>{});let t=i("welcome");t&&(t.classList.remove("hidden"),t.style.display="",vn(bn()));let n=i("project-view");n&&(n.classList.add("hidden"),n.style.display="none"),wr("/")}async function nt(e,t,n,s,a,o={}){let r=o.tab&&["chat","files","git","shell","memory"].includes(o.tab)?o.tab:"chat",d=o.skipHistory??(r!=="chat"&&r!=="memory"),u=ne.peek().find(L=>L.sessionId===e&&(!a||L.machineId===a||!L.machineId)),l=Xt(),f=l?.sessionId===e?l:null,m=s||u?.agent||f?.agent||"claude",g=a||u?.machineId||f?.machineId||j.peek()||null,w=t||u?.cwd||f?.cwd||null,y=n||u?.configDir||f?.configDir||null;if(Promise.resolve().then(()=>(As(),Cr)).then(({closeNotes:L})=>L({restore:!1})).catch(()=>{}),Un(),Wn(),Kn(),Gn(),g&&g!==c.machineId){Le(g);try{c.ws?.close()}catch{}c.ws=null,Promise.resolve().then(()=>(Us(),Ic)).then(({syncTopbarMachine:L})=>L()).catch(()=>{}),Promise.resolve().then(()=>(It(),to)).then(({loadAllSessions:L})=>L()).catch(()=>{})}c.sessionId=e,Da(!1),yt({sessionId:e,agent:m,machineId:g}).catch(()=>{}),c.configDir=y,c.agent=m,Ne(m),et(),Fn({sessionId:e,agent:m,machineId:g});let H=w;Tc(H,g,e),H&&x("POST","/api/resolve-path",{path:H},void 0,{machineId:g||void 0}).then(L=>{c.sessionId!==e||!L?.path||L.path===H||(H=L.path,Tc(H,g,e),Qo({sessionId:e,cwd:H}))}).catch(()=>{}),zn(),Pt(),Tt(r),Promise.resolve().then(()=>(It(),to)).then(({markActiveSessionRow:L})=>{L(e,m)}).catch(()=>{}),Qo({sessionId:e,cwd:H||w,configDir:y,agent:m,machineId:g,tab:r}),oc({sessionId:e,cwd:H||w,configDir:y,agent:m,machineId:g,display:u?.display||f?.display||"",projectName:u?.projectName||f?.projectName||"",updatedAt:u?.updatedAt||f?.updatedAt||null});let me=X[m]||m,z=`${c.token||""}:${g||""}:${m}:${e}`,ue=0,q=0,J=null,he=(L,ge,be={},ae=!1)=>{if(c.sessionId!==e||c.agent!==m||(c.machineId||null)!==g)return;let Ft=++ue,h=i("messages"),v=!!h.querySelector(".msg-row"),$=h.scrollTop,k=h.scrollHeight,R=!v||h.scrollHeight-h.scrollTop-h.clientHeight<80;if(fl(),be.oldestIndex>0){let B=document.createElement("button");B.className="btn btn-sm btn-ghost",B.textContent="\u52A0\u8F7D\u66F4\u65E9\u7684\u6D88\u606F",B.onclick=async()=>{B.disabled=!0;try{let ve=new URLSearchParams({tail:"80",compact:"1",before:String(be.oldestIndex),agent:m});g&&ve.set("machine",g);let Ke=await x("GET",`/api/sessions/${e}/messages?${ve}`,void 0,void 0,{machineId:g||void 0});if(Ft!==ue||c.sessionId!==e)return;let A=[...Ke.messages,...L],ce={...be,oldestIndex:Ke.oldestIndex,truncated:Ke.oldestIndex>0};J={msgs:A,context:ge,meta:ce},he(A,ge,ce,!0)}catch(ve){B.disabled=!1,B.textContent=`\u52A0\u8F7D\u5931\u8D25\uFF0C\u70B9\u51FB\u91CD\u8BD5 (${ve.message})`}},i("messages").appendChild(B)}if(be.stale&&C("\u5F53\u524D\u663E\u793A\u79BB\u7EBF\u7F13\u5B58\uFF0C\u6B63\u5728\u7B49\u5F85\u673A\u5668\u6062\u590D\u8FDE\u63A5"),!L.length){C(`${me} \xB7 ${e.slice(0,8)}\u2026 \u2014 no history`),gr();return}pt();let Z=40,N=0,Q=()=>{if(c.sessionId!==e||Ft!==ue)return;let B=Math.min(N+Z,L.length);for(;N<B;N++){let A=L[N],ce=O(A.ts??A.timestamp),Wt=A.type||(A.role?"text":null);if(Wt==="text"||A.role&&A.content!=null&&!A.name){(A.role==="assistant"||A.role==="user")&&pt();let Ln=typeof A.content=="string"?A.content:Array.isArray(A.content)?A.content.map(yd=>yd?.text||"").filter(Boolean).join(`
|
|
585
|
+
`):String(A.content??"");Ln&&Ht(A.role==="user"?"user":"assistant",A.role==="user"?"You":me,Ln,{ts:ce,historyIndex:(be.oldestIndex||0)+N})}else Wt==="tool_use"||A.name?br({name:A.name||"tool",input:A.input??A.arguments??{}},{ts:ce}):(Wt==="token_usage"||A.usage)&&(pt(),On(A.usage||A))}if(N<L.length){requestAnimationFrame(Q);return}pt(),ge&&hr(ge);let ve=L.filter(A=>A.type==="token_usage").length||L.filter(A=>A.role==="user").length,Ke=be.truncated?` (showing last ${L.length} of ${be.total||"?"})`:"";C(`\u2500\u2500 ${me} history \xB7 ${ve} turn${ve!==1?"s":""}${Ke} \u2500\u2500`),gr(ae?$+h.scrollHeight-k:R?null:$)};Q()},Ae=async({preferCache:L=!0}={})=>{let ge=++q,be=co.get(z)||(L?await Ll(z):null);if(!(ge!==q||c.sessionId!==e)){if(L&&be&&be.msgs?.length){let ae=Ts(be);he(ae.msgs,ae.context,ae.meta)}be?.msgs?.length||C(`Loading ${me} history\u2026`);try{let ae=g||j.peek()||c.machineId||null;if(M.peek()&&!ae)throw new Error("\u672A\u9009\u62E9\u673A\u5668\uFF0C\u65E0\u6CD5\u52A0\u8F7D\u5386\u53F2");ae&&c.machineId!==ae&&Le(ae);let Ft=async R=>{let Z=new URLSearchParams({tail:"80",compact:"1"});return R&&Z.set("agent",R),ae&&Z.set("machine",ae),x("GET",`/api/sessions/${e}/messages?${Z}`,void 0,void 0,{machineId:ae||void 0,dedupe:!1,cache:"no-store"})},h=await Ft(m);if(ge!==q||c.sessionId!==e)return;let v=Array.isArray(h)?h:h?.messages||[];!v.length&&m&&(h=await Ft(null),v=Array.isArray(h)?h:h?.messages||[]);let $=Array.isArray(h)?null:h?.context||null;if(ge!==q||c.sessionId!==e)return;let k=Array.isArray(h)?{}:{truncated:h?.truncated,total:h?.total,oldestIndex:h?.oldestIndex||0,stale:h?.stale};if(J&&k.oldestIndex>J.meta.oldestIndex&&J.meta.oldestIndex>0){let R=k.oldestIndex-J.meta.oldestIndex;R<=J.msgs.length&&(v=[...J.msgs.slice(0,R),...v],k.oldestIndex=J.meta.oldestIndex)}if(J={msgs:v,context:$,meta:k},v.length&&!k.stale){let R={msgs:v,context:$,meta:k,at:Date.now()};co.set(z,Ts(R)),El(z,R).catch(()=>{})}else co.delete(z);if(D.peek()||i("messages")?.querySelector(".live-stream"))return;he(v,$,k)}catch(ae){if(c.sessionId!==e||ge!==q)return;co.delete(z),C(`${me} \xB7 ${e.slice(0,8)}\u2026 (history unavailable: ${ae.message})`)}}};Fs={sessionId:e,agent:m,refresh:()=>Ae({preferCache:!1}).catch(()=>{})},d?Ae().catch(()=>{}):(await new Promise(L=>requestAnimationFrame(L)),Ae().catch(()=>{})),Es(),tt()}function Tc(e,t,n){if(e){let s=e.split("/").filter(Boolean).pop()||e;xe(()=>{E.value={id:s,name:s,path:e,machineId:t},ke.value=e,re.value=e,Se.value=e,V.value="",oe.value=null}),i("topbar-project").textContent=t?`${e} @${t}`:e;let a=i("files-root-input");a&&(a.value=e);let o=i("git-root-input");o&&(o.value=e),uo(t),i("welcome")?.classList.add("hidden");let r=i("project-view");r&&(r.classList.remove("hidden"),r.style.display="flex",r.style.flexDirection="column",r.style.flex="1",r.style.minHeight="0",r.style.overflow="hidden")}else{i("welcome")?.classList.add("hidden");let s=i("project-view");s&&(s.classList.remove("hidden"),s.style.display="flex",s.style.flexDirection="column",s.style.flex="1",s.style.minHeight="0"),uo(t)}}function Tt(e){Y.value=e}var Fs,lo,co,ns=U(()=>{W();F();le();Cs();pa();_a();hs();Na();It();Bs();Or();Fs=null,lo=null;document.addEventListener("external-session-updated",({detail:e})=>{let t=Fs;!t||!e||e.sessionId!==t.sessionId||e.agent&&t.agent&&e.agent!==t.agent||(lo&&clearTimeout(lo),lo=setTimeout(()=>{lo=null,Fs?.refresh()},140))});co=new Map});F();F();W();var zf=aa({cache:!1,dedupe:!0,retry:0});async function Ni(){try{let e=await fetch("/api/hub");if(!e.ok)return M.value=!1,!1;let t=await e.json();if(t?.hub)return M.value=!0,t}catch{}return M.value=!1,!1}W();F();le();var ua=null;async function Hi(){if(!ua)return!1;ua.prompt();let e=await ua.userChoice.catch(()=>null);return ua=null,document.getElementById("btn-pwa-install")?.classList.add("hidden"),e?.outcome==="accepted"}Dn();pa();_a();Na();W();le();F();Cs();var Sr=["ANTHROPIC_BASE_URL","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_HAIKU_MODEL","CLAUDE_CODE_SUBAGENT_MODEL","CLAUDE_CODE_EFFORT_LEVEL"],cn="claude";function Cl(){document.getElementById("root").insertAdjacentHTML("beforeend",Pu()),Hu()}function Pu(){return`
|
|
586
|
+
<div id="settings-page" class="set-page" hidden>
|
|
587
|
+
<header class="set-island">
|
|
588
|
+
<button type="button" id="set-back" class="btn btn-ghost btn-sm px-2" aria-label="\u8FD4\u56DE">\u2190</button>
|
|
589
|
+
<span class="font-semibold text-sm">Settings</span>
|
|
590
|
+
</header>
|
|
591
|
+
<div class="set-split">
|
|
592
|
+
<nav class="set-nav" aria-label="\u8BBE\u7F6E\u5206\u533A">
|
|
593
|
+
<button type="button" class="set-nav-item btn btn-ghost btn-sm justify-start is-on" data-set-sec="claude">Claude</button>
|
|
594
|
+
<button type="button" class="set-nav-item btn btn-ghost btn-sm justify-start" data-set-sec="workspaces">Workspaces</button>
|
|
595
|
+
<button type="button" class="set-nav-item btn btn-ghost btn-sm justify-start" data-set-sec="quota">\u989D\u5EA6</button>
|
|
596
|
+
<button type="button" class="set-nav-item btn btn-ghost btn-sm justify-start" data-set-sec="users" id="set-nav-users">Users</button>
|
|
597
|
+
<button type="button" class="set-nav-item btn btn-ghost btn-sm justify-start" data-set-sec="password">Password</button>
|
|
598
|
+
<button type="button" class="set-nav-item btn btn-ghost btn-sm justify-start" data-set-sec="mcp">MCP</button>
|
|
599
|
+
</nav>
|
|
600
|
+
<div class="set-main">
|
|
601
|
+
<section class="set-panel" data-set-panel="quota" hidden>
|
|
602
|
+
<h2 class="text-lg font-semibold">\u8BA2\u9605\u989D\u5EA6</h2>
|
|
603
|
+
<p class="text-sm text-base-content/60 mb-4">\u8BFB\u53D6\u5F53\u524D\u673A\u5668\u7684 CLI \u767B\u5F55\u8D26\u53F7\u3002\u989D\u5EA6\u6BCF 5 \u5206\u949F\u66F4\u65B0\uFF0CAPI Key \u548C\u7B2C\u4E09\u65B9\u7F51\u5173\u53EF\u80FD\u65E0\u6CD5\u63D0\u4F9B\u8BA2\u9605\u989D\u5EA6\u3002</p>
|
|
604
|
+
<button type="button" id="quota-refresh" class="btn btn-sm btn-ghost">\u5237\u65B0</button>
|
|
605
|
+
<select id="quota-profile" class="select select-bordered select-sm" aria-label="Claude \u914D\u7F6E\u8D26\u53F7"><option value="">Claude \u9ED8\u8BA4\u8D26\u53F7</option></select>
|
|
606
|
+
<div id="quota-list" class="set-list mt-3"></div>
|
|
607
|
+
</section>
|
|
608
|
+
<section class="set-panel" data-set-panel="claude">
|
|
609
|
+
<h2 class="text-lg font-semibold">Claude env</h2>
|
|
610
|
+
<p class="text-sm text-base-content/60 mb-4">Workspace \u7684 <b>name</b> \u5BF9\u5E94\u4E00\u5957 ANTHROPIC_*\u3002Default \u662F\u5E95\uFF0C\u540C\u540D\u8986\u76D6\u3002</p>
|
|
611
|
+
<label class="form-control mb-3">
|
|
612
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Profile</span></div>
|
|
613
|
+
<select id="ae-profile" class="select select-bordered select-sm"></select>
|
|
614
|
+
</label>
|
|
615
|
+
<div class="set-fields">${Sr.map(t=>`<label class="form-control"><div class="label py-1"><span class="label-text text-xs font-mono">${p(t)}</span></div><input id="ae-${t}" class="input input-bordered input-sm font-mono text-xs" autocomplete="off" spellcheck="false"></label>`).join("")}</div>
|
|
616
|
+
<p id="claude-env-error" class="text-error text-xs mt-2 hidden"></p>
|
|
617
|
+
<button type="button" id="claude-env-save" class="btn btn-primary btn-sm mt-4">Save profile</button>
|
|
618
|
+
</section>
|
|
619
|
+
<section class="set-panel" data-set-panel="workspaces" hidden>
|
|
620
|
+
<h2 class="text-lg font-semibold">Workspaces</h2>
|
|
621
|
+
<p class="text-sm text-base-content/60 mb-4">\u6BCF\u4E2A name \u4E00\u4EFD Claude \u914D\u7F6E\u76EE\u5F55\u3002\u52A0\u5B8C\u540E\u4F1A\u7ACB\u523B\u51FA\u73B0\u5728\u4E0A\u9762\u7684 Profile \u5217\u8868\u91CC\u3002</p>
|
|
622
|
+
<div id="ws-list" class="set-list"></div>
|
|
623
|
+
<div class="set-add">
|
|
624
|
+
<input id="ws-new-name" class="input input-bordered input-sm" placeholder="name e.g. deepseek">
|
|
625
|
+
<input id="ws-new-dir" class="input input-bordered input-sm font-mono text-xs" placeholder="~/.claude-deepseek">
|
|
626
|
+
<button type="button" id="ws-add-btn" class="btn btn-primary btn-sm">Add</button>
|
|
627
|
+
</div>
|
|
628
|
+
<p id="ws-error" class="text-error text-xs mt-2 hidden"></p>
|
|
629
|
+
</section>
|
|
630
|
+
<section class="set-panel" data-set-panel="users" hidden>
|
|
631
|
+
<h2 class="text-lg font-semibold">Users</h2>
|
|
632
|
+
<p class="text-sm text-base-content/60 mb-4">Admin \u5206\u914D\u8D26\u53F7\u3002\u5BF9\u65B9\u7528\u540C\u4E00\u767B\u5F55\u9875\uFF0C\u6CA1\u6709\u516C\u5F00\u6CE8\u518C\u3002</p>
|
|
633
|
+
<div id="users-list" class="set-list"></div>
|
|
634
|
+
<div class="set-add">
|
|
635
|
+
<input id="user-new-name" class="input input-bordered input-sm" placeholder="username">
|
|
636
|
+
<input id="user-new-pass" type="password" class="input input-bordered input-sm" placeholder="password">
|
|
637
|
+
<select id="user-new-role" class="select select-bordered select-sm">
|
|
638
|
+
<option value="editor">editor</option>
|
|
639
|
+
<option value="viewer">viewer</option>
|
|
640
|
+
<option value="admin">admin</option>
|
|
641
|
+
</select>
|
|
642
|
+
<button type="button" id="user-add-btn" class="btn btn-primary btn-sm">Invite</button>
|
|
643
|
+
</div>
|
|
644
|
+
<p id="users-error" class="text-error text-xs mt-2 hidden"></p>
|
|
645
|
+
</section>
|
|
646
|
+
<section class="set-panel" data-set-panel="password" hidden>
|
|
647
|
+
<h2 class="text-lg font-semibold">Password</h2>
|
|
648
|
+
<p class="text-sm text-base-content/60 mb-4">\u6539\u81EA\u5DF1\u7684\u767B\u5F55\u5BC6\u7801\u3002\u7BA1\u7406\u5458\u91CD\u7F6E\u522B\u4EBA\u7684\u5BC6\u7801\u5728 Users\u3002</p>
|
|
649
|
+
<label class="form-control mb-2">
|
|
650
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Current</span></div>
|
|
651
|
+
<input id="pw-current" type="password" class="input input-bordered input-sm">
|
|
652
|
+
</label>
|
|
653
|
+
<label class="form-control mb-2">
|
|
654
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">New</span></div>
|
|
655
|
+
<input id="pw-next" type="password" class="input input-bordered input-sm">
|
|
656
|
+
</label>
|
|
657
|
+
<label class="form-control mb-2">
|
|
658
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Again</span></div>
|
|
659
|
+
<input id="pw-next2" type="password" class="input input-bordered input-sm">
|
|
660
|
+
</label>
|
|
661
|
+
<p id="pw-error" class="text-error text-xs mt-2 hidden"></p>
|
|
662
|
+
<button type="button" id="pw-save" class="btn btn-primary btn-sm mt-3">Update password</button>
|
|
663
|
+
</section>
|
|
664
|
+
<section class="set-panel" data-set-panel="mcp" hidden>
|
|
665
|
+
<h2 class="text-lg font-semibold">MCP token</h2>
|
|
666
|
+
<p class="text-sm text-base-content/60 mb-4">\u53D1\u7ED9\u5916\u90E8 Agent \u7684\u77ED\u671F\u51ED\u8BC1\uFF0C\u53EA\u663E\u793A\u4E00\u6B21\u3002\u9700\u8981\u5148\u9009\u4E00\u53F0\u5728\u7EBF\u673A\u5668\u3002</p>
|
|
667
|
+
<label class="form-control mb-3">
|
|
668
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Expiry</span></div>
|
|
669
|
+
<select id="mcp-token-expiry" class="select select-bordered select-sm">
|
|
670
|
+
<option value="86400">24 hours</option>
|
|
671
|
+
<option value="604800">7 days</option>
|
|
672
|
+
<option value="2592000">30 days</option>
|
|
673
|
+
</select>
|
|
674
|
+
</label>
|
|
675
|
+
<button type="button" id="mcp-token-generate" class="btn btn-primary btn-sm">Generate</button>
|
|
676
|
+
<div id="mcp-token-result" class="hidden set-token">
|
|
677
|
+
<p id="mcp-token-url" class="font-mono text-xs text-base-content/50"></p>
|
|
678
|
+
<textarea id="mcp-token-value" readonly class="textarea textarea-bordered font-mono text-xs" rows="5"></textarea>
|
|
679
|
+
<button type="button" id="mcp-token-copy" class="btn btn-ghost btn-xs border border-base-300">Copy token</button>
|
|
680
|
+
</div>
|
|
681
|
+
<p id="mcp-token-error" class="text-error text-xs mt-2 hidden"></p>
|
|
682
|
+
</section>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
</div>`}function Hu(){i("quota-refresh")?.addEventListener("click",$r),i("quota-profile")?.addEventListener("change",$r),i("set-back")?.addEventListener("click",Tl),document.querySelectorAll("[data-set-sec]").forEach(e=>{e.addEventListener("click",()=>Ha(e.dataset.setSec))}),i("ws-add-btn")?.addEventListener("click",kr),i("ws-new-name")?.addEventListener("keydown",e=>{e.key==="Enter"&&kr()}),i("ws-new-dir")?.addEventListener("keydown",e=>{e.key==="Enter"&&kr()}),i("mcp-token-generate")?.addEventListener("click",Fu),i("mcp-token-copy")?.addEventListener("click",Wu),i("claude-env-save")?.addEventListener("click",Bu),i("ae-profile")?.addEventListener("change",()=>{Ms()}),i("user-add-btn")?.addEventListener("click",Ou),i("pw-save")?.addEventListener("click",Uu),document.addEventListener("router:settings",()=>qa()),document.addEventListener("router:home",()=>{qu()&&Tl()})}function Ha(e){cn=e||"claude",document.querySelectorAll("[data-set-sec]").forEach(t=>t.classList.toggle("is-on",t.dataset.setSec===cn)),document.querySelectorAll("[data-set-panel]").forEach(t=>{t.hidden=t.dataset.setPanel!==cn}),cn==="quota"&&$r()}var Il=0;async function $r(){let e=++Il,t=i("quota-list");if(!t)return;t.textContent="\u6B63\u5728\u8BFB\u53D6\u5F53\u524D\u673A\u5668\u7684\u989D\u5EA6\u2026";let n=j.peek(),s=i("quota-profile"),a=s?.value||"";if(s&&(s.innerHTML='<option value="">Claude \u9ED8\u8BA4\u8D26\u53F7</option>'+(pe.peek()||[]).map(r=>`<option value="${p(r.configDir)}">${p(r.name||r.configDir)}</option>`).join(""),s.value=a),M.peek()&&!n){t.textContent="\u8BF7\u5148\u9009\u62E9\u673A\u5668";return}let o=await Promise.all(["claude","grok","codex"].map(async r=>{let d=new URLSearchParams({agent:r});r==="claude"&&s?.value&&d.set("configDir",s.value);try{return await x("GET",`/api/agents/quota?${d}`,void 0,void 0,{machineId:n||void 0})}catch(u){return{agent:r,meters:[],message:u.message}}}));e!==Il||n!==j.peek()||(t.innerHTML=o.map(r=>`<div class="border border-base-300 rounded-lg p-4 mb-3">
|
|
686
|
+
<h3 class="font-semibold">${p(r.agent)} ${p(r.plan||"")}</h3>
|
|
687
|
+
${(r.meters||[]).map(d=>`<div class="mt-3"><div class="text-sm">${p(d.label)} \xB7 \u5DF2\u7528 ${p(d.usedPercent)}% \xB7 \u5269\u4F59 ${p(d.remainingPercent)}%</div>
|
|
688
|
+
<progress class="progress progress-primary w-full" max="100" value="${Number(d.usedPercent)}"></progress>
|
|
689
|
+
${d.resetsAt?`<div class="text-xs opacity-60">\u91CD\u7F6E\uFF1A${p(new Date(d.resetsAt).toLocaleString())}</div>`:""}</div>`).join("")||`<p class="text-sm opacity-60 mt-2">${p(r.message||"\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u989D\u5EA6")}</p>`}
|
|
690
|
+
${r.fetchedAt?`<div class="text-xs opacity-50 mt-2">\u66F4\u65B0\u4E8E ${p(new Date(r.fetchedAt).toLocaleString())}</div>`:""}
|
|
691
|
+
</div>`).join(""))}function qa(e){let t=i("settings-page");if(!t)return;t.hidden=!1,document.documentElement.classList.add("settings-open"),Ha(e||cn||"claude"),Lr(),Er(),Ms(),Ml(),(i("mcp-token-settings")||document.querySelector('[data-set-panel="mcp"]'))&&!M.peek()&&document.querySelector('[data-set-sec="mcp"]')?.classList.add("hidden"),(location.hash||"")!=="#/settings"&&(location.hash="/settings")}function Tl(){let e=i("settings-page");e&&(e.hidden=!0),document.documentElement.classList.remove("settings-open"),(location.hash||"")==="#/settings"&&(location.hash="")}function qu(){return!i("settings-page")?.hidden}function Lr(){let e=i("ws-list");if(!e)return;let t=pe.peek()||[];if(!t.length){e.innerHTML='<div class="text-xs text-base-content/40">\u8FD8\u6CA1\u6709 workspace</div>';return}e.innerHTML=t.map((n,s)=>`
|
|
692
|
+
<div class="set-row" style="--index:${s}">
|
|
693
|
+
<div class="set-row-body">
|
|
694
|
+
<div class="text-sm font-medium">${p(n.name)}</div>
|
|
695
|
+
<div class="text-xs font-mono text-base-content/50">${p(n.configDir)}</div>
|
|
696
|
+
</div>
|
|
697
|
+
${t.length>1?`<button type="button" class="btn btn-ghost btn-xs" data-ws-delete="${p(n.id)}">Remove</button>`:'<span class="text-xs text-base-content/40">default</span>'}
|
|
698
|
+
</div>`).join(""),e.querySelectorAll("[data-ws-delete]").forEach(n=>{n.addEventListener("click",()=>Ru(n.dataset.wsDelete))})}function Er(e){let t=i("ae-profile");if(!t)return;let n=e??t.value,s=pe.peek()||[],a=[...new Set(s.map(o=>o.name).filter(Boolean))];t.innerHTML='<option value="">Default</option>'+a.map(o=>`<option value="${p(o)}">${p(o)}</option>`).join(""),[...t.options].some(o=>o.value===n)?t.value=n:t.value=""}async function kr(){let e=i("ws-new-name").value.trim(),t=i("ws-new-dir").value.trim(),n=i("ws-error");if(n.classList.add("hidden"),!e||!t){n.textContent="\u9700\u8981 name \u548C\u8DEF\u5F84",n.classList.remove("hidden");return}try{let s=await x("POST","/api/workspaces",{name:e,configDir:t}),a=[...(pe.peek()||[]).filter(o=>o.id!==s.id),s];pe.value=a,Is(a),i("ws-new-name").value="",i("ws-new-dir").value="",Lr(),Er(s.name),await Ms(),Ha("claude")}catch(s){n.textContent=s.message,n.classList.remove("hidden")}}async function Ru(e){try{await x("DELETE",`/api/workspaces/${e}`);let t=(pe.peek()||[]).filter(n=>n.id!==e);pe.value=t,Is(t),Lr(),Er(""),await Ms()}catch(t){let n=i("ws-error");n&&(n.textContent=t.message,n.classList.remove("hidden"))}}async function Ms(){try{let e=i("ae-profile")?.value||"",t=e?`?name=${encodeURIComponent(e)}`:"",n=await x("GET",`/api/agent-env${t}`),s=n.env||{},a=e?{}:n.process||{};for(let o of Sr){let r=i(`ae-${o}`);if(!r)continue;let d=s[o]??a[o];d&&typeof d=="object"&&d.set?(r.placeholder=`saved ${d.preview||"\u2022\u2022\u2022\u2022"}`,r.value="",r.dataset.keep="1"):(r.value=typeof d=="string"?d:"",r.placeholder=o,r.dataset.keep="")}}catch{}}async function Bu(){let e=i("claude-env-error");e?.classList.add("hidden");let t={};for(let n of Sr){let s=i(`ae-${n}`);if(!s)continue;let a=s.value.trim();a?t[n]=a:s.dataset.keep==="1"?t[n]={set:!0}:t[n]=""}try{let n=i("ae-profile")?.value||"";await x("PUT","/api/agent-env",{name:n,env:t}),await Ms()}catch(n){e&&(e.textContent=n.message,e.classList.remove("hidden"))}}async function Ml(){let e=i("set-nav-users"),t=document.querySelector('[data-set-panel="users"]');try{let n=await x("GET","/api/collab/me"),s=n.role==="admin"||n.role==="owner";if(e?.classList.toggle("hidden",!s),t&&(t.hidden=!s||cn!=="users"),!s){cn==="users"&&Ha("claude");return}let a=await x("GET","/api/collab/users"),o=i("users-list"),r=Array.isArray(a)?a:[];o.innerHTML=r.map(d=>`<div class="set-row"><div class="text-sm font-medium flex-1">${p(d.username)}</div><div class="text-xs text-base-content/50">${p(d.role||"")}</div></div>`).join("")||'<div class="text-xs text-base-content/40">\u8FD8\u6CA1\u6709\u5176\u4ED6\u7528\u6237</div>'}catch{e?.classList.add("hidden")}}async function Ou(){let e=i("users-error");e?.classList.add("hidden");let t=i("user-new-name")?.value.trim(),n=i("user-new-pass")?.value||"",s=i("user-new-role")?.value||"editor";if(!t||!n){e&&(e.textContent="\u9700\u8981\u7528\u6237\u540D\u548C\u5BC6\u7801",e.classList.remove("hidden"));return}try{await x("POST","/api/collab/users",{username:t,password:n,role:s}),i("user-new-name").value="",i("user-new-pass").value="",await Ml()}catch(a){e&&(e.textContent=a.message,e.classList.remove("hidden"))}}async function Uu(){let e=i("pw-error");e?.classList.add("hidden");let t=i("pw-current")?.value||"",n=i("pw-next")?.value||"",s=i("pw-next2")?.value||"";if(n!==s){e&&(e.textContent="\u4E24\u6B21\u65B0\u5BC6\u7801\u4E0D\u4E00\u81F4",e.classList.remove("hidden"));return}try{await x("POST","/api/auth/password",{current:t,next:n}),i("pw-current").value="",i("pw-next").value="",i("pw-next2").value=""}catch(a){e&&(e.textContent=a.message,e.classList.remove("hidden"))}}async function Fu(){let e=i("mcp-token-result"),t=i("mcp-token-error");e?.classList.add("hidden"),t?.classList.add("hidden");let n=j.peek();if(!n){t.textContent="\u8BF7\u5148\u5728\u4E3B\u754C\u9762\u9009\u4E00\u53F0\u5728\u7EBF\u673A\u5668\u3002",t.classList.remove("hidden");return}try{let s=Number(i("mcp-token-expiry").value),a=await x("POST",`/api/mcp/tokens?machine=${encodeURIComponent(n)}`,{expiresInSeconds:s});i("mcp-token-value").value=a.token||"";let o=i("mcp-token-url");o&&(o.textContent=`${location.origin}/mcp`),e.classList.remove("hidden")}catch(s){t.textContent=s.message,t.classList.remove("hidden")}}async function Wu(){let e=i("mcp-token-value")?.value;if(e)try{await navigator.clipboard.writeText(e)}catch{i("mcp-token-value")?.select(),document.execCommand("copy")}}As();Ps();ya();F();var Yl=()=>`
|
|
699
|
+
<div id="auth-screen" class="${c.token?"hidden":""} flex items-center justify-center h-full p-4" ${c.token?'style="display:none"':""}>
|
|
700
|
+
<div class="card bg-base-200 border border-base-300 w-full max-w-sm shadow-xl">
|
|
701
|
+
<div class="card-body gap-3 p-8">
|
|
702
|
+
<h1 class="text-xl font-bold">\u{1F916} Agent UI</h1>
|
|
703
|
+
<p id="auth-subtitle" class="text-sm text-base-content/60 mb-1">Claude \xB7 Codex \xB7 Grok \xB7 Gemini \xB7 Cursor</p>
|
|
704
|
+
<a href="/download/agentui-android.apk" class="btn btn-ghost btn-sm border border-base-300" download>\u4E0B\u8F7D Android App</a>
|
|
705
|
+
<form id="auth-form" class="flex flex-col gap-3" autocomplete="on" action="#">
|
|
706
|
+
<label class="form-control">
|
|
707
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Username</span></div>
|
|
708
|
+
<input id="auth-username" type="text" class="input input-bordered input-sm" placeholder="username" autocomplete="username">
|
|
709
|
+
</label>
|
|
710
|
+
<label class="form-control">
|
|
711
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Password</span></div>
|
|
712
|
+
<input id="auth-password" type="password" class="input input-bordered input-sm" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022" autocomplete="current-password">
|
|
713
|
+
</label>
|
|
714
|
+
<button type="submit" id="auth-btn" class="btn btn-primary btn-sm mt-1" data-mode="login">Sign In</button>
|
|
715
|
+
</form>
|
|
716
|
+
<div id="auth-error" class="alert alert-error text-xs py-2 hidden"></div>
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
</div>`,Xl=(e={})=>{let t=!!e.restoreSession,n=c.token?"":"hidden",s=c.token?"display:flex":"display:none";return`
|
|
720
|
+
<div id="sidebar-overlay" class="hidden fixed inset-0 bg-black/50 z-[9]" aria-hidden="true"></div>
|
|
721
|
+
<div id="app" class="${n} flex-col flex-1 overflow-hidden" style="${s}">
|
|
722
|
+
<div id="topbar" class="flex items-center gap-2 px-3 bg-base-200 border-b border-base-300 flex-shrink-0" style="height:44px">
|
|
723
|
+
<button id="hamburger" class="btn btn-ghost btn-sm px-2 text-lg" aria-label="\u6253\u5F00\u9879\u76EE\u4E0E\u4F1A\u8BDD\u4FA7\u680F" aria-controls="sidebar" aria-expanded="false">\u2630</button>
|
|
724
|
+
<span id="btn-home" class="font-semibold text-sm hidden sm:inline cursor-pointer hover:text-primary transition-colors select-none">\u{1F916} Agent UI</span>
|
|
725
|
+
<span class="text-base-300 hidden sm:inline">/</span>
|
|
726
|
+
<div id="machine-menu-wrap" class="relative hidden flex-shrink-0">
|
|
727
|
+
<button type="button" id="btn-machine-menu" class="btn btn-ghost btn-xs border border-base-300 font-mono gap-1 max-w-[11rem]"
|
|
728
|
+
title="\u673A\u5668\u5217\u8868 / \u5207\u6362">
|
|
729
|
+
<span id="topbar-machine-dot" class="w-1.5 h-1.5 rounded-full bg-success flex-shrink-0"></span>
|
|
730
|
+
<span id="topbar-machine-label" class="truncate">\u673A\u5668</span>
|
|
731
|
+
<span class="text-[10px] opacity-50">\u25BE</span>
|
|
732
|
+
</button>
|
|
733
|
+
<div id="machine-menu" class="hidden absolute left-0 top-full mt-1 z-50 w-72 max-h-80 overflow-y-auto
|
|
734
|
+
rounded-lg border border-base-300 bg-base-100 shadow-xl p-2">
|
|
735
|
+
<div class="flex items-center justify-between px-1 pb-1.5 mb-1 border-b border-base-300">
|
|
736
|
+
<span class="text-[10px] uppercase tracking-wide text-base-content/45 font-semibold">Machines</span>
|
|
737
|
+
<button type="button" id="btn-refresh-machines-menu" class="btn btn-ghost btn-xs px-1 text-[10px]">\u21BB</button>
|
|
738
|
+
</div>
|
|
739
|
+
<div id="machine-menu-list" class="flex flex-col gap-1"></div>
|
|
740
|
+
<p id="machine-menu-empty" class="text-xs text-base-content/40 px-1 py-2 hidden">\u6682\u65E0\u673A\u5668\u5728\u7EBF</p>
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
<div id="recent-menu-wrap" class="relative flex-shrink-0">
|
|
744
|
+
<button type="button" id="btn-recent-sessions" class="btn btn-ghost btn-xs border border-base-300 gap-1 min-h-8 px-2"
|
|
745
|
+
title="\u6700\u8FD1\u4F1A\u8BDD / \u5FEB\u901F\u8DF3\u8F6C" aria-haspopup="listbox" aria-expanded="false">
|
|
746
|
+
<span>\u6700\u8FD1</span>
|
|
747
|
+
<span class="text-[10px] opacity-50">\u25BE</span>
|
|
748
|
+
</button>
|
|
749
|
+
</div>
|
|
750
|
+
<div id="notifications-wrap" class="relative flex-shrink-0">
|
|
751
|
+
<button type="button" id="btn-notifications" class="btn btn-ghost btn-xs border border-base-300 gap-1 min-h-8 px-2"
|
|
752
|
+
title="\u901A\u77E5" aria-haspopup="dialog" aria-expanded="false">
|
|
753
|
+
<span>\u{1F514}</span>
|
|
754
|
+
<span id="notifications-badge" class="hidden inline-flex min-w-5 h-5 px-1 items-center justify-center rounded-full bg-error text-error-content text-[10px] font-bold">0</span>
|
|
755
|
+
</button>
|
|
756
|
+
</div>
|
|
757
|
+
<span id="topbar-project" class="text-sm text-base-content/50 flex-1 truncate min-w-0">Select a session</span>
|
|
758
|
+
<span id="conn-dot" class="w-2 h-2 rounded-full bg-base-content/30 flex-shrink-0" title="\u8FDE\u63A5\u72B6\u6001"></span>
|
|
759
|
+
<div class="flex gap-2 topbar-actions">
|
|
760
|
+
<button id="btn-pwa-install" class="btn btn-ghost btn-xs border border-base-300 hidden" title="\u5B89\u88C5\u5230\u4E3B\u5C4F\u5E55">\u5B89\u88C5</button>
|
|
761
|
+
<a href="/download/agentui-android.apk" class="btn btn-ghost btn-xs border border-base-300" title="\u4E0B\u8F7D Android APK" download>Android</a>
|
|
762
|
+
<button id="btn-meta-agent" class="btn btn-ghost btn-xs border border-primary/40 text-primary topbar-icon-btn" title="Meta Agent \u2014 \u62A5\u544A / \u95EE\u7B54 / VLM" aria-label="\u6253\u5F00 Meta Agent">
|
|
763
|
+
<svg class="topbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="m12 2 1.6 6.4L20 10l-6.4 1.6L12 18l-1.6-6.4L4 10l6.4-1.6L12 2Z"/><path d="m19 16 .7 2.3L22 19l-2.3.7L19 22l-.7-2.3L16 19l2.3-.7L19 16Z"/></svg><span class="topbar-icon-label">Agent</span>
|
|
764
|
+
</button>
|
|
765
|
+
<button id="btn-notes" class="btn btn-ghost btn-xs border border-base-300 topbar-icon-btn" title="\u8BB0\u4E8B" aria-label="\u8BB0\u4E8B">
|
|
766
|
+
<svg class="topbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><path d="M5 4h11l3 3v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z"/><path d="M8 9h7M8 13h7M8 17h4"/></svg><span class="topbar-icon-label">\u8BB0\u4E8B</span>
|
|
767
|
+
</button>
|
|
768
|
+
<button id="btn-new-session" class="btn btn-ghost btn-xs border border-base-300 topbar-icon-btn" title="New session" aria-label="\u65B0\u5EFA\u4F1A\u8BDD">
|
|
769
|
+
<svg class="topbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="12" cy="12" r="8"/><path d="M12 8v8M8 12h8"/></svg><span class="topbar-icon-label">New</span>
|
|
770
|
+
</button>
|
|
771
|
+
<button id="btn-theme" class="btn btn-ghost btn-xs border border-base-300 topbar-icon-btn" title="\u5207\u6362\u4E3B\u9898" aria-label="\u5207\u6362\u4E3B\u9898"><svg class="topbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><path d="M20 15.5A8 8 0 0 1 8.5 4 8 8 0 1 0 20 15.5Z"/></svg></button>
|
|
772
|
+
<button id="btn-settings" class="btn btn-ghost btn-xs border border-base-300 topbar-icon-btn" title="\u8BBE\u7F6E" aria-label="\u8BBE\u7F6E"><svg class="topbar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .34 1.88l.06.06-2.12 2.12-.06-.06A1.7 1.7 0 0 0 15.74 18a1.7 1.7 0 0 0-1.02 1.56V20h-3v-.44A1.7 1.7 0 0 0 10.7 18a1.7 1.7 0 0 0-1.88.34l-.06.06-2.12-2.12.06-.06A1.7 1.7 0 0 0 7.04 14.3 1.7 1.7 0 0 0 5.5 13.28H5v-3h.5a1.7 1.7 0 0 0 1.54-1.02A1.7 1.7 0 0 0 6.7 7.38l-.06-.06L8.76 5.2l.06.06A1.7 1.7 0 0 0 10.7 5a1.7 1.7 0 0 0 1.02-1.56V3h3v.44A1.7 1.7 0 0 0 15.74 5a1.7 1.7 0 0 0 1.88-.34l.06-.06 2.12 2.12-.06.06a1.7 1.7 0 0 0-.34 1.88 1.7 1.7 0 0 0 1.56 1.02h.5v3h-.5A1.7 1.7 0 0 0 19.4 15Z"/></svg></button>
|
|
773
|
+
<button id="btn-logout" class="btn btn-ghost btn-xs border border-base-300">Sign out</button>
|
|
774
|
+
</div>
|
|
775
|
+
</div>
|
|
776
|
+
<button id="btn-expand-chat-chrome" class="chat-chrome-fab hidden" type="button"
|
|
777
|
+
title="\u663E\u793A\u4F1A\u8BDD\u5DE5\u5177\u680F" aria-label="\u663E\u793A\u4F1A\u8BDD\u5DE5\u5177\u680F">
|
|
778
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><path d="M7 14l5-5 5 5"/><path d="M5 19h14"/></svg>
|
|
779
|
+
</button>
|
|
780
|
+
<!-- Fixed panel + backdrop: siblings of topbar so flex layout never clips them -->
|
|
781
|
+
<div id="recent-menu-backdrop" class="hidden fixed inset-0 z-[55] bg-black/40" aria-hidden="true"></div>
|
|
782
|
+
<div id="recent-menu" class="hidden fixed z-[60] w-80 max-h-[min(24rem,70vh)] overflow-y-auto
|
|
783
|
+
rounded-lg border border-base-300 bg-base-100 shadow-xl p-2"
|
|
784
|
+
role="listbox" aria-label="\u6700\u8FD1\u4F1A\u8BDD">
|
|
785
|
+
<div class="flex items-center justify-between px-1 pb-1.5 mb-1 border-b border-base-300 sticky top-0 bg-base-100 z-[1]">
|
|
786
|
+
<span class="text-[10px] uppercase tracking-wide text-base-content/45 font-semibold">\u6700\u8FD1\u4F1A\u8BDD</span>
|
|
787
|
+
<span id="recent-menu-count" class="text-[10px] text-base-content/35 font-mono"></span>
|
|
788
|
+
</div>
|
|
789
|
+
<div id="recent-menu-list" class="flex flex-col gap-0.5"></div>
|
|
790
|
+
<p id="recent-menu-empty" class="text-xs text-base-content/40 px-1 py-2 hidden">\u6682\u65E0\u6700\u8FD1\u4F1A\u8BDD</p>
|
|
791
|
+
</div>
|
|
792
|
+
<div id="notifications-backdrop" class="hidden fixed inset-0 z-[55] bg-black/40" aria-hidden="true"></div>
|
|
793
|
+
<div id="notifications-menu" class="hidden fixed z-[60] w-[min(26rem,calc(100vw-1rem))] max-h-[min(30rem,75vh)] overflow-y-auto
|
|
794
|
+
rounded-lg border border-base-300 bg-base-100 shadow-xl p-2"
|
|
795
|
+
role="dialog" aria-label="\u901A\u77E5\u4E2D\u5FC3">
|
|
796
|
+
<div class="flex items-center justify-between px-1 pb-1.5 mb-1 border-b border-base-300 sticky top-0 bg-base-100 z-[1]">
|
|
797
|
+
<span class="text-[10px] uppercase tracking-wide text-base-content/45 font-semibold">\u901A\u77E5</span>
|
|
798
|
+
<button type="button" id="btn-notifications-read-all" class="btn btn-ghost btn-xs px-1 text-[10px]">\u5168\u90E8\u5DF2\u8BFB</button>
|
|
799
|
+
</div>
|
|
800
|
+
<div id="notifications-menu-list" class="flex flex-col gap-1"></div>
|
|
801
|
+
<p id="notifications-menu-empty" class="text-xs text-base-content/40 px-1 py-2 hidden">\u6682\u65E0\u901A\u77E5</p>
|
|
802
|
+
</div>
|
|
803
|
+
<!-- Hub: only when no remembered machine (or last one offline) -->
|
|
804
|
+
<div id="machine-picker" class="hidden fixed inset-0 z-[60] bg-base-100 flex items-center justify-center p-4">
|
|
805
|
+
<div class="w-full max-w-md">
|
|
806
|
+
<h2 class="text-xl font-bold mb-1">\u9009\u62E9\u673A\u5668</h2>
|
|
807
|
+
<p class="text-sm text-base-content/55 mb-4">\u9996\u6B21\u4F7F\u7528\u6216\u4E0A\u6B21\u9009\u62E9\u7684\u673A\u5668\u4E0D\u5728\u7EBF\u65F6\u9700\u8981\u9009\u62E9\u3002\u4E4B\u540E\u4F1A\u8BB0\u4F4F\u4F60\u7684\u9009\u62E9\uFF0C\u4E5F\u53EF\u968F\u65F6\u5728\u9876\u680F\u5207\u6362\u3002</p>
|
|
808
|
+
<div id="machine-picker-list" class="flex flex-col gap-2 mb-4"></div>
|
|
809
|
+
<p id="machine-picker-empty" class="text-sm text-base-content/40 hidden">\u6682\u65E0\u5728\u7EBF\u673A\u5668\u3002\u8BF7\u5728\u4E1A\u52A1\u673A\u4E0A\u8FD0\u884C <code class="text-xs">npm run client</code> \u540E\u70B9\u5237\u65B0\u3002</p>
|
|
810
|
+
<div class="flex items-center gap-2">
|
|
811
|
+
<button id="btn-refresh-machines" class="btn btn-ghost btn-sm border border-base-300">\u21BB \u5237\u65B0</button>
|
|
812
|
+
<span id="machine-picker-status" class="text-xs text-base-content/40"></span>
|
|
813
|
+
</div>
|
|
814
|
+
</div>
|
|
815
|
+
</div>
|
|
816
|
+
<div class="flex flex-1 overflow-hidden relative">
|
|
817
|
+
<aside id="sidebar" class="bg-base-200 border-r border-base-300 flex flex-col flex-shrink-0 overflow-hidden" style="width:280px;min-width:180px;max-width:520px" aria-label="\u9879\u76EE\u4E0E\u4F1A\u8BDD" tabindex="-1">
|
|
818
|
+
<div class="flex items-center justify-between px-3 py-2 border-b border-base-300 flex-shrink-0">
|
|
819
|
+
<span class="text-xs uppercase tracking-wider text-base-content/50 font-medium">Projects</span>
|
|
820
|
+
<div class="flex items-center gap-1">
|
|
821
|
+
<span id="session-filter-badge" class="hidden text-[10px] text-primary cursor-pointer">\xD7 filter</span>
|
|
822
|
+
<button id="sidebar-refresh" class="btn btn-ghost btn-xs px-1 text-[10px] text-base-content/40" title="Refresh">\u21BB</button>
|
|
823
|
+
</div>
|
|
824
|
+
</div>
|
|
825
|
+
<div id="ws-tabs" class="flex overflow-x-auto border-b border-base-300 flex-shrink-0" style="scrollbar-width:none"></div>
|
|
826
|
+
<div class="px-2 py-1.5 border-b border-base-300 flex-shrink-0 relative">
|
|
827
|
+
<div class="flex gap-1.5">
|
|
828
|
+
<input id="session-search" type="text" placeholder="Search projects & recent work\u2026"
|
|
829
|
+
class="input input-xs input-bordered flex-1 min-w-0 text-xs" autocomplete="off">
|
|
830
|
+
<button id="sidebar-filter-toggle" type="button" class="btn btn-ghost btn-xs border border-base-300 px-2" title="\u7B5B\u9009\u9879\u76EE" aria-expanded="false">\u2699</button>
|
|
831
|
+
</div>
|
|
832
|
+
<div id="sidebar-filter-menu" class="hidden absolute left-2 right-2 top-[calc(100%-.25rem)] z-30 rounded-lg border border-base-300 bg-base-100 p-2 shadow-xl">
|
|
833
|
+
<div class="text-[10px] uppercase tracking-wide text-base-content/45 mb-1.5">Agents \xB7 multi-select</div>
|
|
834
|
+
<div class="grid grid-cols-2 gap-1 text-xs">
|
|
835
|
+
<label><input type="checkbox" data-agent-option="claude"> Claude</label>
|
|
836
|
+
<label><input type="checkbox" data-agent-option="codex"> Codex</label>
|
|
837
|
+
<label><input type="checkbox" data-agent-option="grok"> Grok</label>
|
|
838
|
+
<label><input type="checkbox" data-agent-option="gemini"> Gemini</label>
|
|
839
|
+
<label><input type="checkbox" data-agent-option="cursor"> Cursor</label>
|
|
840
|
+
</div>
|
|
841
|
+
<div class="mt-2 pt-2 border-t border-base-300 flex gap-3 text-xs">
|
|
842
|
+
<label><input id="filter-favorites" type="checkbox"> Favorites</label>
|
|
843
|
+
<label><input id="filter-hidden" type="checkbox"> Hidden</label>
|
|
844
|
+
<button id="filter-clear" type="button" class="ml-auto text-primary">Clear</button>
|
|
845
|
+
</div>
|
|
846
|
+
</div>
|
|
847
|
+
<div id="search-status" class="hidden text-[10px] text-base-content/40 px-0.5"></div>
|
|
848
|
+
</div>
|
|
849
|
+
<div id="session-list" class="overflow-y-auto flex-1"></div>
|
|
850
|
+
<div class="sidebar-mobile-actions hidden border-t border-base-300 px-2 py-2 flex-shrink-0">
|
|
851
|
+
<button type="button" class="btn btn-primary btn-sm flex-1" data-sidebar-action="new">\uFF0B \u65B0\u4F1A\u8BDD</button>
|
|
852
|
+
<button type="button" class="btn btn-ghost btn-sm px-2" data-sidebar-action="theme" aria-label="\u5207\u6362\u6DF1\u8272\u6216\u6D45\u8272\u4E3B\u9898">\u{1F319}</button>
|
|
853
|
+
<button type="button" class="btn btn-ghost btn-sm px-2" data-sidebar-action="settings" aria-label="\u8BBE\u7F6E">\u2699\uFE0F</button>
|
|
854
|
+
<button type="button" class="btn btn-ghost btn-sm px-2 text-error" data-sidebar-action="logout" aria-label="\u9000\u51FA\u767B\u5F55">\u21E5</button>
|
|
855
|
+
</div>
|
|
856
|
+
</aside>
|
|
857
|
+
<div class="flex flex-col flex-shrink-0 relative" style="width:12px">
|
|
858
|
+
<div id="sidebar-resize" class="absolute inset-0 bg-transparent hover:bg-primary/30 transition-colors cursor-col-resize"></div>
|
|
859
|
+
<button id="sidebar-toggle" title="\u6536\u8D77\u4FA7\u680F" aria-label="\u6536\u8D77\u4FA7\u680F" aria-controls="sidebar" aria-expanded="true"
|
|
860
|
+
class="absolute z-10 flex items-center justify-center w-5 h-8 bg-base-200 border border-base-300 rounded-r-md text-[10px] text-base-content/40 hover:text-base-content cursor-pointer"
|
|
861
|
+
style="left:0;top:50%;transform:translateY(-50%)">\u25C0</button>
|
|
862
|
+
</div>
|
|
863
|
+
<div id="main" class="flex-1 flex flex-col overflow-hidden min-w-0">
|
|
864
|
+
<div id="welcome" class="${t?"hidden flex-1 flex-col items-center justify-start overflow-y-auto p-4 md:p-6 gap-5":"flex-1 flex flex-col items-center justify-start overflow-y-auto p-4 md:p-6 gap-5"}">
|
|
865
|
+
<div class="max-w-4xl w-full text-center flex flex-col items-center gap-2 mt-2 md:mt-4">
|
|
866
|
+
<h2 class="text-3xl font-extrabold tracking-tight bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent select-none">\u{1F916} Agent UI</h2>
|
|
867
|
+
<p class="text-sm text-base-content/65 max-w-md">Claude \xB7 Codex \xB7 Grok \xB7 Gemini \u2014 Select a session from the sidebar or click a day on the calendar to view activity.</p>
|
|
868
|
+
<div class="flex gap-2 mt-0.5">
|
|
869
|
+
<button id="btn-new-session-welcome" class="btn btn-primary btn-sm shadow-md">\uFF0B New Session</button>
|
|
870
|
+
<button id="btn-meta-agent-welcome" class="btn btn-outline btn-primary btn-sm">\u2726 Meta Agent</button>
|
|
871
|
+
</div>
|
|
872
|
+
</div>
|
|
873
|
+
|
|
874
|
+
<!-- Stats Banner -->
|
|
875
|
+
<div class="max-w-4xl w-full grid grid-cols-2 md:grid-cols-4 gap-4 text-center select-none mt-1">
|
|
876
|
+
<div class="bg-base-200 border border-base-300 rounded-2xl p-3 shadow-md flex flex-col justify-center items-center">
|
|
877
|
+
<span class="text-[10px] uppercase tracking-wider text-base-content/40 font-bold">Total Sessions</span>
|
|
878
|
+
<span id="stats-total-sessions" class="text-xl md:text-2xl font-extrabold text-primary mt-0.5">0</span>
|
|
879
|
+
</div>
|
|
880
|
+
<div class="bg-base-200 border border-base-300 rounded-2xl p-3 shadow-md flex flex-col justify-center items-center">
|
|
881
|
+
<span class="text-[10px] uppercase tracking-wider text-base-content/40 font-bold">Active Projects</span>
|
|
882
|
+
<span id="stats-total-projects" class="text-xl md:text-2xl font-extrabold text-accent mt-0.5">0</span>
|
|
883
|
+
</div>
|
|
884
|
+
<div class="bg-base-200 border border-base-300 rounded-2xl p-3 shadow-md flex flex-col justify-center items-center">
|
|
885
|
+
<span class="text-[10px] uppercase tracking-wider text-base-content/40 font-bold">Total Tokens</span>
|
|
886
|
+
<span id="stats-total-tokens" class="text-xl md:text-2xl font-extrabold text-secondary mt-0.5">0</span>
|
|
887
|
+
</div>
|
|
888
|
+
<div class="bg-base-200 border border-base-300 rounded-2xl p-3 shadow-md flex flex-col justify-center items-center">
|
|
889
|
+
<span class="text-[10px] uppercase tracking-wider text-base-content/40 font-bold">Selected Day Tokens</span>
|
|
890
|
+
<span id="stats-selected-tokens" class="text-xl md:text-2xl font-extrabold text-success mt-0.5">0</span>
|
|
891
|
+
</div>
|
|
892
|
+
</div>
|
|
893
|
+
<div class="max-w-4xl w-full grid grid-cols-1 md:grid-cols-12 gap-5 items-start text-left">
|
|
894
|
+
<!-- Calendar Card -->
|
|
895
|
+
<div class="card bg-base-200 border border-base-300 md:col-span-7 shadow-xl">
|
|
896
|
+
<div class="card-body p-4">
|
|
897
|
+
<div class="flex items-center justify-between mb-3">
|
|
898
|
+
<button id="btn-cal-prev" class="btn btn-ghost btn-sm text-base font-bold">\u25C0</button>
|
|
899
|
+
<h3 id="calendar-month-year" class="text-base font-extrabold text-base-content select-none"></h3>
|
|
900
|
+
<button id="btn-cal-next" class="btn btn-ghost btn-sm text-base font-bold">\u25B6</button>
|
|
901
|
+
</div>
|
|
902
|
+
|
|
903
|
+
<div class="grid grid-cols-7 gap-2 text-center text-[10px] font-bold text-base-content/40 mb-1">
|
|
904
|
+
<div>Sun</div><div>Mon</div><div>Tue</div><div>Wed</div><div>Thu</div><div>Fri</div><div>Sat</div>
|
|
905
|
+
</div>
|
|
906
|
+
|
|
907
|
+
<div id="calendar-grid" class="grid grid-cols-7 gap-2">
|
|
908
|
+
<!-- JS Rendered -->
|
|
909
|
+
</div>
|
|
910
|
+
</div>
|
|
911
|
+
</div>
|
|
912
|
+
|
|
913
|
+
<!-- Details Card -->
|
|
914
|
+
<div class="card bg-base-200 border border-base-300 md:col-span-5 shadow-xl min-h-[290px] flex flex-col">
|
|
915
|
+
<div class="card-body p-4 flex flex-col flex-1">
|
|
916
|
+
<h3 id="selected-day-title" class="card-title text-xs font-bold uppercase tracking-wider text-base-content/50 mb-3 select-none">Daily Activity</h3>
|
|
917
|
+
<div id="selected-day-sessions" class="flex-1 overflow-y-auto flex flex-col gap-2 max-h-[250px]">
|
|
918
|
+
<div class="text-center text-xs text-base-content/40 my-auto py-6">Select a date on the calendar to view its sessions.</div>
|
|
919
|
+
</div>
|
|
920
|
+
</div>
|
|
921
|
+
</div>
|
|
922
|
+
</div>
|
|
923
|
+
|
|
924
|
+
<!-- Recent Sessions Section -->
|
|
925
|
+
<div class="max-w-4xl w-full border-t border-base-300/60 pt-4 mt-1 text-left">
|
|
926
|
+
<h3 class="text-xs font-bold uppercase tracking-wider text-base-content/50 mb-3 select-none">Recent Workspaces & Sessions</h3>
|
|
927
|
+
<div id="recent-sessions-list" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
928
|
+
<!-- JS Rendered -->
|
|
929
|
+
</div>
|
|
930
|
+
</div>
|
|
931
|
+
</div>
|
|
932
|
+
<div id="project-view" class="${t?"flex flex-col flex-1 overflow-hidden min-h-0":"hidden flex-col flex-1 overflow-hidden min-h-0"}" style="${t?"display:flex;flex-direction:column;flex:1;min-height:0":""}">
|
|
933
|
+
<div class="flex bg-base-200 border-b border-base-300 flex-shrink-0 overflow-x-auto" style="scrollbar-width:none">
|
|
934
|
+
<button class="px-4 py-2.5 text-sm border-b-2 flex-shrink-0 text-primary border-primary" data-tab="chat">Chat</button>
|
|
935
|
+
<button class="px-4 py-2.5 text-sm border-b-2 flex-shrink-0 text-base-content/50 border-transparent" data-tab="files">Files</button>
|
|
936
|
+
<button class="px-4 py-2.5 text-sm border-b-2 flex-shrink-0 text-base-content/50 border-transparent" data-tab="git">Git</button>
|
|
937
|
+
<button class="px-4 py-2.5 text-sm border-b-2 flex-shrink-0 text-base-content/50 border-transparent" data-tab="shell">Shell</button>
|
|
938
|
+
<button class="px-4 py-2.5 text-sm border-b-2 flex-shrink-0 text-base-content/50 border-transparent" data-tab="memory">\u{1F9E0} Memory</button>
|
|
939
|
+
</div>
|
|
940
|
+
<div id="tab-chat" class="flex flex-col flex-1 overflow-hidden relative">
|
|
941
|
+
<div id="project-notes-bar" class="bg-base-200 border-b border-base-300 px-3 py-1.5 text-xs flex flex-col gap-1" style="display:none"></div>
|
|
942
|
+
<div id="session-notes-bar" class="bg-base-200/80 border-b border-base-300 px-3 py-1 text-xs flex justify-between items-center gap-2" style="display:none"></div>
|
|
943
|
+
<div id="session-lock-banner" class="session-lock-banner hidden px-3 py-1.5 text-[11px] text-center border-b"></div>
|
|
944
|
+
<div id="ws-banner" class="hidden px-3 py-1.5 text-[11px] text-center bg-warning/15 text-warning border-b border-warning/20 flex items-center justify-center gap-2">
|
|
945
|
+
<span id="ws-banner-text"></span>
|
|
946
|
+
<button type="button" id="ws-banner-retry" class="btn btn-ghost btn-xs h-6 min-h-0 px-2 text-warning border border-warning/30">\u91CD\u8FDE</button>
|
|
947
|
+
</div>
|
|
948
|
+
<div id="messages" class="flex-1 overflow-y-auto p-3 flex flex-col gap-2"></div>
|
|
949
|
+
<div id="scroll-nav" class="absolute right-3 bottom-24 flex flex-col gap-1.5 z-10">
|
|
950
|
+
<button id="scroll-top-btn" class="scroll-fab hidden" title="Jump to top">\u2191</button>
|
|
951
|
+
<button id="scroll-bottom-btn" class="scroll-fab hidden" title="Jump to bottom">\u2193</button>
|
|
952
|
+
</div>
|
|
953
|
+
<div id="permission-requests"></div>
|
|
954
|
+
<form id="chat-form" autocomplete="off" action="#" class="flex flex-col flex-shrink-0">
|
|
955
|
+
<div id="chat-composer" class="flex flex-col border-t border-base-300 bg-base-200 flex-shrink-0">
|
|
956
|
+
<div id="chat-attach-bar" class="hidden flex flex-wrap gap-1.5 px-3 pt-2"></div>
|
|
957
|
+
<div id="chat-opts" class="hidden flex items-center gap-1.5 px-3 pt-2 flex-wrap" inert>
|
|
958
|
+
<select id="sel-agent" class="select select-xs select-bordered text-xs font-semibold" title="Agent">
|
|
959
|
+
<option value="claude">Claude</option>
|
|
960
|
+
<option value="codex">Codex</option>
|
|
961
|
+
<option value="grok">Grok</option>
|
|
962
|
+
<option value="gemini">Gemini</option>
|
|
963
|
+
<option value="cursor">Cursor</option>
|
|
964
|
+
</select>
|
|
965
|
+
<select id="sel-convert-agent" class="select select-xs select-bordered text-xs font-semibold" title="Convert session to another agent">
|
|
966
|
+
<option value="" disabled selected>Convert to...</option>
|
|
967
|
+
<option value="claude">Convert to Claude</option>
|
|
968
|
+
<option value="codex">Convert to Codex</option>
|
|
969
|
+
<option value="grok">Convert to Grok</option>
|
|
970
|
+
</select>
|
|
971
|
+
<div class="flex items-center gap-0.5">
|
|
972
|
+
<select id="sel-model" class="select select-xs select-bordered font-mono text-xs max-w-[11rem]" title="Model">
|
|
973
|
+
<option value="claude-sonnet-4-5">sonnet-4-5</option>
|
|
974
|
+
<option value="claude-sonnet-4-6">sonnet-4-6</option>
|
|
975
|
+
<option value="claude-opus-4-5">opus-4-5</option>
|
|
976
|
+
<option value="claude-haiku-4-5">haiku-4-5</option>
|
|
977
|
+
</select>
|
|
978
|
+
<button type="button" id="btn-model-add" class="btn btn-ghost btn-xs px-1.5 font-mono" title="Add / set custom model id">+</button>
|
|
979
|
+
<button type="button" id="btn-model-edit" class="btn btn-ghost btn-xs px-1.5" title="Edit current model id">\u270E</button>
|
|
980
|
+
</div>
|
|
981
|
+
<select id="sel-effort" class="select select-xs select-bordered text-xs" title="Effort">
|
|
982
|
+
<option value="">effort: off</option>
|
|
983
|
+
<option value="low">low</option>
|
|
984
|
+
<option value="medium">medium</option>
|
|
985
|
+
<option value="high">high</option>
|
|
986
|
+
<option value="xhigh">xhigh</option>
|
|
987
|
+
<option value="max">max</option>
|
|
988
|
+
</select>
|
|
989
|
+
<select id="sel-permission" class="select select-xs select-bordered text-xs" title="Permissions">
|
|
990
|
+
<option value="default">perms: default</option>
|
|
991
|
+
<option value="acceptEdits">acceptEdits</option>
|
|
992
|
+
<option value="auto">auto</option>
|
|
993
|
+
<option value="plan">plan</option>
|
|
994
|
+
<option value="bypassPermissions" selected>\u26A0 bypass all</option>
|
|
995
|
+
</select>
|
|
996
|
+
<select id="sel-density" class="select select-xs select-bordered text-xs" title="Chat density \u2014 how tools are shown">
|
|
997
|
+
<option value="clean">density: clean</option>
|
|
998
|
+
<option value="normal">density: normal</option>
|
|
999
|
+
<option value="full">density: full</option>
|
|
1000
|
+
</select>
|
|
1001
|
+
</div>
|
|
1002
|
+
<div id="composer-row" class="px-3 pt-2 pb-2">
|
|
1003
|
+
<div class="composer-surface">
|
|
1004
|
+
<textarea id="chat-input" rows="1" placeholder="\u95EE\u70B9\u4EC0\u4E48\u2026"
|
|
1005
|
+
class="chat-input w-full text-sm resize-none leading-relaxed"
|
|
1006
|
+
name="q"
|
|
1007
|
+
enterkeyhint="send"
|
|
1008
|
+
inputmode="text"
|
|
1009
|
+
autocomplete="off"
|
|
1010
|
+
autocorrect="off"
|
|
1011
|
+
autocapitalize="sentences"
|
|
1012
|
+
spellcheck="false"
|
|
1013
|
+
data-1p-ignore="true"
|
|
1014
|
+
data-lpignore="true"
|
|
1015
|
+
data-form-type="other"
|
|
1016
|
+
data-bwignore="true"></textarea>
|
|
1017
|
+
<div class="composer-actions">
|
|
1018
|
+
<div class="composer-tools">
|
|
1019
|
+
<button type="button" id="btn-opts" class="composer-icon-btn" title="Options" aria-label="Options">\u2699</button>
|
|
1020
|
+
<button type="button" id="btn-attach" class="composer-icon-btn" title="\u6DFB\u52A0\u56FE\u7247 / \u6587\u4EF6" aria-label="\u6DFB\u52A0\u56FE\u7247 / \u6587\u4EF6">\u{1F4CE}</button>
|
|
1021
|
+
<input type="file" id="chat-file-input" class="hidden" multiple accept="image/*,*/*" tabindex="-1">
|
|
1022
|
+
</div>
|
|
1023
|
+
<div class="composer-submit">
|
|
1024
|
+
<span class="composer-hint">Enter \u53D1\u9001</span>
|
|
1025
|
+
<button type="submit" id="send-btn" class="composer-send-btn">Send</button>
|
|
1026
|
+
<button type="button" id="stop-btn" class="composer-stop-btn hidden" aria-label="\u505C\u6B62\u751F\u6210">\u25A0</button>
|
|
1027
|
+
</div>
|
|
1028
|
+
</div>
|
|
1029
|
+
</div>
|
|
1030
|
+
</div>
|
|
1031
|
+
</div>
|
|
1032
|
+
</form>
|
|
1033
|
+
</div>
|
|
1034
|
+
<div id="tab-files" class="hidden flex-col flex-1 overflow-hidden">
|
|
1035
|
+
<div class="flex items-center gap-2 px-3 py-1.5 border-b border-base-300 flex-shrink-0 bg-base-200">
|
|
1036
|
+
<span class="text-xs text-base-content/40 flex-shrink-0">Root</span>
|
|
1037
|
+
<span id="files-machine-hint" class="hidden text-[10px] font-mono font-semibold text-primary flex-shrink-0"></span>
|
|
1038
|
+
<input id="files-root-input" type="text" placeholder="Absolute path on the target machine"
|
|
1039
|
+
class="input input-xs flex-1 font-mono text-xs bg-transparent border-0 focus:outline-none px-1" autocomplete="off">
|
|
1040
|
+
<button id="files-root-btn" class="btn btn-ghost btn-xs text-xs">Go</button>
|
|
1041
|
+
</div>
|
|
1042
|
+
<div id="files-breadcrumb" class="flex items-center flex-wrap gap-1 px-4 py-2 border-b border-base-300 text-xs text-base-content/60 flex-shrink-0"></div>
|
|
1043
|
+
<div id="files-area" class="flex-1 overflow-y-auto"></div>
|
|
1044
|
+
</div>
|
|
1045
|
+
<div id="tab-shell" class="hidden flex-col flex-1 overflow-hidden bg-[#0d1117]">
|
|
1046
|
+
<div class="flex items-center gap-2 px-3 py-1.5 border-b border-base-300 bg-base-200 flex-shrink-0">
|
|
1047
|
+
<span class="text-xs text-base-content/40 font-mono flex-1" id="term-cwd"></span>
|
|
1048
|
+
<button id="term-keyboard" class="btn btn-ghost btn-xs text-xs text-base-content/60" type="button">Keyboard</button>
|
|
1049
|
+
<button id="term-reconnect" class="btn btn-ghost btn-xs text-xs text-base-content/40">Reconnect</button>
|
|
1050
|
+
</div>
|
|
1051
|
+
<div id="term-mobile-keys" class="hidden items-center gap-1 px-2 py-1 border-b border-slate-700 bg-[#161b22] flex-shrink-0" aria-label="Terminal shortcuts">
|
|
1052
|
+
<button class="term-key" type="button" data-term-key="ctrl-c">Ctrl+C</button>
|
|
1053
|
+
<button class="term-key" type="button" data-term-key="escape">Esc</button>
|
|
1054
|
+
<button class="term-key" type="button" data-term-key="tab">Tab</button>
|
|
1055
|
+
<button class="term-key" type="button" data-term-key="up">\u2191</button>
|
|
1056
|
+
<button class="term-key" type="button" data-term-key="down">\u2193</button>
|
|
1057
|
+
<button class="term-key" type="button" data-term-key="left">\u2190</button>
|
|
1058
|
+
<button class="term-key" type="button" data-term-key="right">\u2192</button>
|
|
1059
|
+
</div>
|
|
1060
|
+
<div id="terminal-container" class="flex-1 p-2 overflow-hidden"></div>
|
|
1061
|
+
<form id="term-mobile-composer" class="hidden items-center gap-2 px-2 py-2 border-t border-slate-700 bg-[#161b22] flex-shrink-0">
|
|
1062
|
+
<input id="term-mobile-input" class="term-mobile-input" type="text" placeholder="\u8F93\u5165\u547D\u4EE4\u2026" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" inputmode="text" enterkeyhint="send" aria-label="Terminal command">
|
|
1063
|
+
<button class="term-mobile-send" type="submit">\u53D1\u9001</button>
|
|
1064
|
+
</form>
|
|
1065
|
+
</div>
|
|
1066
|
+
<div id="tab-git" class="hidden flex-col flex-1 overflow-hidden">
|
|
1067
|
+
<div class="flex items-center gap-2 px-3 py-1.5 border-b border-base-300 flex-shrink-0 bg-base-200">
|
|
1068
|
+
<span class="text-xs text-base-content/40 flex-shrink-0">Root</span>
|
|
1069
|
+
<span id="git-machine-hint" class="hidden text-[10px] font-mono font-semibold text-primary flex-shrink-0"></span>
|
|
1070
|
+
<input id="git-root-input" type="text" placeholder="Absolute path on the target machine"
|
|
1071
|
+
class="input input-xs flex-1 font-mono text-xs bg-transparent border-0 focus:outline-none px-1" autocomplete="off">
|
|
1072
|
+
<button id="git-root-btn" class="btn btn-ghost btn-xs text-xs">Go</button>
|
|
1073
|
+
</div>
|
|
1074
|
+
<div id="git-area" class="flex-1 overflow-y-auto"></div>
|
|
1075
|
+
</div>
|
|
1076
|
+
<div id="tab-memory" class="hidden flex-col flex-1 overflow-hidden">
|
|
1077
|
+
<div class="flex items-center gap-2 px-3 py-1.5 border-b border-base-300 flex-shrink-0 bg-base-200">
|
|
1078
|
+
<span class="text-xs text-base-content/40 flex-shrink-0">\u{1F9E0} Agent memory</span>
|
|
1079
|
+
<span class="flex-1"></span>
|
|
1080
|
+
<button id="memory-refresh" class="btn btn-ghost btn-xs text-xs">Refresh</button>
|
|
1081
|
+
</div>
|
|
1082
|
+
<div id="memory-area" class="flex-1 overflow-y-auto text-sm"></div>
|
|
1083
|
+
</div>
|
|
1084
|
+
</div>
|
|
1085
|
+
</div>
|
|
1086
|
+
</div>
|
|
1087
|
+
</div>
|
|
1088
|
+
<dialog id="modal-new-session" class="modal">
|
|
1089
|
+
<div class="modal-box max-w-sm">
|
|
1090
|
+
<h3 class="font-bold text-base mb-4">\uFF0B New Session</h3>
|
|
1091
|
+
<div class="flex flex-col gap-3">
|
|
1092
|
+
<label class="form-control">
|
|
1093
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Agent</span></div>
|
|
1094
|
+
<select id="new-session-agent" class="select select-bordered select-sm">
|
|
1095
|
+
<option value="claude">Claude Code</option>
|
|
1096
|
+
<option value="codex">OpenAI Codex</option>
|
|
1097
|
+
<option value="grok">Grok</option>
|
|
1098
|
+
<option value="gemini">Google Gemini (agy)</option>
|
|
1099
|
+
<option value="cursor">Cursor Agent</option>
|
|
1100
|
+
</select>
|
|
1101
|
+
</label>
|
|
1102
|
+
<label class="form-control" id="new-session-machine-wrap" style="display:none">
|
|
1103
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Machine (edge server)</span></div>
|
|
1104
|
+
<select id="new-session-machine" class="select select-bordered select-sm"></select>
|
|
1105
|
+
</label>
|
|
1106
|
+
<label class="form-control">
|
|
1107
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Working Directory</span></div>
|
|
1108
|
+
<input id="new-session-path" type="text" class="input input-bordered input-sm font-mono"
|
|
1109
|
+
placeholder="~/projects/my-app" autocomplete="off">
|
|
1110
|
+
</label>
|
|
1111
|
+
<label class="form-control" id="new-session-ws-wrap">
|
|
1112
|
+
<div class="label py-1"><span class="label-text text-xs uppercase tracking-wide">Claude Workspace</span></div>
|
|
1113
|
+
<select id="new-session-workspace" class="select select-bordered select-sm"></select>
|
|
1114
|
+
</label>
|
|
1115
|
+
<div id="new-session-error" class="alert alert-error text-xs py-2 hidden"></div>
|
|
1116
|
+
</div>
|
|
1117
|
+
<div class="modal-action">
|
|
1118
|
+
<button id="new-session-cancel" class="btn btn-ghost btn-sm">Cancel</button>
|
|
1119
|
+
<button id="new-session-start" class="btn btn-primary btn-sm">Start</button>
|
|
1120
|
+
</div>
|
|
1121
|
+
</div>
|
|
1122
|
+
<form method="dialog" class="modal-backdrop"><button>close</button></form>
|
|
1123
|
+
</dialog>`};Or();It();ns();W();F();le();hs();Cs();pa();It();Bs();Ps();ns();Us();Dn();async function fo(e={}){i("auth-screen").style.display="none";let t=i("app");t.classList.remove("hidden"),t.style.display="flex",queueMicrotask(Ee),Ki().catch(()=>{});let n=e.hub;n===void 0?n=await da():n?(M.value=!0,n.machines&&(ie.value=n.machines)):M.value=!1;let s=e.deepLink||null,a=Xt();if(!!(s?.id||(location.hash||"").startsWith("#/session/"))){let d=i("welcome");d&&(d.classList.add("hidden"),d.style.display="none");let u=i("project-view");u&&(u.classList.remove("hidden"),u.style.display="flex",u.style.flexDirection="column",u.style.flex="1",u.style.minHeight="0")}if(M.peek()){let d=localStorage.getItem("machineId")||a?.machineId||"";d&&(Le(d),io(),it.value=!0,Ns());let u=yn().then(m=>(Bt(),d&&!m.some(w=>w.id===d&&w.online!==!1)&&m.length&&(m.some(y=>y.id===d)||(Le(null),wn())),m));Qr(),Bt();let l=Promise.all([We({waitFresh:!1}),Zn({waitFresh:!1}),Rs().catch(()=>{}),es().catch(()=>{})]);if(s?.id){let m=ne.peek().find(g=>g.sessionId===s.id)||(a?.sessionId===s.id?a:null);await nt(s.id,m?.cwd||null,m?.configDir||null,s.agent||m?.agent||null,s.machineId||m?.machineId||d||null,{tab:s.tab||"chat"}),u.catch(()=>{}),l.catch(()=>{});return}if(!d){if(await u,!(ie.peek()||[]).length){wn(),l.catch(()=>{});return}wn(),l.catch(()=>{});return}await l;let f=i("topbar-project");f&&f.textContent==="Select a session"&&(f.textContent=`Machine \xB7 ${d}`);return}Ns();let r=Promise.all([We({waitFresh:!1}),Zn({waitFresh:!1}),Rs().catch(()=>{}),es().catch(()=>{})]);if(s?.id){await Pa().then(u=>{Array.isArray(u)?ne.value=u:u&&Array.isArray(u.sessions)&&(ne.value=u.sessions)}).catch(()=>{});let d=ne.peek().find(u=>u.sessionId===s.id)||(a?.sessionId===s.id?a:null);await nt(s.id,d?.cwd||null,d?.configDir||null,s.agent||d?.agent||null,null,{tab:s.tab||"chat"}),r.catch(()=>{});return}await r}Bs();Us();W();F();le();_a();It();ns();Us();Dn();function Cc(){let e=i("sidebar");e&&(e.classList.add("open"),i("sidebar-overlay").classList.remove("hidden"),i("hamburger")?.setAttribute("aria-expanded","true"),Ee(),setTimeout(()=>i("session-search")?.focus({preventScroll:!0}),180))}function Ws(){let e=i("sidebar");e&&(e.classList.remove("open"),i("sidebar-overlay").classList.add("hidden"),i("hamburger")?.setAttribute("aria-expanded","false"),Ee(),i("hamburger")?.focus({preventScroll:!0}))}function Mc(){window.innerWidth<=640&&Ws()}function Ac(){let e=i("sidebar-toggle"),t=i("sidebar");if(!e||!t)return;let n=localStorage.getItem("sidebarCollapsed")==="1",s=localStorage.getItem("sidebarWidth")||t.style.width||"280px",a=()=>{t.classList.toggle("desktop-collapsed",n),n?(t.style.width="0",t.style.minWidth="0",t.style.overflow="hidden"):(t.style.width=s,t.style.minWidth="",t.style.overflow=""),e.textContent=n?"\u25B6":"\u25C0",e.title=n?"\u5C55\u5F00\u4FA7\u680F":"\u6536\u8D77\u4FA7\u680F",e.setAttribute("aria-label",e.title),e.setAttribute("aria-expanded",n?"false":"true")};a(),e.addEventListener("click",()=>{n=!n,n&&(s=t.style.width||s),localStorage.setItem("sidebarCollapsed",n?"1":"0"),a()})}function jc(){let e=i("sidebar-resize"),t=i("sidebar"),n=!1;e.addEventListener("mousedown",s=>{n=!0,document.body.style.userSelect="none",document.body.style.cursor="col-resize",s.preventDefault()}),document.addEventListener("mousemove",s=>{if(!n)return;let a=Math.min(Math.max(s.clientX,160),520);t.style.width=a+"px",t.style.minWidth=""}),document.addEventListener("mouseup",()=>{if(!n)return;n=!1,document.body.style.userSelect="",document.body.style.cursor="";let s=Math.round(t.getBoundingClientRect().width);s>=160&&localStorage.setItem("sidebarWidth",`${s}px`)})}function Zr(e){document.documentElement.setAttribute("data-theme",e),localStorage.setItem("theme",e);let t=i("btn-theme"),n=e==="dark"||e==="night"||e==="black"?"\u{1F319}":"\u2600\uFE0F";t&&(t.textContent=n),document.querySelectorAll('[data-sidebar-action="theme"]').forEach(a=>{a.textContent=n});let s=document.getElementById("hljs-theme");if(s||(s=document.querySelector('link[href*="highlight"][href*="styles"]'),s&&(s.id="hljs-theme")),s){let a=e==="dark"||e==="night"||e==="black";s.href="/vendor/highlight-dark.min.css"}}function ei(){let e=document.documentElement.getAttribute("data-theme")||"dark";Zr(e==="dark"?"light":"dark")}function ti(){let e=i("new-session-agent");e&&(e.value=S.peek()||"claude");let t=i("new-session-workspace");if(t){let a=pe.peek();t.innerHTML=a.map(o=>`<option value="${p(o.configDir)}">${p(o.name)} \u2014 ${p(o.configDir)}</option>`).join(""),c.configDir&&(t.value=c.configDir)}let n=i("new-session-machine-wrap"),s=i("new-session-machine");if(n&&s)if(M.peek()){n.style.display="";let a=ie.peek()||[],o=j.peek()||"";s.innerHTML=a.length?a.map(r=>`<option value="${p(r.id)}">${p(r.id)}${r.hostname?" \u2014 "+p(r.hostname):""}</option>`).join(""):'<option value="">(no machines online)</option>',o&&(s.value=o),s.disabled=!0}else n.style.display="none",s&&(s.disabled=!1);ni(),i("new-session-path").value=E.peek()?.path||"",i("new-session-error").classList.add("hidden"),i("modal-new-session").showModal(),setTimeout(()=>i("new-session-path").focus(),50)}function ni(){let e=i("new-session-agent")?.value||"claude",t=i("new-session-ws-wrap");t&&(t.style.display=e==="claude"?"":"none")}async function si(){let e=i("new-session-path").value.trim(),t=i("new-session-agent")?.value||"claude",n=t==="claude"?i("new-session-workspace").value:null,s=i("new-session-error");if(s.classList.add("hidden"),!e){s.textContent="Working directory is required",s.classList.remove("hidden");return}if(M.peek()){let a=j.peek()||i("new-session-machine")?.value||ie.peek()?.[0]?.id;if(!a){s.textContent="\u8BF7\u5148\u9009\u62E9\u4E00\u53F0\u673A\u5668",s.classList.remove("hidden"),wn();return}Le(a)}try{let a=await x("POST","/api/resolve-path",{path:e});if(!a.isDir)throw new Error("Path is not a directory");i("modal-new-session").close();let o=a.path.split("/").filter(Boolean).pop()||a.path;Un(),Wn(),Kn(),Gn(),c.sessionId=null,c.configDir=n||null,c.agent=t,Ne(t),se(Oe(t)||_.peek()),et(),xe(()=>{E.value={id:o,name:o,path:a.path,machineId:j.peek()||c.machineId},ke.value=a.path,re.value=a.path,Se.value=a.path,V.value="",oe.value=null}),i("topbar-project").textContent=a.path;let r=i("files-root-input");r&&(r.value=a.path);let d=i("git-root-input");d&&(d.value=a.path),i("welcome").classList.add("hidden");let u=i("project-view");u.classList.remove("hidden"),u.style.display="flex",zn(),Fn({sessionId:null}),Pt(),Tt("chat"),C(`New ${X[t]||t} session \xB7 ${a.path}`)}catch(a){s.textContent=a.message,s.classList.remove("hidden")}}function vp(){let e=/iPad|iPhone|iPod/.test(navigator.userAgent)||navigator.platform==="MacIntel"&&navigator.maxTouchPoints>1,t=/Android/i.test(navigator.userAgent),n;e?n=`<ol class="list-decimal pl-4 space-y-2 text-sm text-base-content/80">
|
|
1124
|
+
<li>\u70B9\u5E95\u90E8\u5206\u4EAB\u6309\u94AE <strong>\u5206\u4EAB</strong>\uFF08\u65B9\u6846+\u5411\u4E0A\u7BAD\u5934\uFF09</li>
|
|
1125
|
+
<li>\u4E0B\u6ED1\u627E\u5230\u5E76\u70B9 <strong>\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55</strong></li>
|
|
1126
|
+
<li>\u786E\u8BA4\u540D\u79F0\u540E\u70B9 <strong>\u6DFB\u52A0</strong></li>
|
|
1127
|
+
</ol>
|
|
1128
|
+
<p class="text-xs text-base-content/50 mt-3">\u9700\u7528 <strong>Safari</strong> \u6253\u5F00\u672C\u7AD9\uFF1B\u5FAE\u4FE1/Chrome \u5185\u7F6E\u6D4F\u89C8\u5668\u901A\u5E38\u6CA1\u6709\u300C\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55\u300D\u3002</p>
|
|
1129
|
+
<p class="text-xs text-warning/80 mt-2">\u5F53\u524D\u82E5\u662F IP + \u81EA\u7B7E HTTPS\uFF0CSafari \u4ECD\u4F1A\u663E\u793A\u300C\u4E0D\u5B89\u5168\u300D\u3002\u52A0\u5230\u4E3B\u5C4F\u5E55\u53EF\u53BB\u6389\u6D4F\u89C8\u5668\u5916\u58F3\uFF0C\u4F46\u4E0D\u80FD\u53BB\u6389\u7CFB\u7EDF\u8F93\u5165\u6761\u3002\u5F7B\u5E95\u5E72\u51C0\u9700\u8981\u6B63\u5F0F\u57DF\u540D\u8BC1\u4E66\u3002</p>`:t?n=`<ol class="list-decimal pl-4 space-y-2 text-sm text-base-content/80">
|
|
1130
|
+
<li>\u70B9\u53F3\u4E0A\u89D2\u83DC\u5355 <strong>\u22EE</strong></li>
|
|
1131
|
+
<li>\u9009\u62E9 <strong>\u5B89\u88C5\u5E94\u7528</strong> \u6216 <strong>\u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55</strong></li>
|
|
1132
|
+
</ol>
|
|
1133
|
+
<p class="text-xs text-base-content/50 mt-3">\u82E5\u83DC\u5355\u91CC\u6CA1\u6709\u8BE5\u9879\uFF1A\u8BF7\u7528 <strong>Chrome</strong> \u6253\u5F00\uFF0C\u5E76\u5148\u63A5\u53D7\u672C\u7AD9\u8BC1\u4E66\u63D0\u793A\u3002\u81EA\u7B7E HTTPS \u4E0B\u90E8\u5206\u673A\u578B\u4E0D\u5F39\u51FA\u4E00\u952E\u5B89\u88C5\u3002</p>
|
|
1134
|
+
<a class="btn btn-primary btn-sm mt-4" href="/download/agentui-android.apk" download>\u4E0B\u8F7D Android APK</a>`:n=`<p class="text-sm text-base-content/80">\u8BF7\u5728\u6D4F\u89C8\u5668\u83DC\u5355\u4E2D\u9009\u62E9 <strong>\u5B89\u88C5\u5E94\u7528 / \u5B89\u88C5\u7F51\u9875\u5E94\u7528 / \u6DFB\u52A0\u5230\u4E3B\u5C4F\u5E55</strong>\u3002</p>
|
|
1135
|
+
<p class="text-xs text-base-content/50 mt-3">Chrome / Edge \u5730\u5740\u680F\u53F3\u4FA7\u6709\u65F6\u4E5F\u4F1A\u51FA\u73B0\u5B89\u88C5\u56FE\u6807\u3002</p>`;let s=document.getElementById("modal-pwa-install");s||(s=document.createElement("dialog"),s.id="modal-pwa-install",s.className="modal",document.body.appendChild(s)),s.innerHTML=`
|
|
1136
|
+
<div class="modal-box max-w-sm">
|
|
1137
|
+
<h3 class="font-bold text-base mb-3">\u5B89\u88C5\u5230\u4E3B\u5C4F\u5E55</h3>
|
|
1138
|
+
${n}
|
|
1139
|
+
<div class="modal-action">
|
|
1140
|
+
<form method="dialog"><button class="btn btn-sm">\u77E5\u9053\u4E86</button></form>
|
|
1141
|
+
</div>
|
|
1142
|
+
</div>
|
|
1143
|
+
<form method="dialog" class="modal-backdrop"><button>close</button></form>`,s.showModal()}async function oi(){let e=i("auth-screen");e&&(e.classList.remove("hidden"),e.style.display="flex");let t=i("app");t&&(t.classList.add("hidden"),t.style.display="none");let n=i("auth-btn"),s,a=new AbortController,o=setTimeout(()=>a.abort(),8e3);try{s=await x("GET","/api/auth/status",void 0,a.signal)}catch(r){console.warn("[auth status]",r);let d=i("auth-error");d&&(d.textContent="\u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u5668\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u670D\u52A1\u5730\u5740\u540E\u91CD\u8BD5\u3002",d.classList.remove("hidden")),n&&(n.dataset.mode="login");return}finally{clearTimeout(o)}s.needsSetup?(i("auth-subtitle").textContent="Create your account to get started",n.textContent="Create Account",n.dataset.mode="register"):n.dataset.mode="login"}async function ai(){let e=i("auth-username").value.trim(),t=i("auth-password").value,n=i("auth-error");n.classList.add("hidden");try{let s=await x("POST",`/api/auth/${i("auth-btn").dataset.mode||"login"}`,{username:e,password:t});c.token=s.token,localStorage.setItem("token",s.token),fo()}catch(s){n.textContent=s.message,n.classList.remove("hidden")}}function ri(){return c.token?/^#\/session\//.test(location.hash||""):!1}function Dc(e={}){if(Zr(localStorage.getItem("theme")||"dark"),!document.getElementById("xterm-css")){let l=document.createElement("link");l.id="xterm-css",l.rel="stylesheet",l.href="/xterm.min.css",document.head.appendChild(l)}if(!document.getElementById("xterm-js")){let l=document.createElement("script");l.id="xterm-js",l.src="/xterm.min.js",document.head.appendChild(l)}if(!document.getElementById("xterm-fit-js")){let l=document.createElement("script");l.id="xterm-fit-js",l.src="/addon-fit.min.js",document.head.appendChild(l)}let t=e.restoreSession??ri(),n=document.getElementById("root");if(n.style.cssText="display:flex;flex-direction:column;flex:1;height:100%",n.innerHTML=Yl()+Xl({restoreSession:t}),t){let l=i("session-list");l&&(l.innerHTML='<div class="px-3 py-3 text-[10px] text-base-content/35">Loading sessions\u2026</div>')}je(()=>{let l=pe.value,f=i("ws-tabs");if(!f)return;if(l.length<=1){f.innerHTML="";return}let m=ke.peek();f.innerHTML=[{id:null,name:"All"},...l].map(g=>`<button class="px-3 py-1.5 text-[11px] flex-shrink-0 border-b-2 whitespace-nowrap
|
|
1144
|
+
${(g.id===null?!m:m===g.configDir)?"border-primary text-primary":"border-transparent text-base-content/50 hover:text-base-content"}"
|
|
1145
|
+
data-ws-tab="${p(g.configDir||"")}">
|
|
1146
|
+
${p(g.name)}
|
|
1147
|
+
</button>`).join("")}),je(()=>{Dt.value,Vt.value,ht.value,rt.value,T.value;let l=i("session-list");if(!l||l.querySelector(".session-rename-input"))return;let f=Gr();if(l._lastHtml===f){qs();return}let m=l.scrollTop;l.innerHTML=f,l._lastHtml=f,l.scrollTop=m,qs()}),je(()=>{gt.value,qs()}),je(()=>{ne.value,ye.value,j.value,M.value;let l=i("welcome");l&&(document.documentElement.classList.contains("boot-restore")||document.documentElement.classList.contains("boot-pending")||l.classList.contains("hidden")||l.style.display==="none"||vn())}),De(ke,l=>{let f=i("session-filter-badge");f&&(f.style.display=l?"inline":"none",f.title=l||"")}),je(()=>{let l=E.value;if(l&&l.path)xc(l.path);else{let f=i("project-notes-bar");f&&(f.style.display="none")}}),De(Y,l=>{document.querySelectorAll("[data-tab]").forEach(m=>{let g=m.dataset.tab===l;m.classList.toggle("text-primary",g),m.classList.toggle("border-primary",g),m.classList.toggle("text-base-content/50",!g),m.classList.toggle("border-transparent",!g)});let f=i("project-view");f&&!f.classList.contains("hidden")&&(f.style.display="flex",f.style.flexDirection="column",f.style.minHeight="0",f.style.flex="1"),["chat","files","git","shell","memory"].forEach(m=>{let g=i(`tab-${m}`);if(!g)return;let w=m===l;g.classList.toggle("hidden",!w),w?(g.style.display="flex",g.style.flexDirection="column",g.style.flex="1 1 0",g.style.minHeight="0",g.style.overflow="hidden"):g.style.display="none"}),l==="memory"&&eo(),l==="shell"&&requestAnimationFrame(()=>{document.dispatchEvent(new CustomEvent("shell-tab-shown"))}),Ee()}),jc(),Ac(),Zi({openSession:nt});let s=l=>{i("app")?.classList.toggle("chat-chrome-collapsed",l),i("btn-expand-chat-chrome")?.classList.toggle("hidden",!l),localStorage.setItem("chatChromeCollapsed",l?"1":"0")};s(localStorage.getItem("chatChromeCollapsed")==="1");let a=null;document.addEventListener("sessions-changed",()=>{a&&clearTimeout(a),a=setTimeout(()=>{a=null,We({waitFresh:!1})},1200)}),document.addEventListener("router:home",po),document.addEventListener("router:session",async({detail:{id:l,tab:f,machineId:m,agent:g}})=>{let w=ne.peek().find(H=>H.sessionId===l),y=Xt();await nt(l,w?.cwd||(y?.sessionId===l?y.cwd:null)||null,w?.configDir||(y?.sessionId===l?y.configDir:null)||null,g||w?.agent||(y?.sessionId===l?y.agent:null)||null,m||w?.machineId||(y?.sessionId===l?y.machineId:null)||null,{tab:f||"chat"})}),b.on("click","#btn-home",po),b.on("click","#btn-share-session, #btn-share-session-current",async(l,f)=>{let m=kl();if(m)try{await navigator.clipboard.writeText(m),f.classList.add("is-copied"),f.title="\u5DF2\u590D\u5236\u5206\u4EAB\u94FE\u63A5",setTimeout(()=>{f.classList.remove("is-copied"),f.title="\u590D\u5236\u5F53\u524D\u4F1A\u8BDD\u5206\u4EAB\u94FE\u63A5"},1400)}catch{window.prompt("\u590D\u5236\u4F1A\u8BDD\u94FE\u63A5\uFF1A",m)}}),b.on("click","#auth-btn",ai),b.on("submit","#auth-form",l=>{l.preventDefault(),ai()}),b.on("keydown","#auth-username, #auth-password",l=>{l.key==="Enter"&&ai()}),b.on("click","#hamburger",()=>i("sidebar").classList.contains("open")?Ws():Cc()),b.on("click","#sidebar-overlay",Ws),document.addEventListener("keydown",l=>{l.key==="Escape"&&window.innerWidth<=640&&i("sidebar")?.classList.contains("open")&&(l.preventDefault(),Ws())}),b.on("input","#session-search",(l,f)=>{$e.value=f.value,Za(f.value)}),b.on("click","#sidebar-filter-toggle",()=>{let l=i("sidebar-filter-menu");if(!l)return;let f=l.classList.toggle("hidden");i("sidebar-filter-toggle")?.setAttribute("aria-expanded",String(!f))}),b.on("change","[data-agent-option]",(l,f)=>{let m=new Set(zt.peek());f.checked?m.add(f.dataset.agentOption):m.delete(f.dataset.agentOption);let g=[...m];zt.value=g,localStorage.setItem("agentFilters",JSON.stringify(g)),ye.value=g.length===1?g[0]:"all"}),b.on("change","#filter-favorites",(l,f)=>{ze.value=f.checked,localStorage.setItem("favoritesOnly",f.checked?"1":"0")}),b.on("change","#filter-hidden",(l,f)=>{Je.value=f.checked,localStorage.setItem("showHiddenOnly",f.checked?"1":"0")}),b.on("click","#filter-clear",()=>{zt.value=[],ye.value="all",ze.value=!1,Je.value=!1,localStorage.setItem("agentFilters","[]"),localStorage.setItem("favoritesOnly","0"),localStorage.setItem("showHiddenOnly","0"),document.querySelectorAll("[data-agent-option]").forEach(l=>{l.checked=!1}),i("filter-favorites")&&(i("filter-favorites").checked=!1),i("filter-hidden")&&(i("filter-hidden").checked=!1)}),b.on("click","#session-filter-badge",()=>{ke.value=null}),b.on("click","[data-ws-tab]",(l,f)=>{ke.value=f.dataset.wsTab||null}),b.on("click","#sidebar-refresh",()=>{We(),$e.peek().trim()&&Xa($e.peek())}),b.on("click","[data-view]",(l,f)=>{ht.value=f.dataset.view,localStorage.setItem("sidebarView",f.dataset.view)}),b.on("click","[data-agent-filter]",(l,f)=>{ye.value=f.dataset.agentFilter,localStorage.setItem("agentFilter",f.dataset.agentFilter),$e.peek().trim()&&Za($e.peek())}),b.on("dblclick","[data-project-cwd]",(l,f)=>{let m=f.dataset.projectCwd;if(!m)return;let g=m.split("/").filter(Boolean).pop()||m;Xr({id:g,name:g,path:m}),C(`Project \xB7 ${m}`)}),b.on("click","#btn-pwa-install",async()=>{await Hi()||vp()}),document.addEventListener("pwa-installable",()=>{document.getElementById("btn-pwa-install")?.classList.remove("hidden")}),b.on("click","#btn-settings",qa),b.on("click","#btn-notes",()=>Ra()),b.on("click","#btn-collapse-chat-chrome",()=>s(!0)),b.on("click","#btn-expand-chat-chrome",()=>s(!1)),b.on("click","#btn-meta-agent",()=>Gl()),b.on("click","#btn-meta-agent-welcome",()=>Dr("chat")),b.on("click","#btn-theme",ei),b.on("click","[data-sidebar-action]",(l,f)=>{let m=f.dataset.sidebarAction;m==="new"&&ti(),m==="theme"&&ei(),m==="settings"&&qa(),m==="logout"&&(c.token=null,localStorage.removeItem("token"),Le(null),it.value=!1,location.reload())}),b.on("click","#btn-cal-prev",()=>{Br(-1),vn(bn())}),b.on("click","#btn-cal-next",()=>{Br(1),vn(bn())}),b.on("click","[data-cal-date]",(l,f)=>{cc(f.dataset.calDate),vn(bn())}),b.on("click","[data-session-id]",(l,f)=>{l.target.closest("[data-fav-toggle]")||l.target.closest("[data-hide-toggle]")||l.target.closest("[data-rename-session]")||l.target.closest(".session-rename-input")||l.target.closest(".session-title-wrap.session-rename-active")||(nt(f.dataset.sessionId,f.dataset.sessionCwd||null,f.dataset.sessionConfigDir||null,f.dataset.sessionAgent||"claude",f.dataset.sessionMachine||null),Mc())}),b.on("click","[data-rename-session]",(l,f)=>{l.preventDefault(),l.stopPropagation();let m=f.closest(".session-title-wrap")||f,g=m.dataset.renameSessionId||m.dataset.sessionId;g&&Jr({sessionId:g,agent:m.dataset.renameSessionAgent||"claude",machineId:m.dataset.renameSessionMachine||null,fallbackDisplay:m.dataset.renameSessionDisplay||"",mountEl:m})}),b.on("click","[data-rename-bar]",(l,f)=>{if(l.preventDefault(),l.stopPropagation(),!c.sessionId)return;let m=document.getElementById("session-title-display")||f;Jr({sessionId:c.sessionId,agent:c.agent||S.peek()||"claude",machineId:c.machineId||null,mountEl:m})}),b.on("click","[data-folder]",(l,f)=>{let m=f.dataset.folder,w=f.querySelector("span")?.textContent.trim()==="\u25BE",y=new Set(Cn.peek()),H=new Set(Mn.peek());w?(y.delete(m),H.add(m)):(y.add(m),H.delete(m)),xe(()=>{Cn.value=y,Mn.value=H})}),b.on("click","#memory-refresh",eo),b.on("click","[data-memory-file]",l=>Kr(l.dataset.memoryFile,l.dataset.memoryAgent)),b.on("click","[data-tab]",(l,f)=>Tt(f.dataset.tab));let o=async(l,f)=>{let m=i(l),g=m?.value.trim();if(!g){f.value="";return}try{let w=await x("POST","/api/resolve-path",{path:g});if(w.isDir===!1)throw new Error("Path is not a directory on the target machine");f.value=w.path,m.value=w.path;let y=E.peek();y&&(E.value={...y,path:w.path})}catch(w){m.style.color="oklch(var(--er))",m.title=w.message,setTimeout(()=>{m.style.color="",m.title=""},2e3)}};b.on("click","#files-root-btn",()=>o("files-root-input",re)),b.on("click","#git-root-btn",()=>o("git-root-input",Se)),b.on("keydown","#files-root-input",l=>{l.key==="Enter"&&o("files-root-input",re)}),b.on("keydown","#git-root-input",l=>{l.key==="Enter"&&o("git-root-input",Se)}),b.on("click","#btn-opts",()=>{i("chat-opts").classList.toggle("hidden"),Ee()}),b.on("change","#sel-agent",(l,f)=>{let m=S.peek(),g=f.value;m!==g&&(c.sessionId=null,Ne(g),se(Oe(g)||_.peek()),i("sel-permission").value=de.peek(),et(),C(`Agent \u2192 ${X[g]||g} \xB7 model ${_.peek()} \xB7 new session`))}),b.on("change","#sel-convert-agent",async(l,f)=>{let m=f.value;if(!m)return;let g=c.sessionId;if(!g){alert("No active session to convert."),f.value="";return}let w=c.agent||S.peek()||"claude";if(w===m){alert("Cannot convert to the same agent."),f.value="";return}f.disabled=!0,C(`Converting session ${g.slice(0,8)} from ${w} to ${m}...`);try{let y=await x("POST",`/api/sessions/${g}/convert`,{targetAgent:m,sourceAgent:w});y&&y.success?(C(`\u2713 Converted successfully. New session: ${y.targetSessionId.slice(0,8)}`),await We(),await nt(y.targetSessionId,E.peek()?.path||null,null,y.targetAgent),Es()):C("Failed to convert session.")}catch(y){C(`Error converting session: ${y.message}`),alert(`Error converting session: ${y.message}`)}finally{f.disabled=!1,f.value=""}}),b.on("change","#sel-model",(l,f)=>{se(f.value),Va()}),b.on("click","#btn-model-add",()=>Ya({editCurrent:!1})),b.on("click","#btn-model-edit",()=>Ya({editCurrent:!0})),b.on("change","#sel-effort",(l,f)=>{te.value=f.value}),b.on("change","#sel-permission",(l,f)=>{de.value=f.value}),b.on("change","#sel-density",(l,f)=>{Go(f.value),C(`Density \u2192 ${f.value} (applies to new tool calls; reload session to re-group history)`)}),document.addEventListener("agent-changed",et),b.on("click","#btn-new-session, #btn-new-session-current, #btn-new-session-welcome",ti),b.on("click","#new-session-cancel",()=>i("modal-new-session").close()),b.on("click","#new-session-start",si),b.on("change","#new-session-agent",ni),b.on("keydown","#new-session-path",l=>{l.key==="Enter"&&si()}),b.on("click","#send-btn",Ls),b.on("click","#stop-btn",ul),b.on("click","#btn-logout",()=>{c.token=null,localStorage.removeItem("token"),Le(null),it.value=!1,location.reload()}),b.on("click","[data-pick-machine]",async(l,f)=>{let m=f.dataset.pickMachine;if(!m||m===j.peek()){kn();return}await Vr(m,{forceReload:!0}),va()});let r=async()=>{let l=i("machine-picker-status");if(l&&(l.textContent="\u5237\u65B0\u4E2D\u2026"),await yn(),ro(),Os(),Bt(),l){let f=(ie.peek()||[]).filter(m=>m.online!==!1).length;l.textContent=`${f} online`}};b.on("click","#btn-refresh-machines",r),b.on("click","#btn-refresh-machines-menu",async l=>{l.stopPropagation(),await r()}),b.on("click","#btn-machine-menu",async l=>{l.stopPropagation(),xn(),an();let f=i("machine-menu");f&&(f.classList.contains("hidden")?(await yn(),Os(),f.classList.remove("hidden")):f.classList.add("hidden"))}),b.on("click","#btn-recent-sessions",l=>{l.preventDefault(),l.stopPropagation(),kn(),an(),lc();let f=!i("recent-menu")?.classList.contains("hidden"),m=i("btn-recent-sessions");m&&m.setAttribute("aria-expanded",f?"true":"false")}),b.on("click","#recent-menu-backdrop",l=>{l.preventDefault(),l.stopPropagation(),xn(),i("btn-recent-sessions")?.setAttribute("aria-expanded","false")}),document.addEventListener("click",l=>{let f=i("machine-menu-wrap");f&&!f.contains(l.target)&&kn();let m=i("recent-menu"),g=i("btn-recent-sessions"),w=l.target;if(m&&!m.classList.contains("hidden")){if(m.contains(w)||g?.contains(w))return;xn(),g?.setAttribute("aria-expanded","false")}}),b.on("click","#btn-notifications",l=>{l.preventDefault(),l.stopPropagation(),kn(),xn(),Xi()}),window.addEventListener("resize",()=>{i("recent-menu")&&!i("recent-menu").classList.contains("hidden")&&qr()}),b.on("click","#recent-menu [data-session-id]",()=>{xn(),i("btn-recent-sessions")?.setAttribute("aria-expanded","false")}),b.on("click","[data-dismiss-recent-session]",(l,f)=>{l.preventDefault(),l.stopPropagation(),rc({sessionId:f.dataset.dismissRecentSession,agent:f.dataset.dismissRecentAgent||"claude",machineId:f.dataset.dismissRecentMachine||null})}),b.on("click","#btn-edit-project-notes, #project-goal-text, #project-notes-text",()=>{yc()}),b.on("click","#btn-cancel-project-notes",()=>{ts()});let d=async()=>{let l=i("project-goal-input")?.value?.trim()??"",f=i("project-notes-input")?.value?.trim()??"",m=E.peek();if(!(!m||!m.path))try{let g=await x("POST","/api/projects/notes",{root:m.path,goal:l,notes:f});vc(g.goal||"",g.notes||""),ts()}catch(g){alert(`Error saving project notes: ${g.message}`)}};b.on("click","#btn-save-project-notes",d),b.on("keydown","#project-goal-input",l=>{l.key==="Enter"&&d(),l.key==="Escape"&&ts()}),b.on("keydown","#project-notes-input",l=>{l.key==="Escape"&&ts()}),b.on("click","[data-fav-toggle]",(l,f)=>{l.stopPropagation(),l.preventDefault();let m=f.dataset.favSessionMachine||c.machineId;m&&(c.machineId=m,localStorage.setItem("machineId",m)),$c(f.dataset.favSessionId,f.dataset.favSessionAgent||"claude",{machineId:m||null})}),b.on("click","[data-hide-toggle]",(l,f)=>{l.stopPropagation(),l.preventDefault();let m=f.dataset.hideSessionMachine||c.machineId;m&&(c.machineId=m,localStorage.setItem("machineId",m)),Sc(f.dataset.hideSessionId,f.dataset.hideSessionAgent||"claude",{machineId:m||null})}),b.on("click","#btn-edit-session-notes, #session-notes-text",()=>{wc()}),b.on("click","#btn-cancel-session-notes",()=>tt()),b.on("click","#btn-save-session-notes",async()=>{let l=i("session-notes-input")?.value?.trim()||"";if(!c.sessionId)return;let f=c.agent||S.peek()||"claude";await zr(c.sessionId,f,l)&&tt()}),b.on("keydown","#session-notes-input",async l=>{if(l.key==="Escape"&&tt(),l.key==="Enter"){let f=l.target.value.trim();if(!c.sessionId)return;let m=c.agent||S.peek()||"claude";await zr(c.sessionId,m,f)&&tt()}}),b.on("click","#btn-fav-filter",()=>{let l=!ze.peek();ze.value=l,localStorage.setItem("favoritesOnly",l?"1":"0"),i("btn-fav-filter")?.classList.toggle("active",l),l&&Je.peek()&&(Je.value=!1,localStorage.setItem("showHiddenOnly","0"),i("btn-hidden-filter")?.classList.remove("active"))}),b.on("click","#btn-hidden-filter",()=>{let l=!Je.peek();Je.value=l,localStorage.setItem("showHiddenOnly",l?"1":"0"),i("btn-hidden-filter")?.classList.toggle("active",l),l&&ze.peek()&&(ze.value=!1,localStorage.setItem("favoritesOnly","0"),i("btn-fav-filter")?.classList.remove("active"))}),et(),je(()=>{M.value,j.value,c.token&&va()}),i("sel-permission").value=de.peek(),gl();let u=i("sel-density");u&&(u.value=_e.peek()||"normal"),document.querySelectorAll("[data-agent-option]").forEach(l=>{l.checked=zt.peek().includes(l.dataset.agentOption)}),i("filter-favorites")&&(i("filter-favorites").checked=ze.peek()),i("filter-hidden")&&(i("filter-hidden").checked=Je.peek()),document.querySelectorAll("[data-agent-filter]").forEach(l=>{l.classList.toggle("active",l.dataset.agentFilter===ye.peek())}),i("btn-fav-filter")?.classList.toggle("active",ze.peek()),i("btn-hidden-filter")?.classList.toggle("active",Je.peek()),document.querySelectorAll("[data-view]").forEach(l=>{let f=l.dataset.view===ht.peek();l.classList.toggle("bg-primary/15",f),l.classList.toggle("text-primary",f),l.classList.toggle("font-medium",f),l.classList.toggle("text-base-content/50",!f)})}W();er();F();le();hs();or();ya();_n();Zt();en();ir();_t();_t();function xp(){return X[S.peek()]||"Assistant"}function yp(e){let t=String(e||"").trim();return/remote compact task|error decoding response body/i.test(t)?"Codex \u4F1A\u8BDD\u538B\u7F29\u5931\u8D25\uFF08\u7F51\u7EDC\u4E2D\u65AD\uFF09\u3002\u518D\u53D1\u4E00\u6761\u6D88\u606F\u91CD\u8BD5\uFF0C\u6216\u5F00\u65B0\u4F1A\u8BDD\u3002":t||"\u53D1\u9001\u5931\u8D25"}var $n=null;function wp(e){return vs(e)}function Oc(e){return e?($n&&$n.el===e||($n?.destroy?.(),$n=wa(e),$n.el=e),$n):null}function Re(e,t){if(!e||e.dataset.historyPainting==="1")return;Oc(e).stick(!!t)}var Ks=0,At=null,at=1e3,Mt=0,go=null,_c=!1,bo=!1,Nc=null,vo=!1,li="hubStreamCursors",Eo=new Map,kp=0,ci=new Set,di="pendingUserTexts",Sn=(()=>{try{let e=JSON.parse(sessionStorage.getItem(di)||"[]");return Array.isArray(e)?e.filter(t=>t?.key&&t?.text).slice(-30):[]}catch{return[]}})(),Pc=new Set,Uc=new Map;function Fc(){try{Sn.length?sessionStorage.setItem(di,JSON.stringify(Sn.slice(-30))):sessionStorage.removeItem(di)}catch{}}function $p(){let e=Ys(),t=Sn.filter(n=>n.key===e).length;t&&!Pc.has(e)&&(Pc.add(e),P(`\u231B Restored ${t} queued prompt${t===1?"":"s"} in this browser tab`))}function Wc(e=c.sessionId,t=c.agent,n=c.machineId){return e?`${n||""}:${t||"claude"}:${e}`:""}function Sp(e={}){let t=Wc(e.sessionId,e.agent,e.machineId);if(!t)return 0;try{return Number(JSON.parse(localStorage.getItem(li)||"{}")[t])||0}catch{return 0}}function Lp(e){let t=Number(e?.hubSeq)||0;if(!t)return!0;let n=Wc(e.sessionId||c.sessionId,e.agent||c.agent,c.machineId);if(!n)return!0;let s={};try{s=JSON.parse(localStorage.getItem(li)||"{}")||{}}catch{}let a=Number(s[n])||0;if(t<=a)return!1;s[n]=t;let o=Object.keys(s);o.length>500&&o.sort((r,d)=>Number(s[d])-Number(s[r])).slice(500).forEach(r=>delete s[r]);try{localStorage.setItem(li,JSON.stringify(s))}catch{}return!0}function Ys({sessionId:e=c.sessionId,agent:t=c.agent,machineId:n=c.machineId}={}){return e?`${n||""}:${t||"claude"}:${e}`:null}function Ep(){_c||(_c=!0,document.addEventListener("visibilitychange",()=>{if(document.visibilityState==="visible"&&(at=400,ss({probe:!0}),c.ws?.readyState===WebSocket.OPEN&&c.sessionId))try{c.ws.send(JSON.stringify({type:"subscribe",sessionId:c.sessionId,agent:c.agent}))}catch{}}),window.addEventListener("online",()=>{at=400,ss({force:!0})}),window.addEventListener("pageshow",e=>{e.persisted?ss({force:!0}):ss({probe:!0})}),window.addEventListener("focus",()=>ss({probe:!0})),navigator.connection?.addEventListener?.("change",()=>{at=400,ss({probe:!0})}))}function Js(){let e=i("conn-dot");if(!e)return;let t=fe.peek();e.classList.remove("bg-success","bg-warning","bg-error","bg-base-content/30","animate-pulse"),t==="open"?(e.classList.add("bg-success"),e.title="\u5DF2\u8FDE\u63A5"):t==="connecting"||t==="reconnecting"?(e.classList.add("bg-warning","animate-pulse"),e.title=t==="connecting"?"\u8FDE\u63A5\u4E2D\u2026":"\u91CD\u8FDE\u4E2D\u2026"):t==="offline"?(e.classList.add("bg-error"),e.title="\u79BB\u7EBF"):(e.classList.add("bg-base-content/30"),e.title="\u672A\u8FDE\u63A5")}function ss(e={}){let t=c.ws?.readyState;if(e.force){at=400,ko({quiet:!0});return}if(t===WebSocket.OPEN){if(e.probe&&Mt&&Date.now()-Mt>45e3)try{c.ws.close()}catch{}else if(e.probe&&c.ws.readyState===WebSocket.OPEN)try{c.ws.send(JSON.stringify({type:"ping"}))}catch{}return}t!==WebSocket.CONNECTING&&(at=Math.min(at,800),ko({quiet:!0}))}function Ip(){At||(fe.value=typeof navigator<"u"&&navigator.onLine===!1?"offline":"reconnecting",Js(),At=setTimeout(()=>{At=null,ko({quiet:!0})},at),at=Math.min(Math.round(at*1.8),15e3))}function Gc(){go&&(clearInterval(go),go=null)}function Tp(e,t){Gc(),go=setInterval(()=>{if(!(t!==Ks||e.readyState!==WebSocket.OPEN)){if(Mt&&Date.now()-Mt>7e4){try{e.close()}catch{}return}if(!(typeof document<"u"&&document.visibilityState==="hidden")&&Mt&&Date.now()-Mt>4e4)try{e.send(JSON.stringify({type:"ping"}))}catch{}}},3e4)}function jt(){let e=D.peek()||!!E.peek()&&fe.peek()==="open";ba(e)}function wo(){return(c.role||"editor")==="viewer"?"\u53EA\u8BFB\u8D26\u53F7\uFF0C\u65E0\u6CD5\u8F93\u5165":c.lock?.foreign?`\u4F1A\u8BDD\u7531 ${c.lock.holder&&c.lock.holder!=="viewer"?c.lock.holder:"\u5176\u4ED6\u7528\u6237"} \u5360\u7528\uFF08\u9501\uFF09`:"\u5F53\u524D\u65E0\u6CD5\u8F93\u5165"}function as(){let e=tn();c.externalSessionReadOnly=!e;let t=i("chat-input"),n=i("send-btn"),s=i("btn-attach"),a=i("session-lock-banner");t&&(t.disabled=!e,t.readOnly=!e,e?D.peek()?t.placeholder="\u56DE\u590D\u4E2D\u2026 \u53EF\u5148\u5199\u597D\u4E0B\u4E00\u6761\uFF0C\u7ED3\u675F\u540E\u81EA\u52A8\u53D1\u9001 \xB7 \u6216\u70B9 \u25A0 \u505C\u6B62":Qs(t.value||""):t.placeholder=wo()),n&&(n.disabled=!e),s&&(s.disabled=!e),a&&(e?(a.classList.add("hidden"),a.textContent=""):(a.classList.remove("hidden"),a.textContent=wo()))}function Cp(){at=400,At&&(clearTimeout(At),At=null),vo=!1;let e=c.ws?.readyState;if(e===WebSocket.OPEN||e===WebSocket.CONNECTING)try{c.ws?.close()}catch{}ko({quiet:!1}),P("\u6B63\u5728\u91CD\u65B0\u8FDE\u63A5\u5E76\u540C\u6B65\u2026")}function ko(e={}){Ep(),At&&(clearTimeout(At),At=null),e.quiet&&(vo=!0);let t=c.machineId||(typeof localStorage<"u"?localStorage.getItem("machineId"):null);Nc!==t&&(ca(),Nc=t);let n=++Ks;try{c.ws?.close()}catch{}fe.value="connecting",Js();let s=location.protocol==="https:"?"wss":"ws",a=new URLSearchParams;c.token&&a.set("token",c.token),t&&a.set("machine",t),c.sessionId&&a.set("sessionId",c.sessionId),c.agent&&a.set("agent",c.agent);let o=Sp();o&&a.set("lastSeq",String(o));let r=new WebSocket(`${s}://${location.host}/ws/chat?${a}`);c.ws=r,r.addEventListener("open",()=>{if(n===Ks){if(at=1e3,Mt=Date.now(),fe.value="open",Js(),c.sessionId)try{r.send(JSON.stringify({type:"subscribe",sessionId:c.sessionId,agent:c.agent}))}catch{}la(),$p(),Tp(r,n),jt(),bo&&!vo&&P(t?`\u5DF2\u91CD\u8FDE \xB7 ${t}`:"\u5DF2\u91CD\u8FDE"),bo=!1,vo=!1}}),r.addEventListener("message",d=>{if(n!==Ks)return;let u;try{u=JSON.parse(d.data)}catch{return}if(Lp(u)){if(u.type==="pong"){Mt=Date.now();return}if(u.type==="ping"){if(Mt=Date.now(),r.readyState===WebSocket.OPEN)try{r.send(JSON.stringify({type:"pong"}))}catch{}return}if(u.type==="run-status"){u.running?D.value=!0:(D.peek()&&(D.value=!1),ui()),jt();return}Kc(u)}}),r.addEventListener("close",()=>{n===Ks&&(Gc(),bo=!0,fe.value=typeof navigator<"u"&&navigator.onLine===!1?"offline":"reconnecting",Js(),Ip())}),r.addEventListener("error",()=>{})}function ui(){if(!Sn.length||D.peek())return;let e=Ys(),t=Sn.findIndex(a=>a.key===e);if(t<0)return;let[n]=Sn.splice(t,1);Fc();let s=i("chat-input");s&&(s.value=n.text,Vs(s)),setTimeout(()=>{if(n.key!==Ys()||D.peek()){Uc.set(n.key,n.text);return}Xs()},0)}function mo(){D.value=!1,jt(),ui()}function Kc(e){if(!(e?.sessionId&&c.sessionId&&e.sessionId!==c.sessionId)){if(e&&typeof e.type=="string"&&(e.type==="note.added"||e.type==="note.updated"||e.type==="note.removed"||e.type==="queue.item.added"||e.type==="queue.item.updated"||e.type==="queue.item.removed"||e.type==="queue.item.moved"||e.type==="queue.item.sending")){window.dispatchEvent(new CustomEvent("hub-ws-message",{detail:e}));let t={"note.added":"hub:note-added","note.updated":"hub:note-updated","note.removed":"hub:note-removed"}[e.type];t&&window.dispatchEvent(new CustomEvent(t,{detail:e}))}if(e._hubReplay===!0){document.dispatchEvent(new CustomEvent("external-session-updated",{detail:e}));return}if(e.type==="batch"&&Array.isArray(e.items)){for(let t of e.items)Kc(t);return}if(e.type==="session-created"){let t=_.peek();c.sessionId=e.sessionId,e.agent&&e.agent!==S.peek()&&Ne(e.agent),se(t,e.agent||S.peek(),e.sessionId),document.dispatchEvent(new CustomEvent("sessions-changed"));return}if(e.type==="external-sessions-changed"){document.dispatchEvent(new CustomEvent("sessions-changed"));return}if(e.type==="external-session-updated"){document.dispatchEvent(new CustomEvent("sessions-changed")),document.dispatchEvent(new CustomEvent("external-session-updated",{detail:e}));return}if(e.type==="notification"&&e.notification){xa(e.notification);return}if(e.type==="grok-queue-status"){Qp(e);return}if(e.type==="result"){zs(),Gs(),os();let t=e.usage;if(t){let n={input_tokens:t.inputTokens??t.input_tokens,output_tokens:t.outputTokens??t.output_tokens,cache_read_input_tokens:t.cacheReadInputTokens??t.cache_read_input_tokens,cache_creation_input_tokens:t.cacheCreationInputTokens??t.cache_creation_input_tokens,total_tokens:t.totalTokens??t.total_tokens,reasoning_tokens:t.reasoningTokens??t.reasoning_tokens,costUSD:t.costUSD??t.cost_usd};c.lastUsage=n,c.sessionId&&(c.lastUsageSessionId=c.sessionId),xo(n)}e.is_error||P("\u2713 Done"),mo();return}if(e.type==="complete"){zs(),Gs(),os(),!e.aborted&&e.agent==="claude"?P("\u2713 Done"):!e.aborted&&e.agent&&e.agent!=="claude"&&!e.error||(!e.aborted&&!e.agent?P("\u2713 Done"):e.aborted&&P("\u5DF2\u505C\u6B62")),mo();return}if(e.type==="error"){zs(),Gs(),(e.code===423||/locked/i.test(String(e.message||"")))&&(c.lock={...c.lock||{},held:!1,foreign:!0,holder:e.lock?.holder||c.lock?.holder||"another user"},as()),rs("error","Error",yp(e.message)),mo();return}if(e.type==="shell-start"){c.shellBubble=null;return}if(e.type==="shell-output"){c.shellBubble||(c.shellBubble=Xp(e.stream==="stderr"?"shell-err":"shell")),Zp(c.shellBubble,e.data);return}if(e.type==="shell-exit"){c.shellBubble=null,P(e.code===0?"\u2713 Exit 0":`\u2717 Exit ${e.code}${e.error?": "+e.error:""}`),mo();return}if(e.type==="assistant"){Gs();for(let t of e.message?.content||[])t.type==="text"&&t.text?(os(),rs("assistant",xp(),t.text,{ts:e.ts||Date.now()})):t.type==="tool_use"&&nf(t,{ts:e.ts||Date.now()});return}if(e.type==="assistant_stream_start"){D.peek()||(D.value=!0,jt()),zc(e.ts);return}if(e.type==="assistant_delta"){D.peek()||(D.value=!0,jt()),Mp(e.data||"");return}if(e.type==="assistant_stream_end"){Gs();return}if(e.type==="thought_stream_start"){Jc();return}if(e.type==="thought_delta"){Ap(e.data||"");return}if(e.type==="thought_stream_end"){zs();return}if(e.type==="status"){let t=i("stream-status");if(t)t.textContent=e.message||"";else{let n=i("messages");n&&e.message&&(n.insertAdjacentHTML("beforeend",`<div id="stream-status" class="text-center text-[10px] text-base-content/35 py-0.5">${p(e.message)}</div>`),Re(n))}return}if(e.type==="permission_resolved"){let t=e.requestId||e.request_id;t&&i(`perm-${t}`)?.remove();return}(e.type==="permission_request"||e.request_id&&e.tool_name)&&sf(e)}}var st=null,Ge=null,Ot=null,mt=null;function zc(e){let t=i("messages");if(!t||(os(),zs(),st&&t.contains(st)))return;let n=$o(e||Date.now()),s=So(e||Date.now());t.insertAdjacentHTML("beforeend",`
|
|
1148
|
+
<div class="msg-row assistant px-2 live-stream" data-ts="${p(s)}">
|
|
1149
|
+
<div class="max-w-[88%] rounded-2xl rounded-tl-sm px-3 py-2 text-sm bg-base-200 break-words md">
|
|
1150
|
+
<div class="msg-stream-body whitespace-pre-wrap"></div>
|
|
1151
|
+
</div>
|
|
1152
|
+
${n?`<div class="msg-ts" title="${p(s)}">${p(n)}</div>`:""}
|
|
1153
|
+
</div>`),st=t.lastElementChild,Ge=st.querySelector(".msg-stream-body"),i("stream-status")?.remove(),Re(t)}function Mp(e){e&&(Ge||zc(Date.now()),Ge&&(Ge.textContent+=e,Re(i("messages"))))}function Gs(){if(!st||!Ge){st=null,Ge=null;return}let e=Ge.textContent||"";e.trim()?(Ge.classList.remove("whitespace-pre-wrap"),Ge.classList.add("md"),Ge.innerHTML=yo(e),ed(st),Zc(st,e)):st.remove(),st=null,Ge=null,i("stream-status")?.remove()}function Jc(){let e=i("messages");e&&(Ot&&e.contains(Ot)||(e.insertAdjacentHTML("beforeend",`
|
|
1154
|
+
<div class="msg-row assistant px-2 thought-stream">
|
|
1155
|
+
<div class="max-w-[88%] rounded-lg border border-base-300/60 bg-base-200/50 px-2.5 py-1.5 text-[11px] text-base-content/45">
|
|
1156
|
+
<div class="font-medium text-base-content/35 mb-0.5">thinking\u2026</div>
|
|
1157
|
+
<div class="thought-body font-mono whitespace-pre-wrap max-h-24 overflow-y-auto opacity-80"></div>
|
|
1158
|
+
</div>
|
|
1159
|
+
</div>`),Ot=e.lastElementChild,mt=Ot.querySelector(".thought-body"),Re(e)))}function Ap(e){e&&(mt||Jc(),mt&&(mt.textContent+=e,mt.scrollTop=mt.scrollHeight,Re(i("messages"))))}function zs(){if(Ot&&mt){let e=(mt.textContent||"").length;Ot.innerHTML=`
|
|
1160
|
+
<div class="text-[10px] text-base-content/30 px-1 select-none">\u{1F4AD} thought ${e?`(${e} chars)`:""}</div>`}Ot=null,mt=null}var jp={haiku:"claude-haiku-4-5",sonnet:"claude-sonnet-4-6",opus:"claude-opus-4-5",sonnet4:"claude-sonnet-4-6",haiku4:"claude-haiku-4-5"};function Dp(e){let[t,...n]=e.slice(1).trim().split(/\s+/),s=n.join(" ");switch(t.toLowerCase()){case"agent":{if(!s)return P(`Current agent: ${S.peek()} \xB7 agents: claude | codex | grok | gemini | cursor`),!0;let a=s.toLowerCase();return["claude","codex","grok","gemini","cursor"].includes(a)?(a!==S.peek()?(c.sessionId=null,Ne(a),se(Oe(a)),document.dispatchEvent(new CustomEvent("agent-changed")),P(`Agent \u2192 ${X[a]} \xB7 model ${_.peek()} \xB7 new session`)):P(`Agent already ${X[a]}`),!0):(P(`Unknown agent "${s}" \xB7 valid: claude | codex | grok | gemini | cursor`),!0)}case"model":{if(!s){let d=S.peek(),u=Be(d).map(l=>l.value).join(" | ");return P(`Current model: ${_.peek()} (${d})${u?`
|
|
1161
|
+
Available: ${u}`:""}`),!0}let a=jp[s.toLowerCase()]||s,o=S.peek()||"claude",r=Be(o).some(d=>d.value===a);return r||Jt(o,a),se(a),P(`Model set to ${a}${r?"":" (saved as custom \u2605)"}`),document.dispatchEvent(new CustomEvent("agent-changed")),!0}case"effort":{let a=Qt(S.peek(),_.peek());return s?a.includes(s.toLowerCase())?(te.value=s.toLowerCase(),P(`Effort set to ${s.toLowerCase()}`),!0):(P(`Unknown effort level "${s}" \xB7 valid: ${a.join(" | ")}`),!0):(P(`Current effort: ${te.peek()||"(default)"} \xB7 levels: ${a.join(" | ")}`),!0)}case"clear":return zp(),c.sessionId=null,c.lastUsage=null,P("Cleared \xB7 new session"),!0;case"usage":return _p(),!0;case"help":return P(`Available slash commands:
|
|
1162
|
+
/agent [claude|codex|grok|gemini|cursor]
|
|
1163
|
+
/model [haiku|sonnet|opus|<model-id>]
|
|
1164
|
+
/effort [low|medium|high|xhigh|max]
|
|
1165
|
+
/usage
|
|
1166
|
+
/clear
|
|
1167
|
+
/help`),!0;default:return!1}}function Ce(e){if(e==null||Number.isNaN(Number(e)))return"\u2014";let t=Number(e);return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${(t/1e3).toFixed(1)}k`:String(Math.round(t))}async function _p(){let e=S.peek()||"claude",t=_.peek()||"\u2014",n=c.sessionId,s=[`Agent: ${X[e]||e}`,`Model: ${t}`,`Session: ${n?n.slice(0,8)+"\u2026":"(new \u2014 send a message first)"}`];if(c.lastUsage&&(!n||c.lastUsageSessionId===n)){let a=c.lastUsage;s.push(`Last turn: \u2191${Ce(a.input_tokens)} \u2193${Ce(a.output_tokens)}`+(a.cache_read_input_tokens?` \xB7 ${Ce(a.cache_read_input_tokens)} cached`:"")+(a.reasoning_tokens?` \xB7 ${Ce(a.reasoning_tokens)} reason`:"")+(a.total_tokens?` \xB7 \u03A3${Ce(a.total_tokens)}`:"")+(a.costUSD!=null?` \xB7 $${Number(a.costUSD).toFixed(4)}`:""))}if(!n){P(s.join(`
|
|
1168
|
+
`)),mi("\u25C8 /usage \xB7 no session yet");return}P("Loading usage\u2026");try{let a=new URLSearchParams({sessionId:n,agent:e}),r=(await x("GET",`/api/usage?${a}`)).context||{};if(r.model&&(s[1]=`Model: ${r.model}`),r.title&&s.push(`Title: ${r.title}`),r.tokensUsed!=null||r.windowTokens!=null||r.usagePercent!=null){let u=r.tokensUsed!=null?Ce(r.tokensUsed):"\u2014",l=r.windowTokens!=null?Ce(r.windowTokens):"\u2014",f=r.usagePercent!=null?`${r.usagePercent}%`:"\u2014";s.push(`Context window: ${u} / ${l} (${f})`)}if(r.turnCount!=null&&s.push(`Turns: ${r.turnCount}`),r.toolCallCount!=null&&s.push(`Tools: ${r.toolCallCount}`),r.sessionDurationSeconds!=null){let u=Math.floor(r.sessionDurationSeconds/60),l=Math.round(r.sessionDurationSeconds%60);s.push(`Duration: ${u}m ${l}s`)}if(r.sessionTotals){let u=r.sessionTotals;s.push(`Session totals: \u2191${Ce(u.input_tokens)} \u2193${Ce(u.output_tokens)}`+(u.cache_read_input_tokens?` \xB7 ${Ce(u.cache_read_input_tokens)} cached`:"")+(u.total_tokens?` \xB7 \u03A3${Ce(u.total_tokens)}`:"")+(u.costUSD?` \xB7 $${Number(u.costUSD).toFixed(4)}`:""))}if(r.lastTurn&&!c.lastUsage){let u=r.lastTurn;s.push(`Last completed turn: \u2191${Ce(u.input_tokens)} \u2193${Ce(u.output_tokens)}`+(u.cache_read_input_tokens?` \xB7 ${Ce(u.cache_read_input_tokens)} cached`:"")+(u.costUSD!=null?` \xB7 $${Number(u.costUSD).toFixed(4)}`:""))}r.note&&s.push(r.note);let d=i("messages");if(d){let u=[...d.children];for(let l=u.length-1;l>=0;l--)if(u[l].textContent==="Loading usage\u2026"){u[l].remove();break}}P(s.join(`
|
|
1169
|
+
`)),(r.tokensUsed!=null||r.windowTokens!=null)&&Kp({tokensUsed:r.tokensUsed,windowTokens:r.windowTokens,usagePercent:r.usagePercent,model:r.model||t,turnCount:r.turnCount,toolCallCount:r.toolCallCount}),r.sessionTotals?xo(r.sessionTotals):r.lastTurn?xo(r.lastTurn):c.lastUsage&&xo(c.lastUsage)}catch(a){let o=i("messages");if(o){let r=[...o.children];for(let d=r.length-1;d>=0;d--)if(r[d].textContent==="Loading usage\u2026"){r[d].remove();break}}P(`${s.join(`
|
|
1170
|
+
`)}
|
|
1171
|
+
(usage fetch failed: ${a.message})`)}}function Xs(){let e=i("chat-input"),t=e?.value.trim();if(!t||!E.peek())return;if(!tn()){P(wo()),yt().then(()=>as()).catch(()=>{});return}if(c.sessionId&&!c.lock?.held&&!c.lock?.unmanaged){yt().then(s=>{if(!s?.ok&&!s?.skipped){as(),P(wo());return}Xs()}).catch(()=>Xs());return}if(D.peek()){if(S.peek()==="grok"&&c.sessionId){let s="grok",a=te.peek()||Qe(s,_.peek())||"low",o=lt({type:"command",cmd:"turn.start",agent:s,command:t,sessionId:c.sessionId,lockToken:c.lock?.token||void 0,options:{agent:s,cwd:E.peek().path,sessionId:c.sessionId,configDir:c.configDir,model:_.peek(),lockToken:c.lock?.token||void 0,effort:a,...de.peek()&&{permissionMode:de.peek()},...de.peek()==="bypassPermissions"&&{allowDangerouslySkipPermissions:!0}}});Xc(t),e.value="",Vs(e),Qs(""),ii(),P(o?"\u5DF2\u52A0\u5165 Grok \u670D\u52A1\u7AEF\u961F\u5217\uFF0C\u5237\u65B0\u9875\u9762\u4ECD\u4F1A\u663E\u793A":"\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u6D88\u606F\u5C06\u5728\u91CD\u8FDE\u540E\u53D1\u9001");return}Sn.push({key:Ys(),text:t}),Fc(),e.value="",Vs(e),Qs(""),ii(),P(`\u5DF2\u6392\u961F\u4E0B\u4E00\u6761\uFF0C\u5F53\u524D\u56DE\u590D\u7ED3\u675F\u540E\u53D1\u9001\uFF1A${t.length>80?t.slice(0,80)+"\u2026":t}`);return}if(e.value="",Uc.delete(Ys()),Vs(e),Qs(""),ii(),t.startsWith("/")&&Dp(t))return;D.value=!0,jt();let n=Date.now();if(Qc(t))rs("shell","$ Shell",t.slice(1).trim(),{ts:n}),lt({type:"command",cmd:"shell.exec",command:t.slice(1).trim(),cwd:E.peek().path})||P("\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u547D\u4EE4\u5DF2\u5165\u961F\uFF0C\u91CD\u8FDE\u540E\u53D1\u9001");else{os(),rs("user","You",t,{ts:n,forceStick:!0});let s=S.peek()||"claude",a=te.peek()||Qe(s,_.peek())||(s==="grok"?"low":""),o=de.peek();c.sessionId&&se(_.peek(),s,c.sessionId),lt({type:"command",cmd:"turn.start",agent:s,command:t,sessionId:c.sessionId,lockToken:c.lock?.token||void 0,options:{agent:s,cwd:E.peek().path,sessionId:c.sessionId,configDir:c.configDir,model:_.peek(),lockToken:c.lock?.token||void 0,...a&&{effort:a},...o&&{permissionMode:o},...o==="bypassPermissions"&&{allowDangerouslySkipPermissions:!0}}})||P("\u8FDE\u63A5\u672A\u5C31\u7EEA\uFF0C\u6D88\u606F\u5DF2\u5165\u961F\uFF0C\u91CD\u8FDE\u540E\u53D1\u9001")}}function Qs(e){let t=Qc(e),n=i("chat-input"),s=i("send-btn");if(!n||!s)return;n.classList.toggle("textarea-warning",t),n.style.fontFamily=t?"monospace":"",s.classList.toggle("btn-warning",t),s.classList.toggle("btn-primary",!t),s.textContent=t?"Run":"Send";let a=X[S.peek()]||"agent",o=typeof window<"u"&&window.matchMedia("(max-width: 640px)").matches;t?n.placeholder=o?"Shell \u547D\u4EE4\u2026":"Shell command (without !)\u2026":n.placeholder=o?`\u95EE ${a}\u2026`:`Ask ${a}\u2026 or !cmd for shell`}function Qc(e){let t=String(e||"").trimStart();return t.startsWith("!")&&!/^!\[[^\]]*\]\([^)]+\)/.test(t)}function Np(){return typeof window<"u"&&window.matchMedia("(max-width: 640px)").matches,72}function Vs(e){e.style.height="auto",e.style.height=Math.min(e.scrollHeight,Np())+"px"}var Pp=200,Hp=500;function $o(e){let t=O(e);if(t==null)return"";let n=new Date(t);if(Number.isNaN(n.getTime()))return"";let s=new Date,a=n.toDateString()===s.toDateString(),o=n.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1});return a?o:`${n.toLocaleDateString(void 0,{month:"numeric",day:"numeric"})} ${o}`}function So(e){let t=O(e);return t==null?"":new Date(t).toISOString()}function qp(e,t,n){if(e==="system")return t;let s=$o(n),a=So(n),o=s?`<div class="msg-ts" title="${p(a)}">${p(s)}</div>`:"";return`<div class="msg-row ${e==="user"?"user":e==="shell"||e==="shell-err"?"assistant":e} px-2" data-ts="${p(a)}">${t}${o}</div>`}function Rp(e,t,n){let s='<button class="msg-expand-btn text-[10px] text-primary/70 mt-1.5 block cursor-pointer hover:text-primary">\u25BC Show more</button>',a;switch(e){case"user":{let r=/!\[.*?\]\(.*?\)/.test(t)?yo(t):null,d=t.length>Pp,u=d?`<div class="msg-body">${r??p(t.trimEnd())}</div>${s}`:r??p(t.trimEnd());a=`<div class="max-w-[80%] rounded-2xl rounded-tr-sm px-3 py-2 text-sm bg-primary/15 border border-primary/20 text-base-content break-words${d?" msg-card":""}${r?" md":""}"${r?"":' style="white-space:pre-wrap"'}>${u}</div>`;break}case"assistant":{let o=t.length>Hp,r=o?`<div class="msg-body">${yo(t)}</div>${s}`:yo(t);a=`<div class="msg-assistant-content max-w-[min(92%,52rem)] rounded-2xl rounded-tl-sm px-3.5 py-2.5 text-sm bg-base-200 border border-base-300/40 break-words md leading-relaxed${o?" msg-card":""}">${r}</div>`;break}case"error":a=`<div class="max-w-[88%] rounded-2xl rounded-tl-sm px-3 py-2 text-sm bg-error/10 border border-error/20 text-error break-words" style="white-space:pre-wrap">${p(t)}</div>`;break;case"shell":case"shell-err":a=`<div class="w-full max-w-[96%] rounded-lg code-surface px-3 py-2 text-sm font-mono ${e==="shell-err"?"text-error":""} break-words" style="white-space:pre-wrap">${p(t)}</div>`;break;case"system":return`<div class="text-center text-[11px] text-base-content/30 py-0.5 select-none">${p(t)}</div>`;default:a=`<div class="rounded-lg px-3 py-2 text-sm bg-base-300 break-words" style="white-space:pre-wrap">${p(t)}</div>`}return qp(e,a,n)}function rs(e,t,n,s={}){let a=i("messages");if(!a)return;let o=O(s.ts)??(e==="system"?null:Date.now());a.insertAdjacentHTML("beforeend",Rp(e,n,o)),ed(a.lastElementChild),e==="assistant"&&Zc(a.lastElementChild,n,s),Re(a,!!s.forceStick)}function P(e){rs("system","",e)}var Ut=[],ho=0,Hc=!1;async function Bp(e,t){let n=t||`upload-${Date.now()}`,s=await Vc(e,n),a=ct({"x-filename":n});delete a["Content-Type"],s?.type&&!a["Content-Type"]&&!a["content-type"]&&(a["Content-Type"]=s.type);let o=await fetch("/api/upload-image",{method:"POST",headers:a,body:s});if(!o.ok){let d=await o.json().catch(()=>({}));throw new Error(d.error||`Upload failed: ${o.status}`)}let r=await o.json();if(!r?.path)throw new Error("upload returned no path");return r.path}function Op(e,t){return e.length>=8&&e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71?"image/png":e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255?"image/jpeg":e.length>=6&&String.fromCharCode(...e.slice(0,6))==="GIF87a"?"image/gif":e.length>=12&&String.fromCharCode(...e.slice(8,12))==="WEBP"?"image/webp":t||"image/png"}async function Vc(e,t){if(!e||!pi({type:e.type,name:t}))return e;let n;try{n=(await e.slice(0,80).text()).trim()}catch{return e}if(!/^(?:data:image\/[a-z0-9.+-]+;base64,|iVBORw0KGgo|\/9j\/|R0lGOD|UklGR)/i.test(n))return e;let s;try{s=(await e.text()).trim()}catch{return e}let o=/^data:image\/[a-z0-9.+-]+;base64,([a-z0-9+/=\s]+)$/i.exec(s)?.[1]||s;if(!o||!/^[a-z0-9+/=\s]+$/i.test(o)||o.length%4===1)return e;try{let r=atob(o.replace(/\s/g,"")),d=Uint8Array.from(r,f=>f.charCodeAt(0)),u=Op(d,e.type);return u===(e.type||"image/png")&&!/^(image\/png|image\/jpeg|image\/gif|image\/webp)$/.test(u)?e:d.length>=3&&(d[0]===137&&d[1]===80&&d[2]===78||d[0]===255&&d[1]===216&&d[2]===255||String.fromCharCode(...d.slice(0,6))==="GIF87a"||String.fromCharCode(...d.slice(8,12))==="WEBP")?new Blob([d],{type:u}):e}catch{return e}}function Up(e,t){if(!e)return;let n=e.selectionStart??e.value.length,s=e.selectionEnd??e.value.length,o=(n>0&&e.value[n-1]!==`
|
|
1172
|
+
`?`
|
|
1173
|
+
`:"")+t+`
|
|
1174
|
+
`;e.value=e.value.slice(0,n)+o+e.value.slice(s),e.selectionStart=e.selectionEnd=n+o.length,e.dispatchEvent(new Event("input"))}function pi(e){return e?e.type&&e.type.startsWith("image/")?!0:/\.(png|jpe?g|gif|webp|bmp|svg|heic|heif|avif)$/i.test(e.name||""):!1}function Fp(e,t){let n=e?.name||t.split("/").pop()||"file";if(pi(e)){ho+=1;let a=`img${ho}`;return{ref:``,label:a,kind:"image"}}ho+=1;let s=`file${ho}`;return{ref:`[${s}](${t})`,label:s,kind:"file"}}function ii(){for(let e of Ut)if(e.previewUrl)try{URL.revokeObjectURL(e.previewUrl)}catch{}Ut.length=0,fi()}function fi(){let e=i("chat-attach-bar");if(e){if(!Ut.length){e.classList.add("hidden"),e.innerHTML="";return}e.classList.remove("hidden"),e.innerHTML=Ut.map((t,n)=>`
|
|
1175
|
+
<div class="chat-thumb relative" title="${p(t.ref||t.path)}">
|
|
1176
|
+
${t.previewUrl?`<img src="${t.previewUrl}" alt="${p(t.label||"img")}">`:`<span class="chat-thumb-path">${p(t.label||t.name||"file")}</span>`}
|
|
1177
|
+
<span class="chat-thumb-label">${p(t.label||t.kind||"")}</span>
|
|
1178
|
+
<button type="button" class="chat-thumb-x" data-rm-attach="${n}" aria-label="remove">\u2715</button>
|
|
1179
|
+
</div>`).join("")}}async function Wp(e){if(!e)return;let t=e.name||`upload-${Date.now()}`,n=await Vc(e,t),s=await Bp(n,t),{ref:a,label:o,kind:r}=Fp(e,s),d="";if(r==="image")try{d=URL.createObjectURL(n)}catch{}return Ut.push({path:s,ref:a,label:o,kind:r,name:t,previewUrl:d}),fi(),Up(i("chat-input"),a),s}async function Lo(e){let t=[...e||[]].filter(Boolean);if(!t.length)return;let n=i("chat-input");n&&(n.disabled=!0);try{for(let s of t)try{await Wp(s)}catch(a){P(`\u4E0A\u4F20\u5931\u8D25 ${s.name||"file"}: ${a.message}`)}}finally{n&&(n.disabled=!1,n.focus())}}function Gp(){let e=i("chat-file-input");if(e){e.value="",e.click();return}let t=document.createElement("input");t.type="file",t.accept="image/*,*/*",t.multiple=!0,t.addEventListener("change",()=>Lo(t.files)),t.click()}function Yc(){document.addEventListener("paste",async e=>{let t=i("chat-input");if(!t)return;let n=i("chat-composer");if(!(n&&(n.contains(document.activeElement)||document.activeElement===t))&&document.activeElement!==t)return;let a=[...e.clipboardData?.items||[]],o=[];for(let u of a)if(u.kind==="file"){let l=u.getAsFile();l&&o.push(l)}let r=o.filter(u=>pi(u)),d=r.length?r:o;d.length&&(e.preventDefault(),await Lo(d))}),!Hc&&(Hc=!0,document.addEventListener("dragover",e=>{let t=i("chat-composer");!t||!e.dataTransfer?.types?.includes("Files")||!t.contains(e.target)&&e.target!==t||(e.preventDefault(),t.classList.add("chat-drop-active"))}),document.addEventListener("dragleave",e=>{let t=i("chat-composer");t&&(e.target===t||t.contains(e.target))&&(t.contains(e.relatedTarget)||t.classList.remove("chat-drop-active"))}),document.addEventListener("drop",async e=>{let t=i("chat-composer");if(!t||(t.classList.remove("chat-drop-active"),!t.contains(e.target)&&e.target!==t))return;let n=[...e.dataTransfer?.files||[]];n.length&&(e.preventDefault(),await Lo(n))}))}function Ct(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function mi(e){let t=i("messages");t&&(t.insertAdjacentHTML("beforeend",`<div class="token-bar select-none">
|
|
1180
|
+
<span class="token-bar-mark">\u25C8</span><span class="token-bar-text">${p(e)}</span>
|
|
1181
|
+
</div>`),Re(t))}function xo(e){if(!e)return;let t=e.input_tokens??e.inputTokens??0,n=e.output_tokens??e.outputTokens??0,s=e.total_tokens??e.totalTokens??t+n,a=e.cache_read_input_tokens??e.cachedReadTokens?` \xB7 ${Ct(e.cache_read_input_tokens??e.cachedReadTokens)} cached`:"",o=e.cache_creation_input_tokens??e.cacheCreationInputTokens?` \xB7 ${Ct(e.cache_creation_input_tokens??e.cacheCreationInputTokens)} cache-write`:"",r=e.reasoning_tokens??e.reasoningTokens?` \xB7 ${Ct(e.reasoning_tokens??e.reasoningTokens)} reason`:"",d=e.costUSD??e.cost_usd,u=d!=null?` \xB7 $${Number(d).toFixed(4)}`:"",l=s?` \xB7 \u03A3${Ct(s)}`:"";mi(`\u2191${Ct(t)} \u2193${Ct(n)}${a}${o}${r}${l}${u}`)}function Kp(e){if(!e)return;let t=e.tokensUsed??e.contextTokensUsed,n=e.windowTokens??e.contextWindowTokens,s=e.usagePercent??e.contextWindowUsage;if(t==null&&n==null&&s==null)return;let a=[];t!=null&&n!=null?a.push(`context ${Ct(t)} / ${Ct(n)}`):t!=null&&a.push(`context ${Ct(t)}`),s!=null&&a.push(`${s}%`),e.model&&a.push(e.model),e.turnCount!=null&&a.push(`${e.turnCount} turns`),e.toolCallCount!=null&&a.push(`${e.toolCallCount} tools`),mi(`\u25A3 ${a.join(" \xB7 ")}`)}function zp(){let e=i("messages"),t=i("permission-requests");e&&(e.innerHTML="",delete e.dataset.historyPainting),t&&(t.innerHTML=""),c.shellBubble=null,ft=null,st=Ge=null,Ot=mt=null,Eo.clear(),ci.clear()}function Jp(e,t=c.sessionId){return`${t||""}
|
|
1182
|
+
${String(e||"")}`}function Xc(e,t=c.sessionId){let n=Jp(e,t);!e||ci.has(n)||(ci.add(n),rs("user","You",e,{ts:Date.now(),forceStick:!0}),i("messages")?.lastElementChild?.classList.add("queued-user-msg"))}function Qp(e){if((e.sessionId||c.sessionId)!==c.sessionId)return;let t=Array.isArray(e.items)?e.items.filter(n=>typeof n=="string"&&n.trim()):[];for(let n of t)Xc(n,e.sessionId||c.sessionId);t.length&&P(`\u231B Grok queue \xB7 ${t.length} prompt${t.length===1?"":"s"} waiting`)}function Zc(e,t,n={}){if(!e||!t||e.querySelector(".msg-actions"))return;let s=`a${++kp}`;Eo.set(s,{text:t,historyIndex:Number.isInteger(n.historyIndex)?n.historyIndex:null,sessionId:c.sessionId,agent:c.agent||S.peek()||"claude",machineId:c.machineId||null});let a=!["gemini","cursor"].includes(c.agent||S.peek()||"claude"),o=document.createElement("div");o.className="msg-actions",o.innerHTML=`
|
|
1183
|
+
<button type="button" class="msg-action-btn" data-copy-message="${p(s)}" title="Copy answer">Copy</button>
|
|
1184
|
+
${a?`<button type="button" class="msg-action-btn" data-fork-message="${p(s)}" title="Start a branch from this answer">Fork</button>`:""}`;let r=e.querySelector(".msg-ts");e.insertBefore(o,r||null)}async function Vp(e){let t=Eo.get(e.dataset.copyMessage||"");if(t){try{await navigator.clipboard.writeText(t.text),e.textContent="Copied"}catch{e.textContent="Failed"}setTimeout(()=>{e.textContent="Copy"},1300)}}async function Yp(e){let t=Eo.get(e.dataset.forkMessage||"");if(!(!t||!t.sessionId||t.sessionId!==c.sessionId)){e.disabled=!0,e.textContent="Forking\u2026";try{let n=await x("POST",`/api/sessions/${encodeURIComponent(t.sessionId)}/fork`,{sourceAgent:t.agent,...t.historyIndex!=null?{upTo:t.historyIndex}:{},assistantText:t.text},void 0,{machineId:t.machineId||void 0});if(!n?.success||!n.targetSessionId)throw new Error("Fork did not create a session");let s={parentSessionId:t.sessionId,parentAgent:t.agent,parentMachineId:t.machineId,forkMessageIndex:Number.isInteger(n.forkMessageIndex)?n.forkMessageIndex:t.historyIndex,forkedAt:Date.now()},a=await x("PUT","/api/sessions/meta",{sessionId:n.targetSessionId,agent:n.targetAgent||t.agent,branch:s,machineId:t.machineId||void 0},void 0,{machineId:t.machineId||void 0}),o=K(n.targetAgent||t.agent,n.targetSessionId,t.machineId);T.value={...T.peek(),[o]:{favorite:!!a?.favorite,notes:a?.notes||"",title:a?.title||"",hidden:!!a?.hidden,branch:a?.branch||s,updatedAt:a?.updatedAt||Date.now()}};let[{loadAllSessions:r},{resumeSession:d}]=await Promise.all([Promise.resolve().then(()=>(It(),to)),Promise.resolve().then(()=>(ns(),Yr))]);await r({waitFresh:!0}),await d(n.targetSessionId,E.peek()?.path||null,c.configDir||null,n.targetAgent||t.agent,t.machineId||null),P("Fork created \u2014 this branch can now continue independently.")}catch(n){e.textContent="Fork failed",P(`Fork failed: ${n.message}`),setTimeout(()=>{e.textContent="Fork"},1800)}finally{e.disabled=!1,e.textContent==="Forking\u2026"&&(e.textContent="Fork")}}}function Xp(e){let t=i("messages");if(!t)return null;let n=e==="shell-err"?" text-error":"";return t.insertAdjacentHTML("beforeend",`<div class="mx-2 rounded-lg code-surface px-3 py-2 text-sm font-mono${n} whitespace-pre-wrap break-words"></div>`),Re(t),t.lastElementChild}function Zp(e,t){e&&(e.textContent+=t,Re(e.closest("#messages")))}var ft=null;function ef(e){let t=typeof e.input=="object"?JSON.stringify(e.input,null,2):String(e.input||""),s=((typeof e.input=="object"?Object.values(e.input).find(a=>typeof a=="string"&&a.trim()):t)||"").replace(/\n/g," ").slice(0,_e.peek()==="full"?120:80);return{inputStr:t,preview:s}}function qc(e,{inBatch:t=!1}={}){let{inputStr:n,preview:s}=ef(e);return`<div class="tool-card${t?" tool-batch-item":""} cursor-pointer select-none px-2 py-1">
|
|
1185
|
+
<div class="flex items-center gap-1.5 text-xs font-mono">
|
|
1186
|
+
<span class="text-warning">\u26A1</span>
|
|
1187
|
+
<span class="text-warning font-semibold">${p(e.name||"tool")}</span>
|
|
1188
|
+
<span class="text-base-content/50 truncate flex-1">${p(s)}</span>
|
|
1189
|
+
<span class="tool-chevron text-[10px] text-base-content/40">\u25B6</span>
|
|
1190
|
+
</div>
|
|
1191
|
+
<div class="tool-detail">${p(n)}</div>
|
|
1192
|
+
</div>`}function tf(e){let t=[...new Set(e.names)],n=t.slice(0,4).join(", ")+(t.length>4?"\u2026":""),s=e.el.querySelector(".tool-batch-summary");s&&(s.innerHTML=`<span class="text-warning">\u26A1</span>
|
|
1193
|
+
<span class="font-semibold text-base-content/70">${e.count} tool${e.count===1?"":"s"}</span>
|
|
1194
|
+
<span class="text-base-content/40 truncate flex-1">${p(n)}</span>
|
|
1195
|
+
<span class="tool-chevron text-[10px] text-base-content/40">\u25B6</span>`)}function os(){ft=null}function nf(e,t={}){let n=i("messages");if(!n)return;let s=_e.peek()||"normal",a=O(t.ts);if(s==="clean"){if(!ft||!n.contains(ft.el)){let u=$o(a),l=So(a);n.insertAdjacentHTML("beforeend",`
|
|
1196
|
+
<div class="msg-row assistant px-2" data-ts="${p(l)}">
|
|
1197
|
+
<div class="tool-batch w-full max-w-[96%] px-2 py-1.5">
|
|
1198
|
+
<div class="tool-batch-summary flex items-center gap-1.5 text-xs font-mono"></div>
|
|
1199
|
+
<div class="tool-batch-list"></div>
|
|
1200
|
+
</div>
|
|
1201
|
+
${u?`<div class="msg-ts" title="${p(l)}">${p(u)}</div>`:""}
|
|
1202
|
+
</div>`),ft={el:n.lastElementChild.querySelector(".tool-batch"),names:[],count:0}}ft.names.push(e.name||"tool"),ft.count++,ft.el.querySelector(".tool-batch-list")?.insertAdjacentHTML("beforeend",qc(e,{inBatch:!0})),tf(ft),Re(n);return}ft=null;let o=$o(a),r=So(a);n.insertAdjacentHTML("beforeend",`
|
|
1203
|
+
<div class="msg-row assistant px-2" data-ts="${p(r)}">
|
|
1204
|
+
<div class="w-full max-w-[96%]">${qc(e)}</div>
|
|
1205
|
+
${o?`<div class="msg-ts" title="${p(r)}">${p(o)}</div>`:""}
|
|
1206
|
+
</div>`),Re(n)}function Rc(){let e=i("messages");e&&e.setAttribute("data-density",_e.peek()||"normal")}function sf(e){let t=e.request_id||e.requestId;if(!t||i(`perm-${t}`))return;let n=e.tool_input?JSON.stringify(e.tool_input).slice(0,200):"";i("permission-requests")?.insertAdjacentHTML("beforeend",`
|
|
1207
|
+
<div id="perm-${t}" class="perm-banner mx-3 mb-2 rounded-lg border border-warning/25 bg-warning/8 p-3">
|
|
1208
|
+
<div class="text-xs text-warning font-semibold mb-1">\u26A0\uFE0F Permission Required</div>
|
|
1209
|
+
<div class="font-mono text-xs text-base-content/60 break-all mb-2">
|
|
1210
|
+
<strong class="text-base-content">${p(e.tool_name||"")}</strong> ${p(n)}
|
|
1211
|
+
</div>
|
|
1212
|
+
<div class="flex gap-2">
|
|
1213
|
+
<button class="btn btn-success btn-xs" data-perm-id="${t}" data-perm-allow="1">Allow</button>
|
|
1214
|
+
<button class="btn btn-error btn-xs" data-perm-id="${t}" data-perm-allow="0">Deny</button>
|
|
1215
|
+
</div>
|
|
1216
|
+
</div>`),Re(i("messages"))}var Bc=!1;function af(){if(Bc||typeof marked>"u")return;let e=s=>String(s??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),t=(s,a)=>{let o=String(a||"").trim().split(/\s+/)[0]||"",r=o||"text",d=o?`language-${p(o)}`:"";return`<div class="code-block">
|
|
1217
|
+
<div class="code-block-header">
|
|
1218
|
+
<span class="code-block-lang">${p(r)}</span>
|
|
1219
|
+
<button type="button" class="code-copy" data-copy="1" title="Copy code">Copy</button>
|
|
1220
|
+
</div>
|
|
1221
|
+
<pre><code class="hljs ${d}">${e(s)}</code></pre>
|
|
1222
|
+
</div>`},n={code(s,a){return s&&typeof s=="object"&&s.text!=null?t(s.text,s.lang||a):t(s,a)},table(s,a){return s&&typeof s=="object"&&!Array.isArray(s)&&s.header?!1:`<div class="table-wrap"><table><thead>${s}</thead><tbody>${a}</tbody></table></div>`},html(s){return e(s)}};try{if(typeof marked.use=="function")marked.use({gfm:!0,breaks:!0,renderer:n});else if(typeof marked.setOptions=="function"){let s=new marked.Renderer;s.code=n.code,s.table=n.table,marked.setOptions({gfm:!0,breaks:!0,renderer:s})}}catch(s){console.warn("[md] marked setup failed",s)}Bc=!0}function yo(e){if(typeof marked>"u")return p(e);try{return af(),Ve(e,{fallback:()=>p(e)})}catch{return p(e)}}function of(e){!e||typeof hljs>"u"||(e.querySelectorAll("pre code:not(.hljs)").forEach(t=>{try{hljs.highlightElement(t)}catch{}}),e.querySelectorAll("pre code.hljs").forEach(t=>{t.classList.add("hljs")}))}function ed(e){of(e),xt(e),vt(e)}function td(){Rc(),ar(),De(fe,s=>{Js(),jt();let a=i("ws-banner"),o=i("ws-banner-text");if(!a)return;if(s==="open"||s==="idle"){a.classList.add("hidden"),o&&(o.textContent="");return}if(s==="connecting"&&!bo){a.classList.add("hidden");return}a.classList.remove("hidden");let r=s==="offline"?"\u7F51\u7EDC\u5DF2\u65AD\u5F00\uFF0C\u6062\u590D\u540E\u4F1A\u81EA\u52A8\u91CD\u8FDE":s==="connecting"?"\u6B63\u5728\u8FDE\u63A5\u2026":"\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u6B63\u5728\u91CD\u8FDE\u2026\uFF08\u7184\u5C4F\u6216\u5207\u7F51\u65F6\u5E38\u89C1\uFF09";o?o.textContent=r:a.textContent=r}),De(E,()=>jt()),b.on("click","#messages a, #chat-log a, .md-body a",(s,a)=>{let o=a.getAttribute("href")||"",r=E.peek()?.path||"";Zo(o,r)&&(s.preventDefault(),s.stopPropagation())}),b.on("click","#ws-banner-retry",s=>{s.preventDefault(),Cp()}),De(D,s=>{i("send-btn")?.classList.toggle("hidden",s),i("stop-btn")?.classList.toggle("hidden",!s),as(),s||i("send-btn")?.toggleAttribute("disabled",!tn());let a=i("messages");if(!a)return;let o=i("typing-indicator");s&&!o?(a.insertAdjacentHTML("beforeend",'<div id="typing-indicator" class="flex justify-start px-2"><div class="flex items-center gap-1.5 rounded-2xl rounded-tl-sm px-3 py-2 bg-base-200 text-xs text-base-content/40"><span class="dot"></span><span class="dot"></span><span class="dot"></span></div></div>'),Re(a)):s||(o?.remove(),os()),jt()}),De(_e,()=>Rc()),document.addEventListener("session-lock-changed",()=>as()),as(),b.on("keydown","#chat-input",s=>{if(s.key!=="Enter")return;let a=s.metaKey||s.ctrlKey,o=window.matchMedia("(max-width: 640px)").matches&&!s.shiftKey&&!a;(a||o)&&(s.preventDefault(),Xs())}),b.on("submit","#chat-form",s=>{s.preventDefault(),Xs()}),b.on("input","#chat-input",(s,a)=>{Vs(a),Qs(a.value)}),b.on("click","#btn-attach",s=>{s.preventDefault(),Gp()}),b.on("change","#chat-file-input",(s,a)=>{let o=a?.files;o?.length&&Lo(o),a&&(a.value="")}),b.on("click","[data-rm-attach]",(s,a)=>{s.preventDefault(),s.stopPropagation();let o=parseInt(a.dataset.rmAttach,10);if(Number.isNaN(o)||o<0||o>=Ut.length)return;let r=Ut[o];if(r?.previewUrl)try{URL.revokeObjectURL(r.previewUrl)}catch{}let d=i("chat-input");d&&r?.ref&&(d.value=d.value.split(r.ref).join("").replace(/\n{3,}/g,`
|
|
1223
|
+
|
|
1224
|
+
`),d.dispatchEvent(new Event("input"))),Ut.splice(o,1),fi()}),b.on("click","[data-perm-id]",(s,a)=>{lt({type:"command",cmd:"approval.respond",requestId:a.dataset.permId,allow:a.dataset.permAllow==="1",sessionId:c.sessionId}),a.closest(".perm-banner")?.remove()}),b.on("click",".tool-card",(s,a)=>{let o=a.closest(".tool-batch");if(o&&!o.classList.contains("open")&&!a.classList.contains("tool-batch-item"))return;s.stopPropagation();let r=i("messages"),d=a.getBoundingClientRect().top;if(a.classList.toggle("open"),r){let u=a.getBoundingClientRect().top;r.scrollTop+=u-d}}),b.on("click",".tool-batch",(s,a)=>{if(s.target.closest(".tool-card")&&a.classList.contains("open"))return;let o=i("messages"),r=a.getBoundingClientRect().top;if(a.classList.toggle("open"),o){let d=a.getBoundingClientRect().top;o.scrollTop+=d-r}});let e=i("messages"),t=i("scroll-top-btn"),n=i("scroll-bottom-btn");if(e&&t&&n){let s=()=>{let a=e.scrollHeight-e.clientHeight>200;t.classList.toggle("hidden",!a||e.scrollTop<200),n.classList.toggle("hidden",!a||wp(e))};e.addEventListener("scroll",s,{passive:!0}),new ResizeObserver(s).observe(e),new MutationObserver(s).observe(e,{childList:!0,subtree:!0}),t.addEventListener("click",()=>e.scrollTo({top:0,behavior:"smooth"})),n.addEventListener("click",()=>{Oc(e)?.setFollowing(!0),e.scrollTo({top:e.scrollHeight,behavior:"smooth"})}),s()}b.on("click",".msg-expand-btn",(s,a)=>{s.stopPropagation();let r=a.closest(".msg-card").classList.toggle("open");a.textContent=r?"\u25B2 Show less":"\u25BC Show more"}),b.on("click","[data-copy-message]",(s,a)=>{s.preventDefault(),s.stopPropagation(),Vp(a)}),b.on("click","[data-fork-message]",(s,a)=>{s.preventDefault(),s.stopPropagation(),Yp(a)}),b.on("click",".code-copy",async(s,a)=>{s.preventDefault(),s.stopPropagation();let d=a.closest(".code-block")?.querySelector("pre code")?.textContent??"";try{await navigator.clipboard.writeText(d),a.textContent="Copied",a.classList.add("copied"),setTimeout(()=>{a.textContent="Copy",a.classList.remove("copied")},1400)}catch{a.textContent="Failed",setTimeout(()=>{a.textContent="Copy"},1400)}})}W();F();le();Vo();_n();Zt();en();function rf(e){let t=e.split(".").pop()?.toLowerCase();return{js:"\u{1F4C4}",ts:"\u{1F4C4}",jsx:"\u{1F4C4}",tsx:"\u{1F4C4}",py:"\u{1F40D}",md:"\u{1F4DD}",json:"\u2699\uFE0F",html:"\u{1F310}",css:"\u{1F3A8}",sh:"\u26A1",env:"\u{1F511}",docx:"\u{1F4D8}",pptx:"\u{1F4D9}",xlsx:"\u{1F4D7}",pdf:"\u{1F4D5}"}[t]||"\u{1F4C4}"}function nd(e){let t=(e||"").split("/").pop()||"",n=t.lastIndexOf(".");return n>=0?t.slice(n+1).toLowerCase():""}function sd(e){let t=nd(e);return t==="docx"||t==="pptx"||t==="xlsx"||t==="pdf"?t:null}function ad(e){let t=nd(e);return t==="md"||t==="markdown"||t==="mdx"}function lf(e){return e==null?"":e>1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:e>1024?`${(e/1024).toFixed(1)} KB`:`${e} B`}function cf(e){let t=atob(e),n=new Uint8Array(t.length);for(let s=0;s<t.length;s++)n[s]=t.charCodeAt(s);return n.buffer}var hi=new Map;function Io(e){if(hi.has(e))return hi.get(e);let t=new Promise((n,s)=>{let a=document.querySelector(`script[data-src="${e}"]`);if(a){if(a.dataset.loaded==="1")return n();a.addEventListener("load",()=>n()),a.addEventListener("error",()=>s(new Error(`Failed to load ${e}`)));return}let o=document.createElement("script");o.src=e,o.async=!0,o.dataset.src=e,o.onload=()=>{o.dataset.loaded="1",n()},o.onerror=()=>s(new Error(`Failed to load ${e}`)),document.head.appendChild(o)});return hi.set(e,t),t}function df(e){let n=((e||"").split("/").pop()||"").toLowerCase(),s={dockerfile:"dockerfile",makefile:"makefile",gemfile:"ruby",rakefile:"ruby",procfile:"yaml","cmakelists.txt":"cmake"};if(s[n])return s[n];let a=n.includes(".")?n.split(".").pop():"";return{js:"javascript",mjs:"javascript",cjs:"javascript",jsx:"javascript",ts:"typescript",tsx:"typescript",mts:"typescript",cts:"typescript",py:"python",pyw:"python",pyi:"python",rb:"ruby",go:"go",rs:"rust",java:"java",kt:"kotlin",kts:"kotlin",c:"c",h:"c",cpp:"cpp",cc:"cpp",cxx:"cpp",hpp:"cpp",hh:"cpp",cs:"csharp",swift:"swift",php:"php",scala:"scala",sh:"bash",bash:"bash",zsh:"bash",fish:"bash",ps1:"powershell",psm1:"powershell",html:"xml",htm:"xml",xhtml:"xml",xml:"xml",svg:"xml",css:"css",scss:"scss",less:"less",json:"json",jsonc:"json",json5:"json",yml:"yaml",yaml:"yaml",toml:"ini",ini:"ini",conf:"ini",env:"bash",md:"markdown",mdx:"markdown",markdown:"markdown",sql:"sql",graphql:"graphql",gql:"graphql",vue:"xml",svelte:"xml",r:"r",lua:"lua",pl:"perl",pm:"perl",dart:"dart",ex:"elixir",exs:"elixir",erl:"erlang",zig:"zig",nim:"nim",clj:"clojure",cljs:"clojure",diff:"diff",patch:"diff",dockerfile:"dockerfile"}[a]||""}function uf(e){!e||typeof hljs>"u"||e.querySelectorAll("pre code.file-preview-code").forEach(t=>{try{delete t.dataset.highlighted,hljs.highlightElement(t)}catch{}})}function is(e,t,n){let s=lf(t);return`
|
|
1225
|
+
<div class="flex items-center gap-2 px-4 py-1.5 border-b border-base-300 flex-shrink-0 bg-base-200">
|
|
1226
|
+
<span class="text-xs text-base-content/40 flex-1 truncate">${p(e)} \xB7 ${p(s)}${n?` \xB7 <span class="text-primary/70">${p(n)}</span>`:""}</span>
|
|
1227
|
+
<button type="button" class="btn btn-ghost btn-xs" data-download-path="${p(e)}">\u2193 Download</button>
|
|
1228
|
+
</div>`}function pf(e){return!Array.isArray(e)||!e.length?'<div class="p-4 text-xs text-base-content/40">Empty directory</div>':(e.sort((t,n)=>n.isDir-t.isDir||t.name.localeCompare(n.name)),e.map(t=>`
|
|
1229
|
+
<div class="flex items-center gap-2 px-4 py-1.5 hover:bg-base-300 group"
|
|
1230
|
+
${t.isDir?`data-dir-path="${p(t.path)}"`:`data-file-path="${p(t.path)}"`}>
|
|
1231
|
+
<span class="cursor-pointer flex-shrink-0">${t.isDir?"\u{1F4C1}":rf(t.name)}</span>
|
|
1232
|
+
<span class="text-sm flex-1 truncate cursor-pointer ${t.isDir?"text-primary":""}">${p(t.name)}</span>
|
|
1233
|
+
${t.isDir?"":`
|
|
1234
|
+
<button type="button" class="file-row-action btn btn-ghost btn-xs px-1.5 text-base-content/50 hover:text-base-content"
|
|
1235
|
+
data-download-path="${p(t.path)}" title="Download" aria-label="Download">\u2193</button>
|
|
1236
|
+
<button type="button" class="file-row-action btn btn-ghost btn-xs px-1.5 text-error/60 hover:text-error"
|
|
1237
|
+
data-delete-path="${p(t.path)}" title="Delete" aria-label="Delete">\u2715</button>`}
|
|
1238
|
+
</div>`).join(""))}function ff(e,t,n){let s=/[\x00-\x08\x0e-\x1f]/.test(t.slice(0,512));if(!s&&ad(e))return hf(e,t,n);let a=df(e),o=a?`language-${p(a)}`:"",r=s?`<div class="p-4 text-xs text-base-content/40">Binary file \u2014 <button class="text-primary hover:underline" data-download-path="${p(e)}">Download</button></div>`:`<pre class="file-preview p-4 font-mono text-xs leading-relaxed overflow-auto flex-1 m-0"><code class="hljs file-preview-code ${o}">${p(t)}</code></pre>`;return is(e,n,s?"binary":a||"text")+r}function mf(e){return Ve(e,{fallback:t=>p(t).replace(/\n/g,"<br>")})}function hf(e,t,n){return is(e,n,"Markdown")+`
|
|
1239
|
+
<div class="file-markdown-toolbar" role="group" aria-label="Markdown view">
|
|
1240
|
+
<button type="button" class="file-markdown-mode active" data-file-render-mode="preview">Preview</button>
|
|
1241
|
+
<button type="button" class="file-markdown-mode" data-file-render-mode="code">Code</button>
|
|
1242
|
+
</div>
|
|
1243
|
+
<div class="file-markdown-preview md p-4 overflow-auto flex-1">${mf(t)}</div>
|
|
1244
|
+
<pre class="file-markdown-code file-preview p-4 font-mono text-xs leading-relaxed overflow-auto flex-1 m-0 hidden"><code class="file-preview-code language-markdown">${p(t)}</code></pre>`}function gf(e){let t=e?.querySelector(".file-markdown-preview");t&&(typeof hljs<"u"&&t.querySelectorAll("pre code:not(.hljs)").forEach(n=>{try{hljs.highlightElement(n)}catch{}}),xt(t),vt(t))}async function bf(e){if(await Io("/vendor/mammoth.browser.min.js"),typeof mammoth>"u")throw new Error("mammoth failed to load");let t=await mammoth.convertToHtml({arrayBuffer:e});return`<div class="office-preview office-docx overflow-auto flex-1 p-4 md">${t.messages?.length?`<div class="office-warn text-xs text-warning/80 px-3 py-1">${t.messages.length} conversion note(s)</div>`:""}<div class="office-docx-body">${t.value||'<p class="text-base-content/40">Empty document</p>'}</div></div>`}async function vf(e){if(await Io("/vendor/xlsx.full.min.js"),typeof XLSX>"u")throw new Error("SheetJS failed to load");let t=XLSX.read(new Uint8Array(e),{type:"array"}),n=t.SheetNames||[];if(!n.length)return'<div class="p-4 text-xs text-base-content/40">Empty workbook</div>';let s=n.map((o,r)=>`<button type="button" class="office-sheet-tab${r===0?" active":""}" data-sheet-idx="${r}">${p(o)}</button>`).join(""),a=n.map((o,r)=>{let d=t.Sheets[o],u;try{u=XLSX.utils.sheet_to_html(d,{id:`xlsx-sheet-${r}`,editable:!1})}catch{u='<p class="text-base-content/40 text-xs p-2">Unable to render this sheet</p>'}return`<div class="office-sheet-pane${r===0?"":" hidden"}" data-sheet-pane="${r}">${u}</div>`}).join("");return`
|
|
1245
|
+
<div class="office-preview office-xlsx flex flex-col flex-1 min-h-0 overflow-hidden">
|
|
1246
|
+
<div class="office-sheet-tabs flex gap-1 px-2 py-1.5 border-b border-base-300 overflow-x-auto flex-shrink-0 bg-base-200">${s}</div>
|
|
1247
|
+
<div class="office-sheet-body flex-1 overflow-auto p-2">${a}</div>
|
|
1248
|
+
</div>`}function xf(e){let t=[],n=/<a:p[\s>][\s\S]*?<\/a:p>/g,s=/<a:t(?:\s[^>]*)?>([\s\S]*?)<\/a:t>/g,a,o=e.match(n)||[e];for(let r of o){let d=[];for(s.lastIndex=0;(a=s.exec(r))!==null;){let u=a[1].replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'");u&&d.push(u)}d.length&&t.push(d.join(""))}return t}async function yf(e){if(await Io("/vendor/jszip.min.js"),typeof JSZip>"u")throw new Error("JSZip failed to load");let t=await JSZip.loadAsync(e),n=Object.keys(t.files).filter(a=>/^ppt\/slides\/slide\d+\.xml$/i.test(a)).sort((a,o)=>{let r=parseInt(a.match(/slide(\d+)/i)?.[1]||"0",10),d=parseInt(o.match(/slide(\d+)/i)?.[1]||"0",10);return r-d});if(!n.length)return'<div class="p-4 text-xs text-base-content/40">No slides found in this presentation</div>';let s=[];for(let a=0;a<n.length;a++){let o=await t.files[n[a]].async("string"),r=xf(o),d=r.length?r.map(u=>`<p>${p(u)}</p>`).join(""):'<p class="text-base-content/40 italic">\uFF08\u6B64\u9875\u65E0\u53EF\u63D0\u53D6\u6587\u672C / \u53EF\u80FD\u4EE5\u56FE\u7247\u4E3A\u4E3B\uFF09</p>';s.push(`
|
|
1249
|
+
<article class="office-slide-card">
|
|
1250
|
+
<header class="office-slide-num">Slide ${a+1}</header>
|
|
1251
|
+
<div class="office-slide-body">${d}</div>
|
|
1252
|
+
</article>`)}return`
|
|
1253
|
+
<div class="office-preview office-pptx overflow-auto flex-1 p-3 space-y-3">
|
|
1254
|
+
<p class="text-xs text-base-content/50 px-1">\u6587\u672C\u9884\u89C8\uFF08\u7248\u5F0F/\u56FE\u7247\u4E0D\u8FD8\u539F\uFF09\xB7 ${n.length} slide(s)</p>
|
|
1255
|
+
${s.join("")}
|
|
1256
|
+
</div>`}async function wf(){if(await Io("/vendor/pdf.min.js"),typeof pdfjsLib>"u")throw new Error("pdf.js failed to load");return pdfjsLib.GlobalWorkerOptions.workerSrc="/vendor/pdf.worker.min.js",pdfjsLib}async function kf(e){let n=await(await wf()).getDocument({data:e}).promise,s=n.numPages,a=Math.min(s,40),o=[];for(let d=1;d<=a;d++){let u=await n.getPage(d),l=u.getViewport({scale:1}),f=Math.min(1.5,820/l.width),m=u.getViewport({scale:f}),g=document.createElement("canvas");g.width=Math.floor(m.width),g.height=Math.floor(m.height),g.className="office-pdf-page",g.dataset.page=String(d),await u.render({canvasContext:g.getContext("2d"),viewport:m}).promise,o.push(`
|
|
1257
|
+
<figure class="office-pdf-figure">
|
|
1258
|
+
<figcaption class="office-pdf-cap">Page ${d} / ${s}</figcaption>
|
|
1259
|
+
${g.outerHTML}
|
|
1260
|
+
</figure>`)}let r=s>a?`<p class="text-xs text-base-content/50 px-2">Showing first ${a} of ${s} pages \u2014 download for full file.</p>`:"";return`
|
|
1261
|
+
<div class="office-preview office-pdf overflow-auto flex-1 p-3 space-y-3">
|
|
1262
|
+
<p class="text-xs text-base-content/50 px-1">PDF preview \xB7 ${s} page(s)</p>
|
|
1263
|
+
${r}
|
|
1264
|
+
${o.join("")}
|
|
1265
|
+
</div>`}async function $f(e,t,n){let s=sd(e),a={docx:"Word",pptx:"PowerPoint",xlsx:"Excel",pdf:"PDF"},o=cf(t),r;if(s==="docx")r=await bf(o);else if(s==="xlsx")r=await vf(o);else if(s==="pptx")r=await yf(o);else if(s==="pdf")r=await kf(o);else throw new Error("Unsupported office type");return is(e,n,a[s]||s)+r}function Sf(e,t){let n=e?e.split("/"):[],s=t?n.slice(0,-1):n,a='<span class="cursor-pointer text-primary hover:underline" data-dir-path="">root</span>',o="";for(let r of s)o=o?`${o}/${r}`:r,a+=` <span class="text-base-content/40">/</span> <span class="cursor-pointer text-primary hover:underline" data-dir-path="${p(o)}">${p(r)}</span>`;return t&&(a+=` <span class="text-base-content/40">/</span> <span>${p(n.at(-1))}</span>`),a}function Lf(){let e=E.peek(),t=re.peek()||e?.path;if(!t)return;let n=document.createElement("input");n.type="file",n.multiple=!0,n.addEventListener("change",async()=>{let s=V.peek(),a="_",o=[...n.files],r=!1;for(let d of o){let u=s?`${s}/${d.name}`:d.name,l=`/api/projects/${a}/file?root=${encodeURIComponent(t)}&path=${encodeURIComponent(u)}`;try{let f=await fetch(l,{method:"POST",headers:ct(),body:d,duplex:"half"});if(!f.ok){let m=await f.json().catch(()=>({}));throw new Error(m.error||`HTTP ${f.status}`)}}catch(f){alert(`Upload failed (${d.name}): ${f.message}`),r=!0;break}}if(!r){let d=V.peek();V.value=d+"\0",V.value=d}}),n.click()}async function Ef(e,t){let n=re.peek()||e?.path||"";if(!n){alert("No path selected \u2014 set root first");return}let s="_",a=(t||"").split("/").pop()||"download",o=new URLSearchParams({root:n,path:t,download:"true"}),r=`/api/projects/${s}/file?${o}`;try{let d=await fetch(r,{headers:ct(),credentials:"same-origin"});if(!d.ok){let m=await d.json().catch(()=>({}));throw new Error(m.error||`HTTP ${d.status}`)}let u=await d.blob(),l=URL.createObjectURL(u),f=document.createElement("a");f.href=l,f.download=a,f.rel="noopener",f.style.display="none",document.body.appendChild(f),f.click(),f.remove(),setTimeout(()=>URL.revokeObjectURL(l),6e4)}catch(d){try{let u=`/api/projects/${s}/file?${Jo({root:n,path:t,download:"true"})}`,l=document.createElement("a");l.href=u,l.download=a,l.rel="noopener",l.target="_blank",document.body.appendChild(l),l.click(),l.remove()}catch{alert(`Download failed: ${d.message}`)}}}async function If(e,t){if(!confirm(`Delete "${t.split("/").pop()}"?`))return;let n=re.peek()||e?.path||"",s="_";try{await x("DELETE",`/api/projects/${s}/file?root=${encodeURIComponent(n)}&path=${encodeURIComponent(t)}`),V.value=V.peek()+" ",V.value=V.peek().trimEnd()}catch(a){alert(`Delete failed: ${a.message}`)}}async function Tf(e,t,n,s){let a=n.size??(typeof n.content=="string"?n.content.length:0),o=sd(t);if(o&&n.encoding==="base64"){e.innerHTML=is(t,a,o)+`<div class="p-4 text-xs text-base-content/40">Parsing ${o.toUpperCase()}\u2026</div>`;try{let r=await $f(t,n.content,a);if(s.aborted)return;e.innerHTML=r}catch(r){if(s.aborted)return;e.innerHTML=is(t,a,o)+`<div class="p-4 text-xs text-error">Preview failed: ${p(r.message)} \u2014 <button class="text-primary hover:underline" data-download-path="${p(t)}">Download</button></div>`}return}if(n.encoding==="base64"){e.innerHTML=is(t,a,"binary")+`<div class="p-4 text-xs text-base-content/40">Binary file \u2014 <button class="text-primary hover:underline" data-download-path="${p(t)}">Download</button></div>`;return}e.innerHTML=ff(t,n.content||"",a),uf(e),ad(t)&&gf(e)}function od(){je(()=>{let e=i("files-breadcrumb");if(!e)return;let t=oe.value!==null;e.innerHTML=`
|
|
1266
|
+
${Sf(oe.value??V.value,t)}
|
|
1267
|
+
<div class="flex-1"></div>
|
|
1268
|
+
${t?"":'<button id="btn-upload" class="btn btn-ghost btn-xs text-base-content/50 hover:text-base-content">\u2191 Upload</button>'}`}),Tn(async e=>{let t=Y.value,n=E.value,s=(re.value||n?.path||"").trim(),a=oe.value,o=V.value,r=i("files-area");if(!r||t!=="files")return;if(!s){r.innerHTML='<div class="p-4 text-xs text-base-content/40">No path yet \u2014 open a session (uses that machine's cwd) or type an absolute path and press Go.</div>';return}let d="_";r.innerHTML='<div class="p-4 text-xs text-base-content/40">Loading\u2026</div>';try{if(a!==null){let f=await x("GET",`/api/projects/${d}/file?root=${encodeURIComponent(s)}&path=${encodeURIComponent(a)}`,void 0,e);e.aborted||await Tf(r,a,f,e);return}let u=await x("GET",`/api/projects/${d}/files?root=${encodeURIComponent(s)}&path=${encodeURIComponent(o)}`,void 0,e);if(e.aborted)return;let l=Array.isArray(u)?u:Array.isArray(u?.files)?u.files:null;if(!l){r.innerHTML=`<div class="p-4 text-xs text-error">${p(u?.error||"Invalid directory listing")}</div>`;return}r.innerHTML=pf(l)}catch(u){!e.aborted&&u?.name!=="AbortError"&&(r.innerHTML=`<div class="p-4 text-xs text-error">${p(u.message)}</div>`)}}),b.on("click","[data-dir-path]",(e,t)=>{oe.value=null,V.value=t.dataset.dirPath}),b.on("click","[data-file-path]",(e,t)=>{oe.value=t.dataset.filePath}),b.on("click","#btn-upload",()=>Lf()),b.on("click","[data-download-path]",(e,t)=>{e.preventDefault(),e.stopPropagation();let n=t.dataset.downloadPath;n&&Ef(E.peek(),n)}),b.on("click","[data-delete-path]",(e,t)=>{e.preventDefault(),e.stopPropagation();let n=t.dataset.deletePath;n&&If(E.peek(),n)}),b.on("click","[data-file-render-mode]",(e,t)=>{let n=t.closest("#files-area");if(!n)return;let s=t.dataset.fileRenderMode==="code";n.querySelector(".file-markdown-preview")?.classList.toggle("hidden",s),n.querySelector(".file-markdown-code")?.classList.toggle("hidden",!s),n.querySelectorAll("[data-file-render-mode]").forEach(a=>{a.classList.toggle("active",a===t)})}),b.on("click",".office-sheet-tab",(e,t)=>{let n=t.closest(".office-xlsx");if(!n)return;let s=t.dataset.sheetIdx;n.querySelectorAll(".office-sheet-tab").forEach(a=>a.classList.toggle("active",a===t)),n.querySelectorAll(".office-sheet-pane").forEach(a=>{a.classList.toggle("hidden",a.dataset.sheetPane!==s)})})}W();F();le();var rd=I(!1);function Cf(e){return e?e.split(`
|
|
1269
|
+
`).map(t=>p(t).replace(/\b([0-9a-f]{7})\b/,'<span class="gh">$1</span>').replace(/\(([^)]*)\)/,'<span style="color:oklch(var(--wa))">($1)</span>')).join(`
|
|
1270
|
+
`):'<span class="text-base-content/40">No commits</span>'}function Mf(e){if(!e)return"";if(!e.isGit)return'<div class="p-4 text-sm text-base-content/50">Not a git repository</div>';let t={M:"text-warning",D:"text-error"};return`
|
|
1271
|
+
<div class="px-4 py-2 text-xs text-base-content/50 border-b border-base-300">
|
|
1272
|
+
Branch: <span class="text-success font-semibold">${p(e.branch)}</span>
|
|
1273
|
+
</div>
|
|
1274
|
+
${e.files.length?e.files.map(n=>`
|
|
1275
|
+
<div class="flex items-center gap-3 px-4 py-1 text-sm">
|
|
1276
|
+
<span class="font-mono text-xs w-5 flex-shrink-0 ${t[n.status]||"text-success"}">${p(n.status)}</span>
|
|
1277
|
+
<span class="break-all">${p(n.file)}</span>
|
|
1278
|
+
</div>`).join(""):'<div class="px-4 py-2 text-sm text-base-content/50">Working tree clean</div>'}
|
|
1279
|
+
<div class="border-t border-base-300 p-4">
|
|
1280
|
+
<div class="flex gap-4 text-xs mb-3">
|
|
1281
|
+
<span id="diff-unstaged" class="cursor-pointer text-primary">Unstaged</span>
|
|
1282
|
+
<span id="diff-staged" class="cursor-pointer text-base-content/50">Staged</span>
|
|
1283
|
+
</div>
|
|
1284
|
+
<div id="diff-content" class="font-mono text-xs overflow-auto max-h-[30vh] whitespace-pre"></div>
|
|
1285
|
+
</div>
|
|
1286
|
+
<div class="border-t border-base-300">
|
|
1287
|
+
<div class="flex items-center justify-between px-4 py-2 text-xs text-base-content/50 cursor-pointer select-none" id="git-graph-toggle">
|
|
1288
|
+
<span class="uppercase tracking-wider font-medium">Git Graph</span>
|
|
1289
|
+
<span id="git-graph-chevron" class="text-[10px]">\u25B6</span>
|
|
1290
|
+
</div>
|
|
1291
|
+
<div id="git-graph-panel" class="hidden px-4 pb-4">
|
|
1292
|
+
<div id="git-graph-content" class="git-graph overflow-x-auto max-h-[35vh] overflow-y-auto">
|
|
1293
|
+
<span class="text-base-content/40">Loading\u2026</span>
|
|
1294
|
+
</div>
|
|
1295
|
+
</div>
|
|
1296
|
+
</div>`}function Af(e){return e.split(`
|
|
1297
|
+
`).map(t=>t.startsWith("+")&&!t.startsWith("+++")?`<span class="diff-add">${p(t)}</span>`:t.startsWith("-")&&!t.startsWith("---")?`<span class="diff-del">${p(t)}</span>`:t.startsWith("@@")?`<span class="diff-hunk">${p(t)}</span>`:/^(diff |index |---|[+]{3})/.test(t)?`<span class="diff-head">${p(t)}</span>`:`<span>${p(t)}</span>`).join(`
|
|
1298
|
+
`)}function id(){Tn(async e=>{let t=Y.value,n=E.value,s=Se.value||n?.path,a=i("git-area");if(!a||t!=="git")return;if(!s){a.innerHTML='<div class="p-4 text-sm text-base-content/50">Enter a project root above, or open a session with a working directory.</div>';return}let o="_";a.innerHTML='<div class="p-4 text-xs text-base-content/40">Loading\u2026</div>';try{let r=await x("GET",`/api/projects/${o}/git/status?root=${encodeURIComponent(s)}`,void 0,e);e.aborted||(a.innerHTML=Mf(r))}catch(r){!e.aborted&&r?.name!=="AbortError"&&(a.innerHTML=`<div class="p-4 text-xs text-error">${p(r?.message??String(r))}</div>`)}}),Tn(async e=>{let t=E.value,n=Se.value||t?.path,s=rd.value,a=i("diff-content");if(!a||!n)return;let o=t?.id||"_";try{let r=await x("GET",`/api/projects/${o}/git/diff?root=${encodeURIComponent(n)}${s?"&staged=true":""}`,void 0,e);e.aborted||(a.innerHTML=r?.diff?Af(r.diff):'<span class="text-base-content/40">No changes</span>')}catch(r){!e.aborted&&r?.name!=="AbortError"&&(a.innerHTML=`<span class="text-error">${p(r?.message??String(r))}</span>`)}}),b.on("click","#diff-unstaged, #diff-staged",(e,t)=>{let n=t.id==="diff-staged";rd.value=n,i("diff-unstaged").className=`cursor-pointer ${n?"text-base-content/50":"text-primary"}`,i("diff-staged").className=`cursor-pointer ${n?"text-primary":"text-base-content/50"}`}),b.on("click","#git-graph-toggle",()=>{let e=i("git-graph-panel"),t=i("git-graph-chevron"),n=e.classList.toggle("hidden");t.textContent=n?"\u25B6":"\u25BC",n||jf()})}function jf(){let e=E.peek(),t=Se.peek()||e?.path,n=i("git-graph-content");if(!t||!n)return;let s="_";n.innerHTML='<span class="text-base-content/40">Loading\u2026</span>',x("GET",`/api/projects/${s}/git/log?root=${encodeURIComponent(t)}`).then(a=>{n.innerHTML=a.graph?Cf(a.graph):'<span class="text-base-content/40">No commits</span>'}).catch(a=>{n.innerHTML=`<span class="text-error">${p(a.message)}</span>`})}As();W();F();var Me=null,G=null,Co=null,ta=!1,Mo=null,ud=null,Zs=0,ea=null,gi=!1,ld=!1,cd={"ctrl-c":"",escape:"\x1B",tab:" ",up:"\x1B[A",down:"\x1B[B",left:"\x1B[D",right:"\x1B[C"};function bi(e){Me&&Me.readyState===WebSocket.OPEN&&Me.send(JSON.stringify({type:"input",data:e}))}function Df(){return window.matchMedia("(max-width: 640px), (hover: none) and (pointer: coarse)").matches}function Ao(){if(Df()){document.getElementById("term-mobile-input")?.focus({preventScroll:!0});return}G?.focus();let e=document.querySelector("#terminal-container .xterm-helper-textarea");e&&(e.focus({preventScroll:!0}),requestAnimationFrame(()=>e.focus({preventScroll:!0})))}function pd(){if(G)return;let e=i("terminal-container");if(!e)return;if(typeof Terminal>"u"){setTimeout(pd,100);return}G=new Terminal({cursorBlink:!0,fontFamily:"Fira Code, Courier New, monospace",fontSize:12,theme:{background:"#0d1117",foreground:"#c9d1d9",cursor:"#58a6ff",black:"#0d1117",red:"#ff7b72",green:"#3fb950",yellow:"#d29922",blue:"#58a6ff",magenta:"#bc8cff",cyan:"#39c5cf",white:"#b1bac4",brightBlack:"#484f58",brightRed:"#ffa198",brightGreen:"#56d364",brightYellow:"#e3b341",brightBlue:"#79c0ff",brightMagenta:"#d8b9ff",brightCyan:"#56d4dd",brightWhite:"#ffffff"}}),typeof FitAddon<"u"&&(Co=new FitAddon.FitAddon,G.loadAddon(Co)),G.open(e),To(),G.onData(n=>{bi(n)}),e.addEventListener("pointerdown",()=>Ao(),{passive:!0}),e.addEventListener("touchend",()=>Ao(),{passive:!0}),window.addEventListener("resize",()=>{To(),jo()});let t=window.visualViewport;if(t){let n=0,s=()=>{n&&cancelAnimationFrame(n),n=requestAnimationFrame(()=>{n=0,Y.peek()==="shell"&&(To(),jo())})};t.addEventListener("resize",s),t.addEventListener("scroll",s)}}function To(){try{Co&&G&&Co.fit()}catch{}}function jo(){Me&&Me.readyState===WebSocket.OPEN&&G&&Me.send(JSON.stringify({type:"resize",cols:G.cols,rows:G.rows}))}function fd(){return c.machineId||j.peek()||null}function Do(e){ea&&(clearTimeout(ea),ea=null),gi=!0;let t=++Zs;if(Me){try{Me.close()}catch{}Me=null}ta=!1;let n=location.protocol==="https:"?"wss":"ws",s=G?G.cols:80,a=G?G.rows:24,o=new URLSearchParams;c.token&&o.set("token",c.token),e&&o.set("cwd",e),o.set("cols",String(s)),o.set("rows",String(a));let r=fd();M.peek()&&r&&o.set("machine",r),Mo=e||null,ud=r,Me=new WebSocket(`${n}://${location.host}/ws/shell?${o}`),Me.addEventListener("open",()=>{t===Zs&&(ta=!0,G?.write(`\x1B[32mConnected to interactive terminal\x1B[0m\r
|
|
1299
|
+
`),jo())}),Me.addEventListener("message",d=>{if(t!==Zs)return;let u;try{u=JSON.parse(d.data)}catch{return}u.type==="output"?G?.write(u.data):u.type==="exit"?G?.write(`\r
|
|
1300
|
+
\x1B[33m[process exited: ${u.code}]\x1B[0m\r
|
|
1301
|
+
`):u.type==="error"&&G?.write(`\r
|
|
1302
|
+
\x1B[31m[error: ${u.data||u.message||""}]\x1B[0m\r
|
|
1303
|
+
`)}),Me.addEventListener("close",()=>{t===Zs&&(ta=!1,G?.write(`\r
|
|
1304
|
+
\x1B[33m[disconnected]\x1B[0m\r
|
|
1305
|
+
`),!(!gi||Y.peek()!=="shell")&&(G?.write(`\x1B[33m[reconnecting\u2026]\x1B[0m\r
|
|
1306
|
+
`),ea=setTimeout(()=>{ea=null,Do(Mo)},1500)))}),Me.addEventListener("error",()=>{t===Zs&&G?.write(`\r
|
|
1307
|
+
\x1B[31m[WebSocket error]\x1B[0m\r
|
|
1308
|
+
`)})}function dd(){let e=E.peek()?.path,t=i("term-cwd");t&&(t.textContent=e||"~"),G||pd(),requestAnimationFrame(()=>{requestAnimationFrame(()=>{To();let n=fd();!ta||Mo!==(e||null)||ud!==n?(G?.clear(),Do(e)):jo()})})}function md(){ld||(ld=!0,document.getElementById("term-keyboard")?.addEventListener("click",Ao),document.getElementById("term-mobile-composer")?.addEventListener("submit",e=>{e.preventDefault();let t=document.getElementById("term-mobile-input");t&&(bi(`${t.value}\r`),t.value="",t.focus({preventScroll:!0}))}),document.getElementById("term-mobile-keys")?.addEventListener("pointerdown",e=>{e.target.closest("[data-term-key]")&&e.preventDefault()}),document.getElementById("term-mobile-keys")?.addEventListener("click",e=>{let t=e.target.closest("[data-term-key]")?.dataset.termKey;!t||!cd[t]||(bi(cd[t]),Ao())})),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&(Y.peek()!=="shell"||!gi||ta||Do(Mo))}),De(Y,e=>{e==="shell"&&dd()}),document.addEventListener("shell-tab-shown",()=>{Y.peek()==="shell"&&dd()}),document.getElementById("term-reconnect")?.addEventListener("click",()=>{G?.clear(),Do(E.peek()?.path)})}Ps();Na();var hd=null;function gd(){return window.matchMedia("(display-mode: standalone)").matches||window.navigator.standalone===!0||document.referrer.includes("android-app://")}function _f(e){let t=String(e||"").replace(/^\[|\]$/g,"");return!!(/^\d{1,3}(\.\d{1,3}){3}$/.test(t)||t.includes(":")&&/^[0-9a-f:]+$/i.test(t))}function Nf(){if(!("serviceWorker"in navigator)||!window.isSecureContext)return!1;let e=location.hostname;return e==="localhost"||e==="127.0.0.1"||e==="::1"?!0:_f(e)?!1:location.protocol==="https:"}function bd(){document.getElementById("btn-pwa-install")?.classList.remove("hidden")}function vd(){gd()&&document.documentElement.classList.add("pwa-standalone"),window.addEventListener("beforeinstallprompt",n=>{n.preventDefault(),hd=n,document.dispatchEvent(new CustomEvent("pwa-installable")),bd()}),window.addEventListener("appinstalled",()=>{hd=null,document.getElementById("btn-pwa-install")?.classList.add("hidden")});let e=/iPad|iPhone|iPod/.test(navigator.userAgent)||navigator.platform==="MacIntel"&&navigator.maxTouchPoints>1;if(!gd()&&(e||/Android/i.test(navigator.userAgent))&&requestAnimationFrame(()=>bd()),!Nf()){"serviceWorker"in navigator&&navigator.serviceWorker.getRegistrations().then(n=>n.forEach(s=>s.unregister())).catch(()=>{});return}let t=()=>{navigator.serviceWorker.register("/sw.js?v=33",{scope:"/"}).then(n=>{n.addEventListener("updatefound",()=>{let s=n.installing;s&&s.addEventListener("statechange",()=>{s.state==="installed"&&navigator.serviceWorker.controller&&console.info("[pwa] New version ready \u2014 reload to apply")})})}).catch(()=>{navigator.serviceWorker.getRegistrations().then(n=>n.forEach(s=>s.unregister())).catch(()=>{})})};document.readyState==="complete"?setTimeout(t,0):window.addEventListener("load",()=>setTimeout(t,0))}Dn();function vi(){let e=document.documentElement;e.classList.add("boot-ready"),e.classList.remove("boot-pending")}function _o(){document.documentElement.classList.remove("boot-restore")}var xi=yr(location.hash.slice(1)||"/"),xd=ri()||!!(c.token&&xi?.id);Dc({restoreSession:xd});qi();td();od();id();Cl();Tr();md();Yc();Vl();xl(nt,Tt);(async()=>{let e=Ni();if(c.token)try{let t=document.getElementById("auth-screen"),n=document.getElementById("app");if(t&&(t.style.display="none",t.classList.add("hidden")),n&&(n.style.display="flex",n.classList.remove("hidden")),xd){document.documentElement.classList.add("boot-restore");let a=document.getElementById("welcome"),o=document.getElementById("project-view");a&&(a.classList.add("hidden"),a.style.display="none"),o&&(o.classList.remove("hidden"),o.style.cssText="display:flex;flex-direction:column;flex:1;min-height:0;overflow:hidden")}let s=await e;await fo({hub:s,deepLink:xi}),xi?.id||(yl(),(location.hash||"").startsWith("#/session/")||_o()),requestAnimationFrame(()=>{requestAnimationFrame(vi)})}catch(t){console.error("[boot]",t),c.token=null,localStorage.removeItem("token"),_o(),await oi(),vi()}else{_o();try{await oi()}catch(t){console.error("[boot auth]",t)}finally{vi()}}})();document.addEventListener("router:home",()=>{_o()});vd();
|