opencode-glance 0.1.1 → 0.1.2

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.zh.md CHANGED
@@ -51,7 +51,7 @@ npm run dev # vite build --watch,改 GUI 代码自动重载
51
51
 
52
52
  ## 安装
53
53
 
54
- 从 npm 安装(发布后):
54
+ 从 npm 安装:
55
55
 
56
56
  ```jsonc
57
57
  // ~/.config/opencode/opencode.jsonc
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=require("solid-js/web"),G=require("@opencode/plugin/gui"),c=require("solid-js"),q={input:0,output:0,reasoning:0,cache:{read:0,write:0}};function B(t,e){return e?{input:t.input+e.input,output:t.output+e.output,reasoning:t.reasoning+e.reasoning,cache:{read:t.cache.read+e.cache.read,write:t.cache.write+e.cache.write}}:t}function E(t){return t.input+t.output+t.reasoning+t.cache.read+t.cache.write}function K(t){return t.reduce((e,n)=>e+(n.type==="user"?1:0),0)}function P(t,e="assistant"){return e==="tool"?t.reduce((n,r)=>r.type!=="assistant"?n:n+r.content.reduce((a,o)=>a+(o.type==="tool"?1:0),0),0):t.reduce((n,r)=>n+(r.type==="assistant"?1:0),0)}function R(t){let e=0,n=0;for(const r of t){if(r.type!=="assistant"||!r.tokens||typeof r.time.streamed!="number")continue;const a=r.tokens.output+r.tokens.reasoning;if(a<=0)continue;const o=(r.time.streamed-r.time.created)/1e3;o<=0||(e+=a,n+=o)}return n>0?Math.round(e/n):void 0}function F(t){for(let e=t.length-1;e>=0;e--){const n=t[e];if(!n||n.type!=="assistant"||!n.tokens||typeof n.time.streamed!="number")continue;const r=n.tokens.output+n.tokens.reasoning;if(r<=0)continue;const a=(n.time.streamed-n.time.created)/1e3;if(!(a<=0))return Math.round(r/a)}}function J(t){return t.findLast(e=>e.type==="assistant"&&e.time.completed===void 0)}const O=/[\u2e80-\u2eff\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/;function U(t){let e=0,n=0;for(const r of t)/\s/.test(r)||(O.test(r)?e++:n++);return Math.ceil(e+n/4)}function V(t){let e=0;for(const n of t.content){if(n.type==="text"||n.type==="reasoning"){e+=U(n.text);continue}if(n.type!=="tool")continue;const r=n.state.status==="streaming"?n.state.input:JSON.stringify(n.state.input);e+=Math.ceil((r?.length??0)/4)}return e}function H(t){return t.content.findLast(e=>e.type==="tool"&&e.state.status==="running")}function Z(t,e,n){if(!t)return;const r=Math.max(0,(n-t.time.created)/1e3),a=H(t);if(a){const o=a.time.ran??a.time.created;return{kind:"tool",name:a.name,elapsed:Math.max(0,(n-o)/1e3)}}return e>0?{kind:"streaming",elapsed:r,estimatedTokens:e,rate:r>=2?Math.round(e/r):void 0}:{kind:"waiting",elapsed:r}}function _(t){const e=Math.max(0,Math.floor(t));if(e<60)return`${e}s`;const n=Math.floor(e/60);if(n<60){const o=e%60;return o?`${n}m ${o}s`:`${n}m`}const r=Math.floor(n/60),a=n%60;return a?`${r}h ${a}m`:`${r}h`}function W(t){const e=t.input+t.cache.read+t.cache.write;if(!(e<=0))return Math.max(0,Math.min(100,Math.round(t.cache.read/e*100)))}function Y(t,e){const n=e?t.findIndex(o=>o.id===e):-1;if(e&&n===-1)return;const r=n===-1?t.length:n,a=t.findLastIndex((o,i)=>o.type==="compaction"&&o.status==="completed"&&i<r);return t.findLast((o,i)=>o.type==="assistant"&&o.tokens!==void 0&&i>a&&i<r)}function Q(t,e,n){const r=Y(t,n);if(!r)return;const a=E(r.tokens);if(a<=0)return;const o=e?.find(i=>i.providerID===r.model.providerID&&i.id===r.model.id);return{tokens:a,percent:o?.limit.context?Math.max(0,Math.min(100,Math.round(a/o.limit.context*100))):void 0}}function X(t){if(!Number.isFinite(t)||t<0)return String(t);const e=[[1e3,"K"],[1e6,"M"],[1e9,"B"],[1e12,"T"]];let n=-1;for(let a=0;a<e.length;a++)t>=e[a][0]&&(n=a);if(n===-1)return String(t);let r=Number((t/e[n][0]).toFixed(1));return r>=1e3&&n+1<e.length&&(n++,r=Number((t/e[n][0]).toFixed(1))),`${r}${e[n][1]}`}function ee(t){return t==="average"||t==="last"||t==="auto"?t:"auto"}function te(t){return t==="tool"?"tool":"assistant"}function ne(t,e=18){return t.length>e?`${t.slice(0,e-1)}…`:t}function ae(t){const e=t[t.length-1];return e?e.type==="assistant"?[t.length,e.id,"a",e.time.completed??0,e.time.streamed??0,e.tokens?.input??0,e.tokens?.output??0,e.tokens?.cache.read??0,e.tokens?.cache.write??0].join("|"):e.type==="compaction"?`${t.length}|${e.id}|c|${e.status}`:`${t.length}|${e.id}|${e.type}`:"0"}const re=t=>t!==void 0;function oe(t,e){const n=ae(e);return t&&t.key===n?t:{key:n,messages:e}}function ce(t,e){const[n,r]=c.createSignal(Date.now()),[a,o]=c.createSignal();c.createEffect(()=>{if(!t.running())return;r(Date.now());const s=setInterval(()=>r(Date.now()),1e3);c.onCleanup(()=>clearInterval(s))});const i=c.createMemo(s=>oe(s,t.messages())),$=c.createMemo(()=>t.family()),f=c.createMemo(()=>$().reduce((s,u)=>B(s,t.sessionTokens(u)),q)),h=c.createMemo(()=>Q(i().messages,t.models(),t.session()?.revert?.messageID)),m=c.createMemo(()=>K(i().messages)),k=c.createMemo(()=>P(i().messages,e.steps)),d=c.createMemo(()=>R(i().messages)),x=c.createMemo(()=>F(i().messages)),g=c.createMemo(()=>W(f())),p=c.createMemo(()=>t.running()),v=c.createMemo(()=>J(t.messages())),D=c.createMemo(()=>{const s=v();return s?V(s):0}),C=c.createMemo(()=>Z(v(),D(),n()));c.createEffect(()=>{const s=C();if(!p()||!s||s.kind!=="streaming"||s.rate===void 0){o(void 0);return}const u=s.rate;o(M=>M===void 0?u:Math.round(M*.65+u*.35))});const I=c.createMemo(()=>e.rate==="average"?d():x()??d()),w=c.createMemo(()=>`${e.plural("glance.turn",m())} ${e.plural("glance.step",k())}`),b=c.createMemo(()=>e.t("glance.tokens",{tokens:X(E(f()))})),T=c.createMemo(()=>{const s=g();return s===void 0?void 0:e.t("glance.cache",{percent:s})}),S=c.createMemo(()=>{const s=h()?.percent;return s===void 0?"—":e.t("glance.context",{percent:s})}),y=c.createMemo(()=>{const s=C();if(!p()){const j=I();return j===void 0?void 0:e.t("glance.rate",{rate:j})}if(!s)return e.t("glance.preparing");if(s.kind==="tool")return e.t("glance.tool",{name:ne(s.name),elapsed:_(s.elapsed)});if(s.kind==="waiting")return e.t("glance.waiting",{elapsed:_(s.elapsed)});const u=_(s.elapsed);if(e.rate==="auto"&&a()!==void 0)return e.t("glance.live",{rate:a(),elapsed:u});const M=e.rate==="average"?d():x()??d();return M===void 0?e.t("glance.streaming",{elapsed:u}):e.t("glance.rateElapsed",{rate:M,elapsed:u})}),N=c.createMemo(()=>y()?`${w()} · ${y()}`:w()),L=c.createMemo(()=>T()?`${b()} · ${T()}`:b()),z=c.createMemo(()=>`${m()}/${k()} · ${S()}`),A=c.createMemo(()=>(p()?[w(),y(),b(),S()]:[w(),y(),b(),T(),S()]).filter(re).join(" · "));return{totals:f,hit:g,usage:h,turns:m,steps:k,running:p,speed:I,activity:C,turnText:w,tokensText:b,cacheText:T,contextText:S,activityText:y,progressText:N,usageText:L,compactText:z,mediumText:A}}var se=l.template('<svg width=14 height=14 viewBox="0 0 16 16"fill=none stroke=currentColor stroke-width=1.4 stroke-linecap=round stroke-linejoin=round aria-hidden=true><circle cx=8 cy=8 r=6></circle><path d="M8 4.5V8l2.4 1.5">'),le=l.template('<svg width=14 height=14 viewBox="0 0 16 16"fill=none stroke=currentColor stroke-width=1.4 stroke-linecap=round stroke-linejoin=round aria-hidden=true><ellipse cx=8 cy=4.3 rx=5 ry=2.1></ellipse><path d="M3 4.3v7.4c0 1.2 2.2 2.1 5 2.1s5-.9 5-2.1V4.3"></path><path d="M3 8c0 1.2 2.2 2.1 5 2.1s5-.9 5-2.1">'),ie=l.template("<span class=glance-ring aria-hidden=true>"),ge=l.template('<div class=glance-root><div class=glance-bar role=status><span class=glance-group><span class=glance-icon></span><span class=glance-label></span></span><span class="glance-group center"><span class=glance-icon></span><span class=glance-label></span></span><span class="glance-group end"><span class=glance-label>');function ue(){return se()}function de(){return le()}function pe(t){const e=()=>Math.max(0,Math.min(100,t.percent??0))*3.6;return(()=>{var n=ie();return l.effect(r=>l.setStyleProperty(n,"background",`conic-gradient(currentColor ${e()}deg, var(--v2-background-bg-layer-04) 0)`)),n})()}function me(t){const e=t.ctx,n=()=>e.sessions.current(),r=ce({messages:()=>{const a=n();return a?.id?a.server.data.session.message.list(a.id):[]},session:()=>{const a=n();return a?.id?a.server.data.session.get(a.id):void 0},family:()=>{const a=n();if(!a?.id)return[];const o=a.server.data.session.family(a.id);return o.length?o:[a.id]},sessionTokens:a=>n()?.server.data.session.get(a)?.tokens,models:()=>{const a=n();return a?a.server.data.location.model.list(a.location):void 0},running:()=>{const a=n();return a?.id?a.server.data.session.status(a.id)==="running":!1}},{steps:te(e.options.steps),rate:ee(e.options.rate),t:(a,o)=>e.t(a,o),plural:(a,o)=>e.plural(a,o)});return l.createComponent(c.Show,{get when(){return n()},get children(){var a=ge(),o=a.firstChild,i=o.firstChild,$=i.firstChild,f=$.nextSibling,h=i.nextSibling,m=h.firstChild,k=m.nextSibling,d=h.nextSibling,x=d.firstChild;return l.insert($,l.createComponent(ue,{})),l.insert(f,()=>r.progressText()),l.insert(m,l.createComponent(de,{})),l.insert(k,()=>r.usageText()),l.insert(d,l.createComponent(pe,{get percent(){return r.usage()?.percent}}),x),l.insert(x,()=>r.contextText()),l.effect(g=>{var p=`${r.progressText()} · ${r.usageText()} · ${r.contextText()}`,v=`${E(r.totals()).toLocaleString()} tokens · ${(r.usage()?.tokens??0).toLocaleString()} in context`;return p!==g.e&&l.setAttribute(o,"aria-label",g.e=p),v!==g.t&&l.setAttribute(o,"title",g.t=v),g},{e:void 0,t:void 0}),a}})}const fe=`
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=require("solid-js/web"),G=require("@opencode/plugin/gui"),s=require("solid-js"),z={input:0,output:0,reasoning:0,cache:{read:0,write:0}};function A(t,e){return e?{input:t.input+e.input,output:t.output+e.output,reasoning:t.reasoning+e.reasoning,cache:{read:t.cache.read+e.cache.read,write:t.cache.write+e.cache.write}}:t}function _(t){return t.input+t.output+t.reasoning+t.cache.read+t.cache.write}function q(t){return t.reduce((e,n)=>e+(n.type==="user"?1:0),0)}function B(t,e="assistant"){return e==="tool"?t.reduce((n,r)=>r.type!=="assistant"?n:n+r.content.reduce((a,o)=>a+(o.type==="tool"?1:0),0),0):t.reduce((n,r)=>n+(r.type==="assistant"?1:0),0)}function K(t){let e=0,n=0;for(const r of t){if(r.type!=="assistant"||!r.tokens||typeof r.time.streamed!="number")continue;const a=r.tokens.output+r.tokens.reasoning;if(a<=0)continue;const o=(r.time.streamed-r.time.created)/1e3;o<=0||(e+=a,n+=o)}return n>0?Math.round(e/n):void 0}function P(t){for(let e=t.length-1;e>=0;e--){const n=t[e];if(!n||n.type!=="assistant"||!n.tokens||typeof n.time.streamed!="number")continue;const r=n.tokens.output+n.tokens.reasoning;if(r<=0)continue;const a=(n.time.streamed-n.time.created)/1e3;if(!(a<=0))return Math.round(r/a)}}function R(t){return t.findLast(e=>e.type==="assistant"&&e.time.completed===void 0)}const F=/[\u2e80-\u2eff\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/;function J(t){let e=0,n=0;for(const r of t)/\s/.test(r)||(F.test(r)?e++:n++);return Math.ceil(e+n/4)}function O(t){let e=0;for(const n of t.content){if(n.type==="text"||n.type==="reasoning"){e+=J(n.text);continue}if(n.type!=="tool")continue;const r=n.state.status==="streaming"?n.state.input:JSON.stringify(n.state.input);e+=Math.ceil((r?.length??0)/4)}return e}function U(t){return t.content.findLast(e=>e.type==="tool"&&e.state.status==="running")}function V(t,e,n){if(!t)return;const r=Math.max(0,(n-t.time.created)/1e3),a=U(t);if(a){const o=a.time.ran??a.time.created;return{kind:"tool",name:a.name,elapsed:Math.max(0,(n-o)/1e3)}}return e>0?{kind:"streaming",elapsed:r,estimatedTokens:e,rate:r>=2?Math.round(e/r):void 0}:{kind:"waiting",elapsed:r}}function C(t){const e=Math.max(0,Math.floor(t));if(e<60)return`${e}s`;const n=Math.floor(e/60);if(n<60){const o=e%60;return o?`${n}m ${o}s`:`${n}m`}const r=Math.floor(n/60),a=n%60;return a?`${r}h ${a}m`:`${r}h`}function H(t){const e=t.input+t.cache.read+t.cache.write;if(!(e<=0))return Math.max(0,Math.min(100,Math.round(t.cache.read/e*100)))}function Z(t,e){const n=e?t.findIndex(o=>o.id===e):-1;if(e&&n===-1)return;const r=n===-1?t.length:n,a=t.findLastIndex((o,i)=>o.type==="compaction"&&o.status==="completed"&&i<r);return t.findLast((o,i)=>o.type==="assistant"&&o.tokens!==void 0&&i>a&&i<r)}function W(t,e,n){const r=Z(t,n);if(!r)return;const a=_(r.tokens);if(a<=0)return;const o=e?.find(i=>i.providerID===r.model.providerID&&i.id===r.model.id);return{tokens:a,percent:o?.limit.context?Math.max(0,Math.min(100,Math.round(a/o.limit.context*100))):void 0}}function Y(t){if(!Number.isFinite(t)||t<0)return String(t);const e=[[1e3,"K"],[1e6,"M"],[1e9,"B"],[1e12,"T"]];let n=-1;for(let a=0;a<e.length;a++)t>=e[a][0]&&(n=a);if(n===-1)return String(t);let r=Number((t/e[n][0]).toFixed(1));return r>=1e3&&n+1<e.length&&(n++,r=Number((t/e[n][0]).toFixed(1))),`${r}${e[n][1]}`}function Q(t){return t==="average"||t==="last"||t==="auto"?t:"auto"}function X(t){return t==="tool"?"tool":"assistant"}function ee(t,e=18){return t.length>e?`${t.slice(0,e-1)}…`:t}function te(t){const e=t[t.length-1];return e?e.type==="assistant"?[t.length,e.id,"a",e.time.completed??0,e.time.streamed??0,e.tokens?.input??0,e.tokens?.output??0,e.tokens?.cache.read??0,e.tokens?.cache.write??0].join("|"):e.type==="compaction"?`${t.length}|${e.id}|c|${e.status}`:`${t.length}|${e.id}|${e.type}`:"0"}const ne=t=>t!==void 0;function ae(t,e){const n=te(e);return t&&t.key===n?t:{key:n,messages:e}}function re(t,e){const[n,r]=s.createSignal(Date.now()),[a,o]=s.createSignal();s.createEffect(()=>{if(!t.running())return;r(Date.now());const c=setInterval(()=>r(Date.now()),1e3);s.onCleanup(()=>clearInterval(c))});const i=s.createMemo(c=>ae(c,t.messages())),$=s.createMemo(()=>t.family()),h=s.createMemo(()=>$().reduce((c,u)=>A(c,t.sessionTokens(u)),z)),k=s.createMemo(()=>W(i().messages,t.models(),t.session()?.revert?.messageID)),m=s.createMemo(()=>q(i().messages)),x=s.createMemo(()=>B(i().messages,e.steps)),d=s.createMemo(()=>K(i().messages)),v=s.createMemo(()=>P(i().messages)),g=s.createMemo(()=>H(h())),p=s.createMemo(()=>t.running()),f=s.createMemo(()=>{const c=R(t.messages());return V(c,c?O(c):0,n())});s.createEffect(()=>{const c=f();if(!p()||!c||c.kind!=="streaming"||c.rate===void 0){o(void 0);return}const u=c.rate;o(M=>M===void 0?u:Math.round(M*.65+u*.35))});const E=s.createMemo(()=>e.rate==="average"?d():v()??d()),w=s.createMemo(()=>`${e.plural("glance.turn",m())} ${e.plural("glance.step",x())}`),b=s.createMemo(()=>e.t("glance.tokens",{tokens:Y(_(h()))})),T=s.createMemo(()=>{const c=g();return c===void 0?void 0:e.t("glance.cache",{percent:c})}),S=s.createMemo(()=>{const c=k()?.percent;return c===void 0?"—":e.t("glance.context",{percent:c})}),y=s.createMemo(()=>{const c=f();if(!p()){const I=E();return I===void 0?void 0:e.t("glance.rate",{rate:I})}if(!c)return e.t("glance.preparing");if(c.kind==="tool")return e.t("glance.tool",{name:ee(c.name),elapsed:C(c.elapsed)});if(c.kind==="waiting")return e.t("glance.waiting",{elapsed:C(c.elapsed)});const u=C(c.elapsed);if(e.rate==="auto"&&a()!==void 0)return e.t("glance.live",{rate:a(),elapsed:u});const M=e.rate==="average"?d():v()??d();return M===void 0?e.t("glance.streaming",{elapsed:u}):e.t("glance.rateElapsed",{rate:M,elapsed:u})}),j=s.createMemo(()=>y()?`${w()} · ${y()}`:w()),D=s.createMemo(()=>T()?`${b()} · ${T()}`:b()),N=s.createMemo(()=>`${m()}/${x()} · ${S()}`),L=s.createMemo(()=>(p()?[w(),y(),b(),S()]:[w(),y(),b(),T(),S()]).filter(ne).join(" · "));return{totals:h,hit:g,usage:k,turns:m,steps:x,running:p,speed:E,activity:f,turnText:w,tokensText:b,cacheText:T,contextText:S,activityText:y,progressText:j,usageText:D,compactText:N,mediumText:L}}var oe=l.template('<svg width=14 height=14 viewBox="0 0 16 16"fill=none stroke=currentColor stroke-width=1.4 stroke-linecap=round stroke-linejoin=round aria-hidden=true><circle cx=8 cy=8 r=6></circle><path d="M8 4.5V8l2.4 1.5">'),ce=l.template('<svg width=14 height=14 viewBox="0 0 16 16"fill=none stroke=currentColor stroke-width=1.4 stroke-linecap=round stroke-linejoin=round aria-hidden=true><ellipse cx=8 cy=4.3 rx=5 ry=2.1></ellipse><path d="M3 4.3v7.4c0 1.2 2.2 2.1 5 2.1s5-.9 5-2.1V4.3"></path><path d="M3 8c0 1.2 2.2 2.1 5 2.1s5-.9 5-2.1">'),se=l.template("<span class=glance-ring aria-hidden=true>"),le=l.template('<div class=glance-root><div class=glance-bar role=status><span class=glance-group><span class=glance-icon></span><span class=glance-label></span></span><span class="glance-group center"><span class=glance-icon></span><span class=glance-label></span></span><span class="glance-group end"><span class=glance-label>');function ie(){return oe()}function ge(){return ce()}function ue(t){const e=()=>Math.max(0,Math.min(100,t.percent??0))*3.6;return(()=>{var n=se();return l.effect(r=>l.setStyleProperty(n,"background",`conic-gradient(currentColor ${e()}deg, var(--v2-background-bg-layer-04) 0)`)),n})()}function de(t){const e=t.ctx,n=()=>e.sessions.current(),r=re({messages:()=>{const a=n();return a?.id?a.server.data.session.message.list(a.id):[]},session:()=>{const a=n();return a?.id?a.server.data.session.get(a.id):void 0},family:()=>{const a=n();if(!a?.id)return[];const o=a.server.data.session.family(a.id);return o.length?o:[a.id]},sessionTokens:a=>n()?.server.data.session.get(a)?.tokens,models:()=>{const a=n();return a?a.server.data.location.model.list(a.location):void 0},running:()=>{const a=n();return a?.id?a.server.data.session.status(a.id)==="running":!1}},{steps:X(e.options.steps),rate:Q(e.options.rate),t:(a,o)=>e.t(a,o),plural:(a,o)=>e.plural(a,o)});return l.createComponent(s.Show,{get when(){return n()},get children(){var a=le(),o=a.firstChild,i=o.firstChild,$=i.firstChild,h=$.nextSibling,k=i.nextSibling,m=k.firstChild,x=m.nextSibling,d=k.nextSibling,v=d.firstChild;return l.insert($,l.createComponent(ie,{})),l.insert(h,()=>r.progressText()),l.insert(m,l.createComponent(ge,{})),l.insert(x,()=>r.usageText()),l.insert(d,l.createComponent(ue,{get percent(){return r.usage()?.percent}}),v),l.insert(v,()=>r.contextText()),l.effect(g=>{var p=`${r.progressText()} · ${r.usageText()} · ${r.contextText()}`,f=`${_(r.totals()).toLocaleString()} tokens · ${(r.usage()?.tokens??0).toLocaleString()} in context`;return p!==g.e&&l.setAttribute(o,"aria-label",g.e=p),f!==g.t&&l.setAttribute(o,"title",g.t=f),g},{e:void 0,t:void 0}),a}})}const pe=`
2
2
  .glance-root {
3
3
  display: flex;
4
4
  justify-content: center;
@@ -96,4 +96,4 @@
96
96
  font-size: 12px;
97
97
  }
98
98
  }
99
- `,he={"glance.turn.one":"{{count}} turn","glance.turn.other":"{{count}} turns","glance.step.one":"{{count}} step","glance.step.other":"{{count}} steps","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"cache hit {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"waiting {{elapsed}}","glance.streaming":"generating {{elapsed}}","glance.preparing":"preparing","glance.command.toggle":"Glance: toggle status bar","glance.command.group":"Glance"},ke={"glance.turn.one":"{{count}} 轮","glance.turn.other":"{{count}} 轮","glance.step.one":"{{count}} 步","glance.step.other":"{{count}} 步","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"缓存命中 {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"等待响应 {{elapsed}}","glance.streaming":"生成中 {{elapsed}}","glance.preparing":"准备中","glance.command.toggle":"Glance:显示/隐藏状态条","glance.command.group":"Glance"},xe={"glance.turn.one":"{{count}} 輪","glance.turn.other":"{{count}} 輪","glance.step.one":"{{count}} 步","glance.step.other":"{{count}} 步","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"快取命中 {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"等待回應 {{elapsed}}","glance.streaming":"生成中 {{elapsed}}","glance.preparing":"準備中","glance.command.toggle":"Glance:顯示/隱藏狀態列","glance.command.group":"Glance"},ve={"glance.turn.one":"{{count}} ターン","glance.turn.other":"{{count}} ターン","glance.step.one":"{{count}} ステップ","glance.step.other":"{{count}} ステップ","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"キャッシュヒット {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"応答待ち {{elapsed}}","glance.streaming":"生成中 {{elapsed}}","glance.preparing":"準備中","glance.command.toggle":"Glance:ステータスバーを表示/非表示","glance.command.group":"Glance"},we={"glance.turn.one":"{{count}}턴","glance.turn.other":"{{count}}턴","glance.step.one":"{{count}}단계","glance.step.other":"{{count}}단계","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"캐시 적중 {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"응답 대기 {{elapsed}}","glance.streaming":"생성 중 {{elapsed}}","glance.preparing":"준비 중","glance.command.toggle":"Glance: 상태 표시줄 표시/숨기기","glance.command.group":"Glance"},be={"glance.turn.one":"{{count}} Zug","glance.turn.other":"{{count}} Züge","glance.step.one":"{{count}} Schritt","glance.step.other":"{{count}} Schritte","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"Cache-Treffer {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"warte auf Antwort {{elapsed}}","glance.streaming":"generiert {{elapsed}}","glance.preparing":"bereit","glance.command.toggle":"Glance: Statusleiste ein-/ausblenden","glance.command.group":"Glance"},ye={"glance.turn.one":"{{count}} tour","glance.turn.other":"{{count}} tours","glance.step.one":"{{count}} étape","glance.step.other":"{{count}} étapes","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"cache {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"en attente de réponse {{elapsed}}","glance.streaming":"génération {{elapsed}}","glance.preparing":"préparation","glance.command.toggle":"Glance : afficher/masquer la barre d’état","glance.command.group":"Glance"},Me={"glance.turn.one":"{{count}} turno","glance.turn.other":"{{count}} turnos","glance.step.one":"{{count}} paso","glance.step.other":"{{count}} pasos","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"aciertos de caché {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"esperando respuesta {{elapsed}}","glance.streaming":"generando {{elapsed}}","glance.preparing":"preparando","glance.command.toggle":"Glance: mostrar/ocultar la barra de estado","glance.command.group":"Glance"},$e={"glance.turn.one":"{{count}} turno","glance.turn.other":"{{count}} turnos","glance.step.one":"{{count}} passo","glance.step.other":"{{count}} passos","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"acertos de cache {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"aguardando resposta {{elapsed}}","glance.streaming":"gerando {{elapsed}}","glance.preparing":"preparando","glance.command.toggle":"Glance: mostrar/ocultar a barra de status","glance.command.group":"Glance"},Te={"glance.turn.one":"{{count}} turno","glance.turn.other":"{{count}} turni","glance.step.one":"{{count}} passo","glance.step.other":"{{count}} passi","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"hit cache {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"in attesa di risposta {{elapsed}}","glance.streaming":"generazione {{elapsed}}","glance.preparing":"preparazione","glance.command.toggle":"Glance: mostra/nascondi la barra di stato","glance.command.group":"Glance"},Se={en:he,zh:ke,zht:xe,ja:ve,ko:we,de:be,fr:ye,es:Me,pt:$e,it:Te},Ge=G.Plugin.define({i18n:Se,setup(t){const[e,n]=c.createSignal(t.options.show!==!1),r={at:"window.bottom",order:0,render:()=>l.createComponent(me,{ctx:t})};t.add(G.Style,fe),t.add(G.Slot,()=>e()?r:void 0),t.add(G.Command,()=>({id:"toggle",title:t.t("glance.command.toggle"),group:t.t("glance.command.group"),run:()=>{n(a=>!a)}}))}});exports.default=Ge;
99
+ `,me={"glance.turn.one":"{{count}} turn","glance.turn.other":"{{count}} turns","glance.step.one":"{{count}} step","glance.step.other":"{{count}} steps","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"cache hit {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"waiting {{elapsed}}","glance.streaming":"generating {{elapsed}}","glance.preparing":"preparing","glance.command.toggle":"Glance: toggle status bar","glance.command.group":"Glance"},fe={"glance.turn.one":"{{count}} 轮","glance.turn.other":"{{count}} 轮","glance.step.one":"{{count}} 步","glance.step.other":"{{count}} 步","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"缓存命中 {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"等待响应 {{elapsed}}","glance.streaming":"生成中 {{elapsed}}","glance.preparing":"准备中","glance.command.toggle":"Glance:显示/隐藏状态条","glance.command.group":"Glance"},he={"glance.turn.one":"{{count}} 輪","glance.turn.other":"{{count}} 輪","glance.step.one":"{{count}} 步","glance.step.other":"{{count}} 步","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"快取命中 {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"等待回應 {{elapsed}}","glance.streaming":"生成中 {{elapsed}}","glance.preparing":"準備中","glance.command.toggle":"Glance:顯示/隱藏狀態列","glance.command.group":"Glance"},ke={"glance.turn.one":"{{count}} ターン","glance.turn.other":"{{count}} ターン","glance.step.one":"{{count}} ステップ","glance.step.other":"{{count}} ステップ","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"キャッシュヒット {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"応答待ち {{elapsed}}","glance.streaming":"生成中 {{elapsed}}","glance.preparing":"準備中","glance.command.toggle":"Glance:ステータスバーを表示/非表示","glance.command.group":"Glance"},xe={"glance.turn.one":"{{count}}턴","glance.turn.other":"{{count}}턴","glance.step.one":"{{count}}단계","glance.step.other":"{{count}}단계","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"캐시 적중 {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"응답 대기 {{elapsed}}","glance.streaming":"생성 중 {{elapsed}}","glance.preparing":"준비 중","glance.command.toggle":"Glance: 상태 표시줄 표시/숨기기","glance.command.group":"Glance"},ve={"glance.turn.one":"{{count}} Zug","glance.turn.other":"{{count}} Züge","glance.step.one":"{{count}} Schritt","glance.step.other":"{{count}} Schritte","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"Cache-Treffer {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"warte auf Antwort {{elapsed}}","glance.streaming":"generiert {{elapsed}}","glance.preparing":"bereit","glance.command.toggle":"Glance: Statusleiste ein-/ausblenden","glance.command.group":"Glance"},we={"glance.turn.one":"{{count}} tour","glance.turn.other":"{{count}} tours","glance.step.one":"{{count}} étape","glance.step.other":"{{count}} étapes","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"cache {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"en attente de réponse {{elapsed}}","glance.streaming":"génération {{elapsed}}","glance.preparing":"préparation","glance.command.toggle":"Glance : afficher/masquer la barre d’état","glance.command.group":"Glance"},be={"glance.turn.one":"{{count}} turno","glance.turn.other":"{{count}} turnos","glance.step.one":"{{count}} paso","glance.step.other":"{{count}} pasos","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"aciertos de caché {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"esperando respuesta {{elapsed}}","glance.streaming":"generando {{elapsed}}","glance.preparing":"preparando","glance.command.toggle":"Glance: mostrar/ocultar la barra de estado","glance.command.group":"Glance"},ye={"glance.turn.one":"{{count}} turno","glance.turn.other":"{{count}} turnos","glance.step.one":"{{count}} passo","glance.step.other":"{{count}} passos","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"acertos de cache {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"aguardando resposta {{elapsed}}","glance.streaming":"gerando {{elapsed}}","glance.preparing":"preparando","glance.command.toggle":"Glance: mostrar/ocultar a barra de status","glance.command.group":"Glance"},Me={"glance.turn.one":"{{count}} turno","glance.turn.other":"{{count}} turni","glance.step.one":"{{count}} passo","glance.step.other":"{{count}} passi","glance.rate":"{{rate}} tok/s","glance.rateElapsed":"{{rate}} tok/s · {{elapsed}}","glance.live":"~{{rate}} tok/s · {{elapsed}}","glance.tokens":"{{tokens}} tok","glance.cache":"hit cache {{percent}}%","glance.context":"{{percent}}%","glance.tool":"{{name}} {{elapsed}}","glance.waiting":"in attesa di risposta {{elapsed}}","glance.streaming":"generazione {{elapsed}}","glance.preparing":"preparazione","glance.command.toggle":"Glance: mostra/nascondi la barra di stato","glance.command.group":"Glance"},$e={en:me,zh:fe,zht:he,ja:ke,ko:xe,de:ve,fr:we,es:be,pt:ye,it:Me},Te=G.Plugin.define({i18n:$e,setup(t){const[e,n]=s.createSignal(t.options.show!==!1),r={at:"window.bottom",order:0,render:()=>l.createComponent(de,{ctx:t})};t.add(G.Style,pe),t.add(G.Slot,()=>e()?r:void 0),t.add(G.Command,()=>({id:"toggle",title:t.t("glance.command.toggle"),group:t.t("glance.command.group"),run:()=>{n(a=>!a)}}))}});exports.default=Te;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "opencode-glance",
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "description": "Glanceable session stats for OpenCode: turns, steps, throughput, tokens, cache hit, context usage, and live tool activity.",
6
6
  "type": "module",
7
7
  "license": "MIT",
@@ -141,13 +141,13 @@ export function createGlance(source: GlanceSource, options: GlanceOptions) {
141
141
  const hit = createMemo(() => cacheHit(totals()))
142
142
  const running = createMemo(() => source.running())
143
143
 
144
- // The active step must be read live: its content changes on every token.
145
- const active = createMemo(() => activeStep(source.messages()))
146
- const estimated = createMemo(() => {
147
- const step = active()
148
- return step ? estimateStepTokens(step) : 0
144
+ // The active step must be read live: its content changes on every token. Reading the step and its
145
+ // content in one computation matters because the step object keeps its identity while it streams, so a
146
+ // memo that only depended on the step would stop tracking the text after the first delta.
147
+ const activity = createMemo(() => {
148
+ const step = activeStep(source.messages())
149
+ return stepActivity(step, step ? estimateStepTokens(step) : 0, now())
149
150
  })
150
- const activity = createMemo(() => stepActivity(active(), estimated(), now()))
151
151
 
152
152
  // Smooth the character-based estimate so the number does not jump on every delta.
153
153
  createEffect(() => {