opencode-session-turns 0.1.4 → 0.1.5
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/dist/gui-experimental.cjs +3 -3
- package/package.json +1 -1
- package/src/gui.tsx +5 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const
|
|
2
|
-
`).map(b=>b.trim()).find(b=>b.length>0);if(
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const o=require("solid-js/web"),L=require("@opencode/plugin/gui"),i=require("solid-js");var Lt=o.template("<div class=sr-status>"),It=o.template('<span class="sr-title sr-progress">跳转中'),Mt=o.template("<div class=sr-rail><div class=sr-head><button type=button class=sr-close>×</button></div><div class=sr-list>"),Pt=o.template("<span class=sr-title>会话轮次"),jt=o.template("<div class=sr-note>"),Dt=o.template("<button type=button class=sr-turn><span class=sr-text><span class=sr-num>#</span><span class=sr-time></span></span><span class=sr-dash>");const G="v12",Y="message-",gt="session-turns:diag",Z="session-turns:open",qt=40,Rt=200,Ot=50,Jt=120,V=45e3,Nt=4e3,zt=300,Bt=800;let xt=0,X="",Q="";const mt=a=>{const n=String(a?.text??"").split(`
|
|
2
|
+
`).map(b=>b.trim()).find(b=>b.length>0);if(n)return n;const u=a?.files?.length??0;return u>0?`[附件 ×${u}]`:"(空消息)"},bt=a=>String(a).padStart(2,"0"),Ft=a=>{const n=new Date(a??0);return`${bt(n.getHours())}:${bt(n.getMinutes())}`},wt=a=>new Promise(n=>setTimeout(n,a)),vt=()=>document.querySelector('[data-slot="session-timeline-scroll"] > .scroll-view__viewport')??document.querySelector('[data-slot="session-timeline-scroll"] [data-scrollable]')??(()=>{let n=document.querySelector("[data-message-id]")?.parentElement;for(;n;){const u=getComputedStyle(n);if(/(auto|scroll)/.test(u.overflowY)&&n.scrollHeight>n.clientHeight+1)return n;n=n.parentElement}})(),E=a=>document.getElementById(`${Y}${a}`)??[...document.querySelectorAll("[data-message-id]")].find(n=>n.getAttribute("data-message-id")===a),W=a=>{const n=vt(),u=[...document.querySelectorAll("[data-message-id]")],b=u[0]?.getAttribute("data-message-id")??"",O=Q?` · 目标 ${E(Q)?"在":"不在"} DOM`:"",I=b?` · 行ID ${b.slice(0,20)}`:"";let _="(空)";try{_=a.router.path()||"(空)"}catch{}return`轮次 ${xt} · 容器 ${n?"OK":"缺失"} · DOM ${u.length} 行${O}${I} · 路由 ${_} · hash ${window.location.hash||"(空)"}${X?` · ${X}`:""}`},K=(a,n)=>{n.scrollIntoView({block:"start"});const u=a.querySelector("[data-session-title]"),b=u instanceof HTMLElement?u.offsetHeight:0;b&&(a.scrollTop-=b+12)},Ht=a=>{let n="";try{n=a.router.path()||""}catch{}return n.startsWith("/")?n:""},Ut=a=>{const n=document.createElement("a");n.setAttribute("href",a),n.setAttribute("replace",""),n.setAttribute("noscroll",""),n.style.display="none",document.body.appendChild(n);try{n.dispatchEvent(new MouseEvent("click",{bubbles:!0,cancelable:!0,button:0,view:window}))}finally{n.remove()}},Gt=`
|
|
3
3
|
.sr-rail {
|
|
4
4
|
position: fixed;
|
|
5
5
|
top: 50%;
|
|
@@ -215,4 +215,4 @@
|
|
|
215
215
|
white-space: pre-wrap;
|
|
216
216
|
max-width: min(720px, 90vw);
|
|
217
217
|
}
|
|
218
|
-
`;function Vt(
|
|
218
|
+
`;function Vt(a){const n=L.usePlugin(),[u,b]=i.createSignal([]),[O,I]=i.createSignal(""),[_,$]=i.createSignal(!1),[yt,kt]=i.createSignal(""),[tt,et]=i.createSignal(""),[v,M]=i.createSignal(!1),[rt,T]=i.createSignal(0),[nt,P]=i.createSignal(""),y=new Map;let J=0,j=!1,D=!1,N="",A;const k=()=>a.session()?.id,z=()=>{const t=[...y.values()].sort((r,l)=>r.created-l.created),e=i.untrack(u);e.length===t.length&&e.every((r,l)=>r===t[l])||(b(t),xt=t.length)},st=t=>{const e=y.get(t.id);e&&e.created===t.time&&e.text===t.text||y.set(t.id,{id:t.id,created:t.time,text:t.text})},St=async(t,e,r)=>{const l=r?{sessionID:t,type:"user",limit:e,cursor:r}:{sessionID:t,type:"user",limit:e,order:"desc"};return await n.client.message.list(l)},B=async(t,e)=>{const r=++J;j=!0;let l="";try{let s;const c=e==="full"?qt:1,d=e==="full"?Rt:Ot;let p=e!=="full";for(let h=0;h<c;h++){let x;try{x=await St(t,d,s)}catch(m){l=String(m?.message??m);break}if(r!==J)return;p||(y.clear(),p=!0);let f=0;for(const m of x?.data??[])y.has(m.id)||(st({id:m.id,time:m.time?.created??0,text:mt(m)}),f++);z();const g=x?.cursor?.next;if(!g||f===0)break;s=g}}finally{j=!1,N=t,X=l,kt(y.size===0?l||"暂无用户消息":""),D&&(D=!1,ot())}},ot=()=>{A||(A=setTimeout(()=>{A=void 0;const t=i.untrack(k);t&&B(t,"light")},300))},at=t=>{if(!(!t||t!==i.untrack(k))){if(j){D=!0;return}ot()}},$t=t=>{const e=t?.type;if(e==="message.updated"){const r=t?.data??{},l=r.info;l?.role==="user"&&l?.id&&(st({id:l.id,time:l.time?.created??0,text:mt(l)}),z()),at(r.sessionID)}else if(e==="message.removed"){const r=t?.data??{};r.messageID&&y.delete(r.messageID)&&z(),at(r.sessionID)}else if(e==="location.shutdown"){const r=i.untrack(k);r&&N===r&&B(r,"full")}};i.onMount(()=>{let t=!1,e=0,r;(async()=>{for(;!t;){const c=n.client.event.subscribe()[Symbol.asyncIterator]();try{for(;!t;){const d=await c.next();if(d.done)break;e=0,$t(d.value)}}catch{}try{await c.return?.()}catch{}if(t)break;e++,await wt(Math.min(2e3*e,15e3))}})(),i.onCleanup(()=>{t=!0,clearTimeout(r),A&&clearTimeout(A)})}),i.createEffect(()=>{const t=k();t&&i.untrack(()=>{N!==t&&(J++,j=!1,D=!1,y.clear(),b([]),I(""),H="",B(t,"full"))})});let q;const C=()=>(q?.isConnected||(q=vt()),q),Et=()=>{const t=C();if(!t)return;const e=t.querySelectorAll("[data-message-id]");if(e.length===0)return;const r=t.getBoundingClientRect().top+40;for(const l of e)if(l.getBoundingClientRect().bottom>=r){const s=l.getAttribute("data-message-id");s&&I(s);break}};let F=!1;const it=()=>{F||(F=!0,requestAnimationFrame(()=>{F=!1,Et()}))};i.onMount(()=>{const t=()=>it();document.addEventListener("scroll",t,!0);const e=setInterval(it,1500);i.onCleanup(()=>{document.removeEventListener("scroll",t,!0),clearInterval(e)})});let lt=0;const w=(t,e=2600)=>{const r=++lt;et(t),setTimeout(()=>{r===lt&&et("")},e)};i.onMount(()=>{const t=r=>{if(r.key==="Escape"){if(i.untrack(v)){ft(),r.stopPropagation();return}i.untrack(_)&&($(!1),r.stopPropagation())}},e=r=>{if(!i.untrack(_))return;(r.composedPath?.()??[]).some(c=>c instanceof Element&&c.closest?.(".sr-rail"))||$(!1)};window.addEventListener("keydown",t,!0),document.addEventListener("pointerdown",e,!0),i.onCleanup(()=>{window.removeEventListener("keydown",t,!0),document.removeEventListener("pointerdown",e,!0)})}),i.onMount(()=>{const t=()=>w(`${G} · ${W(n)}`),e=()=>$(r=>!r);window.addEventListener(gt,t),window.addEventListener(Z,e),i.onCleanup(()=>{window.removeEventListener(gt,t),window.removeEventListener(Z,e)}),w(`会话轮次 ${G} 已加载`)});let H="",S=0,ct=0,dt="";const U=t=>{try{const e=t.querySelector('[data-slot="user-message-text"]')??t.querySelector('[data-slot="user-message-body"]')??t;e.classList.remove("sr-flash-ring"),e.offsetWidth,e.classList.add("sr-flash-ring"),setTimeout(()=>e.classList.remove("sr-flash-ring"),1900)}catch{}},_t=()=>{for(const t of u())if(E(t.id))return t},ut=(t,e)=>{Ut(`${t}#${Y}${e}`),H=e},pt=()=>{const e=C()?.querySelectorAll("[data-message-id]")??[];if(e.length===0)return"0";const r=e[0].getAttribute("data-message-id")??"",l=e[e.length-1].getAttribute("data-message-id")??"";return`${e.length}:${r}:${l}`},Tt=(t,e,r)=>new Promise(l=>{let s=!1,c,d,p;const h=Date.now(),x=pt(),f=R=>{if(!s){s=!0;try{c?.disconnect()}catch{}clearInterval(d),clearTimeout(p),l(R??null)}},g=R=>{if(e!==S)return f(null);const ht=R?E(t):document.getElementById(`${Y}${t}`);if(ht)return f(ht);R&&Date.now()-h>zt&&pt()!==x&&f(null)},m=E(t);if(m)return f(m);c=new MutationObserver(()=>g(!1)),c.observe(document.documentElement,{childList:!0,subtree:!0}),d=setInterval(()=>g(!0),120),p=setTimeout(()=>f(E(t)),Math.max(400,r))}),ft=()=>{S++,M(!1),T(0),P(""),w("已取消跳转")},At=async t=>{const e=++S;M(!1),T(0),P(""),Q=t.id;const r=Date.now();if(t.id===dt&&r-ct<Bt){const p=E(t.id),h=C();if(p&&h){K(h,p),U(p);return}}ct=r,dt=t.id;const l=C(),s=E(t.id);if(s&&l){K(l,s),U(s),w("已定位");return}const c=Ht(n);if(!c){w(`无法读取当前路由,无法定位 · ${W(n)}`);return}const d=k();M(!0),P(t.id),T(0),$(!0),w("正在定位…",V);try{const p=Date.now()+V;for(let h=0;h<Jt&&Date.now()<p;h++){if(e!==S||k()!==d)return;if(T(h+1),w(`跳转中 · 第 ${h+1} 页`,V),H===t.id){const g=_t()??u()[0];g&&(ut(c,g.id),await wt(120))}if(e!==S||k()!==d)return;ut(c,t.id);const x=Math.min(Nt,p-Date.now()),f=await Tt(t.id,e,x);if(e!==S||k()!==d)return;if(f){const g=C()??l;g&&K(g,f),U(f),w("已定位");return}}e===S&&w(`未能定位 · ${W(n)}`)}finally{e===S&&(M(!1),T(0),P(""))}};i.createEffect(()=>{v()&&nt()&&requestAnimationFrame(()=>{try{document.querySelector('.sr-list .sr-turn[data-busy="true"]')?.scrollIntoView({block:"nearest"})}catch{}})});const Ct=[o.createComponent(i.Show,{get when(){return tt()},get children(){var t=Lt();return o.insert(t,tt),t}}),(()=>{var t=Mt(),e=t.firstChild,r=e.firstChild,l=e.nextSibling;return t.addEventListener("mouseleave",()=>{v()||$(!1)}),t.addEventListener("mouseenter",()=>$(!0)),o.insert(e,o.createComponent(i.Show,{get when(){return v()},get fallback(){return(()=>{var s=Pt();return s.firstChild,o.insert(s,(()=>{var c=o.memo(()=>u().length>0);return()=>c()?` · ${u().length}`:""})(),null),s})()},get children(){var s=It();return s.firstChild,o.insert(s,(()=>{var c=o.memo(()=>rt()>0);return()=>c()?` · 第 ${rt()} 页`:""})(),null),s}}),r),r.$$click=()=>{v()?ft():$(!1)},o.insert(l,o.createComponent(i.Show,{get when(){return u().length>0},get fallback(){return(()=>{var s=jt();return o.insert(s,()=>yt()||`… ${G}`),s})()},get children(){return o.createComponent(i.For,{get each(){return u()},children:(s,c)=>(()=>{var d=Dt(),p=d.firstChild,h=p.firstChild;h.firstChild;var x=h.nextSibling;return d.$$click=()=>{At(s)},o.insert(h,()=>c()+1,null),o.insert(x,()=>Ft(s.created)),o.insert(p,()=>s.text,null),o.effect(f=>{var g=O()===s.id?"true":"false",m=v()&&nt()===s.id?"true":"false";return g!==f.e&&o.setAttribute(d,"data-active",f.e=g),m!==f.t&&o.setAttribute(d,"data-busy",f.t=m),f},{e:void 0,t:void 0}),d})()})}})),o.effect(s=>{var c=_()?"true":"false",d=v()?"true":"false",p=v()?"取消跳转 (Esc)":"关闭 (Esc)";return c!==s.e&&o.setAttribute(t,"data-open",s.e=c),d!==s.t&&o.setAttribute(t,"data-jumping",s.t=d),p!==s.a&&o.setAttribute(r,"title",s.a=p),s},{e:void 0,t:void 0,a:void 0}),t})()];return o.createComponent(o.Portal,{get mount(){return document.body},children:Ct})}const Wt=L.Plugin.define({i18n:{en:{"command.jump":"Session turns: show / jump","command.jump.description":"Reveal the turn rail; click a turn to jump to that message"}},setup(a){a.add(L.Style,Gt),a.add(L.Slot,{at:"window.bottom",render:()=>o.createComponent(i.Show,{get when(){return a.sessions.current()},get children(){return o.createComponent(Vt,{session:()=>a.sessions.current()})}})}),a.add(L.Command,()=>({id:"jump",title:a.t("command.jump"),description:a.t("command.jump.description"),group:a.t("command.jump"),section:"navigation",bind:"mod+alt+r",slash:{name:"turns"},run:()=>{window.dispatchEvent(new Event(Z))}}))}});o.delegateEvents(["click"]);exports.default=Wt;
|
package/package.json
CHANGED
package/src/gui.tsx
CHANGED
|
@@ -745,11 +745,11 @@ function Rail(props) {
|
|
|
745
745
|
}
|
|
746
746
|
const check = (full) => {
|
|
747
747
|
if (token !== jumpToken) return finish(null)
|
|
748
|
-
|
|
748
|
+
// Observer callbacks use the cheap id lookup; only the poll pays for the
|
|
749
|
+
// data-attribute fallback (a full scan) and the row fingerprint.
|
|
750
|
+
const row = full ? findRow(messageID) : document.getElementById(`${HASH_PREFIX}${messageID}`)
|
|
749
751
|
if (row) return finish(row)
|
|
750
752
|
// Let the click settle before trusting a DOM change as "a page arrived".
|
|
751
|
-
// Only the poll evaluates the row fingerprint: streaming output fires
|
|
752
|
-
// the observer constantly and a full query on every mutation is wasted.
|
|
753
753
|
if (full && Date.now() - started > JUMP_SETTLE_MS && rowSignature() !== baseline) finish(null)
|
|
754
754
|
}
|
|
755
755
|
const existing = findRow(messageID)
|
|
@@ -839,12 +839,12 @@ function Rail(props) {
|
|
|
839
839
|
await sleep(120)
|
|
840
840
|
}
|
|
841
841
|
}
|
|
842
|
-
if (token !== jumpToken) return
|
|
842
|
+
if (token !== jumpToken || sessionID() !== sessionAtJump) return
|
|
843
843
|
navTo(path, turn.id)
|
|
844
844
|
|
|
845
845
|
const remaining = Math.min(JUMP_ROW_TIMEOUT_MS, deadline - Date.now())
|
|
846
846
|
const landed = await waitForRow(turn.id, token, remaining)
|
|
847
|
-
if (token !== jumpToken) return
|
|
847
|
+
if (token !== jumpToken || sessionID() !== sessionAtJump) return
|
|
848
848
|
if (landed) {
|
|
849
849
|
const live = scroller() ?? sc
|
|
850
850
|
if (live) scrollToRow(live, landed)
|