codexmeter 1.0.25 → 1.0.27

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.
@@ -0,0 +1,3 @@
1
+ import{c as e,p as t}from"./index-Bxd44dxc.js";import{At as n,Bn as r,Cn as i,Ct as a,Fn as o,Ft as s,H as c,Ht as l,In as u,Jn as d,Kn as f,Ln as p,Mn as m,Nn as h,P as g,Pn as _,Q as v,Qn as y,Rn as b,U as x,Un as S,Ut as C,Vn as w,Vt as T,Wn as E,Yn as ee,Zt as te,_t as ne,at as D,ct as O,d as k,dt as A,er as j,et as M,ft as re,jn as ie,mt as ae,ot as oe,pt as se,rt as N,st as ce,tn as le,tr as P,tt as ue,wn as de,yn as fe,yt as pe,zn as me}from"./animationsDefault-C_urdfl6.js";P();function he(e,t){var n=A(t.get(`padding`)),r=t.getItemStyle([`color`,`opacity`]);return r.fill=t.get(`backgroundColor`),new C({shape:{x:e.x-n[3],y:e.y-n[0],width:e.width+n[1]+n[3],height:e.height+n[0]+n[2],r:t.get(`borderRadius`)},style:r,silent:!0,z2:-1})}var ge=function(e,t){if(t===`all`)return{type:`all`,title:e.getLocaleModel().get([`legend`,`selector`,`all`])};if(t===`inverse`)return{type:`inverse`,title:e.getLocaleModel().get([`legend`,`selector`,`inverse`])}},F=function(e){j(t,e);function t(){var n=e!==null&&e.apply(this,arguments)||this;return n.type=t.type,n.layoutMode={type:`box`,ignoreSize:!0},n}return t.prototype.init=function(e,t,n){this.mergeDefaultAndTheme(e,n),e.selected=e.selected||{},this._updateSelector(e)},t.prototype.mergeOption=function(t,n){e.prototype.mergeOption.call(this,t,n),this._updateSelector(t)},t.prototype._updateSelector=function(e){var t=e.selector,n=this.ecModel;t===!0&&(t=e.selector=[`all`,`inverse`]),w(t)&&u(t,function(e,r){f(e)&&(e={type:e}),t[r]=ee(e,ge(n,e.type))})},t.prototype.optionUpdated=function(){this._updateData(this.ecModel);var e=this._data;if(e[0]&&this.get(`selectedMode`)===`single`){for(var t=!1,n=0;n<e.length;n++){var r=e[n].get(`name`);if(this.isSelected(r)){this.select(r),t=!0;break}}!t&&this.select(e[0].get(`name`))}},t.prototype._updateData=function(e){var t=[],n=[];e.eachRawSeries(function(r){var i=r.name;n.push(i);var a;if(r.legendVisualProvider){var o=r.legendVisualProvider.getAllNames();e.isSeriesFiltered(r)||(n=n.concat(o)),o.length?t=t.concat(o):a=!0}else a=!0;a&&le(r)&&t.push(r.name)}),this._availableNames=n;var r=this.get(`data`)||t,i=h(),a=d(r,function(e){return(f(e)||E(e))&&(e={name:e}),i.get(e.name)?null:(i.set(e.name,!0),new se(e,this,this.ecModel))},this);this._data=b(a,function(e){return!!e})},t.prototype.getData=function(){return this._data},t.prototype.select=function(e){var t=this.option.selected;if(this.get(`selectedMode`)===`single`){var n=this._data;u(n,function(e){t[e.get(`name`)]=!1})}t[e]=!0},t.prototype.unSelect=function(e){this.get(`selectedMode`)!==`single`&&(this.option.selected[e]=!1)},t.prototype.toggleSelected=function(e){var t=this.option.selected;t.hasOwnProperty(e)||(t[e]=!0),this[t[e]?`unSelect`:`select`](e)},t.prototype.allSelect=function(){var e=this._data,t=this.option.selected;u(e,function(e){t[e.get(`name`,!0)]=!0})},t.prototype.inverseSelect=function(){var e=this._data,t=this.option.selected;u(e,function(e){var n=e.get(`name`,!0);t.hasOwnProperty(n)||(t[n]=!0),t[n]=!t[n]})},t.prototype.isSelected=function(e){var t=this.option.selected;return!(t.hasOwnProperty(e)&&!t[e])&&r(this._availableNames,e)>=0},t.prototype.getOrient=function(){return this.get(`orient`)===`vertical`?{index:1,name:`vertical`}:{index:0,name:`horizontal`}},t.type=`legend.plain`,t.dependencies=[`series`],t.defaultOption={z:4,show:!0,orient:`horizontal`,left:`center`,bottom:M.size.m,align:`auto`,backgroundColor:M.color.transparent,borderColor:M.color.border,borderRadius:0,borderWidth:0,padding:5,itemGap:8,itemWidth:25,itemHeight:14,symbolRotate:`inherit`,symbolKeepAspect:!0,inactiveColor:M.color.disabled,inactiveBorderColor:M.color.disabled,inactiveBorderWidth:`auto`,itemStyle:{color:`inherit`,opacity:`inherit`,borderColor:`inherit`,borderWidth:`auto`,borderCap:`inherit`,borderJoin:`inherit`,borderDashOffset:`inherit`,borderMiterLimit:`inherit`},lineStyle:{width:`auto`,color:`inherit`,inactiveColor:M.color.disabled,inactiveWidth:2,opacity:`inherit`,type:`inherit`,cap:`inherit`,join:`inherit`,dashOffset:`inherit`,miterLimit:`inherit`},textStyle:{color:M.color.secondary},selectedMode:!0,selector:!1,selectorLabel:{show:!0,borderRadius:10,padding:[3,5,3,5],fontSize:12,fontFamily:`sans-serif`,color:M.color.tertiary,borderWidth:1,borderColor:M.color.border},emphasis:{selectorLabel:{show:!0,color:M.color.quaternary}},selectorPosition:`auto`,selectorItemGap:7,selectorButtonGap:10,tooltip:{show:!1},triggerEvent:!1},t}(ue);P();var I=_,L=u,R=fe,_e=function(e){j(t,e);function t(){var n=e!==null&&e.apply(this,arguments)||this;return n.type=t.type,n.newlineDisabled=!1,n}return t.prototype.init=function(){this.group.add(this._contentGroup=new R),this.group.add(this._selectorGroup=new R),this._isFirstRender=!0},t.prototype.getContentGroup=function(){return this._contentGroup},t.prototype.getSelectorGroup=function(){return this._selectorGroup},t.prototype.render=function(e,t,n){var r=this._isFirstRender;if(this._isFirstRender=!1,this.resetInner(),e.get(`show`,!0)){var i=e.get(`align`),a=e.get(`orient`);(!i||i===`auto`)&&(i=e.get(`left`)===`right`&&a===`vertical`?`right`:`left`);var s=e.get(`selector`,!0),c=e.get(`selectorPosition`,!0);s&&(!c||c===`auto`)&&(c=a===`horizontal`?`end`:`start`),this.renderInner(i,e,t,n,s,a,c);var l=D(e,n).refContainer,u=e.getBoxLayoutParams(),d=e.get(`padding`),f=ce(u,l,d),p=this.layoutInner(e,i,f,r,s,c),m=ce(o({width:p.width,height:p.height},u),l,d);this.group.x=m.x-p.x,this.group.y=m.y-p.y,this.group.markRedraw(),this.group.add(this._backgroundEl=he(p,e))}},t.prototype.resetInner=function(){this.getContentGroup().removeAll(),this._backgroundEl&&this.group.remove(this._backgroundEl),this.getSelectorGroup().removeAll()},t.prototype.renderInner=function(e,t,n,r,a,o,s){var c=this.getContentGroup(),l=h(),u=t.get(`selectedMode`),d=t.get(`triggerEvent`),f=[];n.eachRawSeries(function(e){!e.get(`legendHoverLink`)&&f.push(e.id)}),L(t.getData(),function(a,o){var s=this,m=a.get(`name`);if(!this.newlineDisabled&&(m===``||m===`
2
+ `)){var h=new R;h.newline=!0,c.add(h);return}var g=n.getSeriesByName(m)[0];if(!l.get(m))if(g){var _=g.getData(),v=_.getVisual(`legendLineStyle`)||{},y=_.getVisual(`legendIcon`),b=_.getVisual(`style`),x=this._createItem(g,m,o,a,t,e,v,b,y,u,r);x.on(`click`,I(be,m,null,r,f)).on(`mouseover`,I(z,g.name,null,r,f)).on(`mouseout`,I(B,g.name,null,r,f)),n.ssr&&x.eachChild(function(e){var t=T(e);t.seriesIndex=g.seriesIndex,t.dataIndex=o,t.ssrType=`legend`}),d&&x.eachChild(function(e){s.packEventData(e,t,g,o,m)}),l.set(m,!0)}else n.eachRawSeries(function(s){var c=this;if(!l.get(m)&&s.legendVisualProvider){var h=s.legendVisualProvider;if(!h.containName(m))return;var g=h.indexOfName(m),_=h.getItemVisual(g,`style`),v=h.getItemVisual(g,`legendIcon`),y=i(_.fill);y&&y[3]===0&&(y[3]=.2,_=p(p({},_),{fill:de(y,`rgba`)}));var b=this._createItem(s,m,o,a,t,e,{},_,v,u,r);b.on(`click`,I(be,null,m,r,f)).on(`mouseover`,I(z,null,m,r,f)).on(`mouseout`,I(B,null,m,r,f)),n.ssr&&b.eachChild(function(e){var t=T(e);t.seriesIndex=s.seriesIndex,t.dataIndex=o,t.ssrType=`legend`}),d&&b.eachChild(function(e){c.packEventData(e,t,s,o,m)}),l.set(m,!0)}},this)},this),a&&this._createSelector(a,t,r,o,s)},t.prototype.packEventData=function(e,t,n,r,i){var a={componentType:`legend`,componentIndex:t.componentIndex,dataIndex:r,value:i,seriesIndex:n.seriesIndex};T(e).eventData=a},t.prototype._createSelector=function(e,t,n,r,i){var a=this.getSelectorGroup();L(e,function(e){var r=e.type,i=new l({style:{x:0,y:0,align:`center`,verticalAlign:`middle`},onclick:function(){n.dispatchAction({type:r===`all`?`legendAllSelect`:`legendInverseSelect`,legendId:t.id})}});a.add(i),ne(i,{normal:t.getModel(`selectorLabel`),emphasis:t.getModel([`emphasis`,`selectorLabel`])},{defaultText:e.title}),s(i)})},t.prototype._createItem=function(e,t,n,r,i,o,c,u,d,p,m){var h=e.visualDrawType,g=i.get(`itemWidth`),_=i.get(`itemHeight`),v=i.isSelected(t),y=r.get(`symbolRotate`),b=r.get(`symbolKeepAspect`),x=r.get(`icon`);d=x||d||`roundRect`;var w=ve(d,r,c,u,h,v,m),T=new R,E=r.getModel(`textStyle`);if(S(e.getLegendIcon)&&(!x||x===`inherit`))T.add(e.getLegendIcon({itemWidth:g,itemHeight:_,icon:d,iconRotate:y,itemStyle:w.itemStyle,lineStyle:w.lineStyle,symbolKeepAspect:b}));else{var ee=x===`inherit`&&e.getData().getVisual(`symbol`)?y===`inherit`?e.getData().getVisual(`symbolRotate`):y:0;T.add(ye({itemWidth:g,itemHeight:_,icon:d,iconRotate:ee,itemStyle:w.itemStyle,lineStyle:w.lineStyle,symbolKeepAspect:b}))}var te=o===`left`?g+5:-5,ne=o,D=i.get(`formatter`),O=t;f(D)&&D?O=D.replace(`{name}`,t??``):S(D)&&(O=D(t));var k=v?E.getTextColor():r.get(`inactiveColor`);T.add(new l({style:ae(E,{text:O,x:te,y:_/2,fill:k,align:ne,verticalAlign:`middle`},{inheritColor:k})}));var A=new C({shape:T.getBoundingRect(),style:{fill:`transparent`}}),j=r.getModel(`tooltip`);return j.get(`show`)&&a({el:A,componentModel:i,itemName:t,itemTooltipOption:j.option}),T.add(A),T.eachChild(function(e){e.silent=!0}),A.silent=!p,this.getContentGroup().add(T),s(T),T.__legendDataIndex=n,T},t.prototype.layoutInner=function(e,t,n,r,i,a){var o=this.getContentGroup(),s=this.getSelectorGroup();N(e.get(`orient`),o,e.get(`itemGap`),n.width,n.height);var c=o.getBoundingRect(),l=[-c.x,-c.y];if(s.markRedraw(),o.markRedraw(),i){N(`horizontal`,s,e.get(`selectorItemGap`,!0));var u=s.getBoundingRect(),d=[-u.x,-u.y],f=e.get(`selectorButtonGap`,!0),p=e.getOrient().index,m=p===0?`width`:`height`,h=p===0?`height`:`width`,g=p===0?`y`:`x`;a===`end`?d[p]+=c[m]+f:l[p]+=u[m]+f,d[1-p]+=c[h]/2-u[h]/2,s.x=d[0],s.y=d[1],o.x=l[0],o.y=l[1];var _={x:0,y:0};return _[m]=c[m]+f+u[m],_[h]=Math.max(c[h],u[h]),_[g]=Math.min(0,u[g]+d[1-p]),_}else return o.x=l[0],o.y=l[1],this.group.getBoundingRect()},t.prototype.remove=function(){this.getContentGroup().removeAll(),this._isFirstRender=!0},t.type=`legend.plain`,t}(v);function ve(e,t,n,r,i,a,o){function s(e,t){e.lineWidth===`auto`&&(e.lineWidth=t.lineWidth>0?2:0),L(e,function(n,r){e[r]===`inherit`&&(e[r]=t[r])})}var l=t.getModel(`itemStyle`),u=l.getItemStyle(),d=e.lastIndexOf(`empty`,0)===0?`fill`:`stroke`,f=l.getShallow(`decal`);u.decal=!f||f===`inherit`?r.decal:c(f,o),u.fill===`inherit`&&(u.fill=r[i]),u.stroke===`inherit`&&(u.stroke=r[d]),u.opacity===`inherit`&&(u.opacity=(i===`fill`?r:n).opacity),s(u,r);var p=t.getModel(`lineStyle`),m=p.getLineStyle();if(s(m,n),u.fill===`auto`&&(u.fill=r.fill),u.stroke===`auto`&&(u.stroke=r.fill),m.stroke===`auto`&&(m.stroke=r.fill),!a){var h=t.get(`inactiveBorderWidth`),g=u[d];u.lineWidth=h===`auto`?r.lineWidth>0&&g?2:0:u.lineWidth,u.fill=t.get(`inactiveColor`),u.stroke=t.get(`inactiveBorderColor`),m.stroke=p.get(`inactiveColor`),m.lineWidth=p.get(`inactiveWidth`)}return{itemStyle:u,lineStyle:m}}function ye(e){var t=e.icon||`roundRect`,n=x(t,0,0,e.itemWidth,e.itemHeight,e.itemStyle.fill,e.symbolKeepAspect);return n.setStyle(e.itemStyle),n.rotation=(e.iconRotate||0)*Math.PI/180,n.setOrigin([e.itemWidth/2,e.itemHeight/2]),t.indexOf(`empty`)>-1&&(n.style.stroke=n.style.fill,n.style.fill=M.color.neutral00,n.style.lineWidth=2),n}function be(e,t,n,r){B(e,t,n,r),n.dispatchAction({type:`legendToggleSelect`,name:e??t}),z(e,t,n,r)}function z(e,t,n,r){n.usingTHL()||n.dispatchAction({type:`highlight`,seriesName:e,name:t,excludeSeriesId:r})}function B(e,t,n,r){n.usingTHL()||n.dispatchAction({type:`downplay`,seriesName:e,name:t,excludeSeriesId:r})}function V(e,t,n){var r=e===`allSelect`||e===`inverseSelect`,i={},a=[];n.eachComponent({mainType:`legend`,query:t},function(n){r?n[e]():n[e](t.name),xe(n,i),a.push(n.componentIndex)});var o={};return n.eachComponent(`legend`,function(e){u(i,function(t,n){e[t?`select`:`unSelect`](n)}),xe(e,o)}),r?{selected:o,legendIndex:a}:{name:t.name,selected:o}}function xe(e,t){var n=t||{};return u(e.getData(),function(t){var r=t.get(`name`);if(!(r===`
3
+ `||r===``)){var i=e.isSelected(r);me(n,r)?n[r]=n[r]&&i:n[r]=i}}),n}function Se(e){e.registerAction(`legendToggleSelect`,`legendselectchanged`,_(V,`toggleSelected`)),e.registerAction(`legendAllSelect`,`legendselectall`,_(V,`allSelect`)),e.registerAction(`legendInverseSelect`,`legendinverseselect`,_(V,`inverseSelect`)),e.registerAction(`legendSelect`,`legendselected`,_(V,`select`)),e.registerAction(`legendUnSelect`,`legendunselected`,_(V,`unSelect`))}var Ce=te(we);function we(e){var t=e.findComponents({mainType:`legend`});t&&t.length&&e.filterSeries(function(e){for(var n=0;n<t.length;n++)if(!t[n].isSelected(e.name))return!1;return!0})}function Te(e){e.registerComponentModel(F),e.registerComponentView(_e),e.registerProcessor(e.PRIORITY.PROCESSOR.SERIES_FILTER,Ce),e.registerSubTypeDefaulter(`legend`,function(){return`plain`}),Se(e)}P();var Ee=function(e){j(t,e);function t(){var n=e!==null&&e.apply(this,arguments)||this;return n.type=t.type,n}return t.prototype.setScrollDataIndex=function(e){this.option.scrollDataIndex=e},t.prototype.init=function(t,n,r){var i=oe(t);e.prototype.init.call(this,t,n,r),De(this,t,i)},t.prototype.mergeOption=function(t,n){e.prototype.mergeOption.call(this,t,n),De(this,this.option,t)},t.type=`legend.scroll`,t.defaultOption=re(F.defaultOption,{scrollDataIndex:0,pageButtonItemGap:5,pageButtonGap:null,pageButtonPosition:`end`,pageFormatter:`{current}/{total}`,pageIcons:{horizontal:[`M0,0L12,-10L12,10z`,`M0,0L-12,-10L-12,10z`],vertical:[`M0,0L20,0L10,-20z`,`M0,0L20,0L10,20z`]},pageIconColor:M.color.accent50,pageIconInactiveColor:M.color.accent10,pageIconSize:15,pageTextStyle:{color:M.color.tertiary},animationDurationUpdate:800}),t}(F);function De(e,t,n){var r=e.getOrient(),i=[1,1];i[r.index]=0,O(t,n,{type:`box`,ignoreSize:!!i})}P();var Oe=fe,H=[`width`,`height`],U=[`x`,`y`],ke=function(e){j(t,e);function t(){var n=e!==null&&e.apply(this,arguments)||this;return n.type=t.type,n.newlineDisabled=!0,n._currentIndex=0,n}return t.prototype.init=function(){e.prototype.init.call(this),this.group.add(this._containerGroup=new Oe),this._containerGroup.add(this.getContentGroup()),this.group.add(this._controllerGroup=new Oe)},t.prototype.resetInner=function(){e.prototype.resetInner.call(this),this._controllerGroup.removeAll(),this._containerGroup.removeClipPath(),this._containerGroup.__rectSize=null},t.prototype.renderInner=function(t,n,r,i,a,o,s){var c=this;e.prototype.renderInner.call(this,t,n,r,i,a,o,s);var u=this._controllerGroup,d=n.get(`pageIconSize`,!0),f=w(d)?d:[d,d];m(`pagePrev`,0);var p=n.getModel(`pageTextStyle`);u.add(new l({name:`pageText`,style:{text:`xx/xx`,fill:p.getTextColor(),font:p.getFont(),verticalAlign:`middle`,align:`center`},silent:!0})),m(`pageNext`,1);function m(e,t){var r=e+`DataIndex`,a=pe(n.get(`pageIcons`,!0)[n.getOrient().name][t],{onclick:ie(c._pageGo,c,r,n,i)},{x:-f[0]/2,y:-f[1]/2,width:f[0],height:f[1]});a.name=e,u.add(a)}},t.prototype.layoutInner=function(e,t,n,r,i,a){var o=this.getSelectorGroup(),s=e.getOrient().index,c=H[s],l=U[s],u=H[1-s],d=U[1-s];i&&N(`horizontal`,o,e.get(`selectorItemGap`,!0));var f=e.get(`selectorButtonGap`,!0),p=o.getBoundingRect(),h=[-p.x,-p.y],g=m(n);i&&(g[c]=n[c]-p[c]-f);var _=this._layoutContentAndController(e,r,g,s,c,u,d,l);if(i){if(a===`end`)h[s]+=_[c]+f;else{var v=p[c]+f;h[s]-=v,_[l]-=v}_[c]+=p[c]+f,h[1-s]+=_[d]+_[u]/2-p[u]/2,_[u]=Math.max(_[u],p[u]),_[d]=Math.min(_[d],p[d]+h[1-s]),o.x=h[0],o.y=h[1],o.markRedraw()}return _},t.prototype._layoutContentAndController=function(e,t,r,i,a,o,s,c){var l=this.getContentGroup(),u=this._containerGroup,d=this._controllerGroup;N(e.get(`orient`),l,e.get(`itemGap`),i?r.width:null,i?null:r.height),N(`horizontal`,d,e.get(`pageButtonItemGap`,!0));var f=l.getBoundingRect(),p=d.getBoundingRect(),m=this._showController=f[a]>r[a],h=[-f.x,-f.y];t||(h[i]=l[c]);var g=[0,0],_=[-p.x,-p.y],v=y(e.get(`pageButtonGap`,!0),e.get(`itemGap`,!0));m&&(e.get(`pageButtonPosition`,!0)===`end`?_[i]+=r[a]-p[a]:g[i]+=p[a]+v),_[1-i]+=f[o]/2-p[o]/2,l.setPosition(h),u.setPosition(g),d.setPosition(_);var b={x:0,y:0};if(b[a]=m?r[a]:f[a],b[o]=Math.max(f[o],p[o]),b[s]=Math.min(0,p[s]+_[1-i]),u.__rectSize=r[a],m){var x={x:0,y:0};x[a]=Math.max(r[a]-p[a]-v,0),x[o]=b[o],u.setClipPath(new C({shape:x})),u.__rectSize=x[a]}else d.eachChild(function(e){e.attr({invisible:!0,silent:!0})});var S=this._getPageInfo(e);return S.pageIndex!=null&&n(l,{x:S.contentPosition[0],y:S.contentPosition[1]},m?e:null),this._updatePageInfoView(e,S),b},t.prototype._pageGo=function(e,t,n){var r=this._getPageInfo(t)[e];r!=null&&n.dispatchAction({type:`legendScroll`,scrollDataIndex:r,legendId:t.id})},t.prototype._updatePageInfoView=function(e,t){var n=this._controllerGroup;u([`pagePrev`,`pageNext`],function(r){var i=t[r+`DataIndex`]!=null,a=n.childOfName(r);a&&(a.setStyle(`fill`,i?e.get(`pageIconColor`,!0):e.get(`pageIconInactiveColor`,!0)),a.cursor=i?`pointer`:`default`)});var r=n.childOfName(`pageText`),i=e.get(`pageFormatter`),a=t.pageIndex,o=a==null?0:a+1,s=t.pageCount;r&&i&&r.setStyle(`text`,f(i)?i.replace(`{current}`,o==null?``:o+``).replace(`{total}`,s==null?``:s+``):i({current:o,total:s}))},t.prototype._getPageInfo=function(e){var t=e.get(`scrollDataIndex`,!0),n=this.getContentGroup(),r=this._containerGroup.__rectSize,i=e.getOrient().index,a=H[i],o=U[i],s=this._findTargetItemIndex(t),c=n.children(),l=c[s],u=c.length,d=+!!u,f={contentPosition:[n.x,n.y],pageCount:d,pageIndex:d-1,pagePrevDataIndex:null,pageNextDataIndex:null};if(!l)return f;var p=v(l);f.contentPosition[i]=-p.s;for(var m=s+1,h=p,g=p,_=null;m<=u;++m)_=v(c[m]),(!_&&g.e>h.s+r||_&&!y(_,h.s))&&(h=g.i>h.i?g:_,h&&(f.pageNextDataIndex??=h.i,++f.pageCount)),g=_;for(var m=s-1,h=p,g=p,_=null;m>=-1;--m)_=v(c[m]),(!_||!y(g,_.s))&&h.i<g.i&&(g=h,f.pagePrevDataIndex??=h.i,++f.pageCount,++f.pageIndex),h=_;return f;function v(e){if(e){var t=e.getBoundingRect(),n=t[o]+e[o];return{s:n,e:n+t[a],i:e.__legendDataIndex}}}function y(e,t){return e.e>=t&&e.s<=t+r}},t.prototype._findTargetItemIndex=function(e){if(!this._showController)return 0;var t,n=this.getContentGroup(),r;return n.eachChild(function(n,i){var a=n.__legendDataIndex;r==null&&a!=null&&(r=i),a===e&&(t=i)}),t??r},t.type=`legend.scroll`,t}(_e);function Ae(e){e.registerAction(`legendScroll`,`legendscroll`,function(e,t){var n=e.scrollDataIndex;n!=null&&t.eachComponent({mainType:`legend`,subType:`scroll`,query:e},function(e){e.setScrollDataIndex(n)})})}function je(e){g(Te),e.registerComponentModel(Ee),e.registerComponentView(ke),Ae(e)}function Me(e){g(Te),g(je)}var W=t(e(),1);function G(e){return(Array.isArray(e?.data)?e.data:Array.isArray(e)?e:[]).slice().sort((e,t)=>String(e?.date||``).localeCompare(String(t?.date||``)))}function Ne(e,t=`model`){return t===`family`?e?.by_family||{}:t===`repo`?e?.by_repo||{}:e?.by_model||{}}function Pe(e,t=`tokens`){return e?t===`elapsed_seconds`?e.elapsed_seconds||0:t===`cost`?e.cost||0:e.tokens||0:0}function Fe(e,{split:t=`model`,metric:n=`tokens`,dates:r=null}={}){let i=G(e);if(!i.length)return{dates:[],groups:[],series:[],dayTotals:[]};let a=r||i.map(e=>e.date),o=new Map(i.map(e=>[e.date,e])),s=[],c=new Set;for(let e of a){let r=Ne(o.get(e),t);for(let[e,t]of Object.entries(r))c.has(e)||Pe(t,n)<=0||(c.add(e),s.push(e))}let l=s.map(e=>({key:e,label:e,data:a.map(r=>Pe(Ne(o.get(r),t)[e],n))}));return{dates:a,groups:s,series:l,dayTotals:a.map((e,t)=>l.reduce((e,n)=>e+(n.data[t]||0),0))}}function K(e,t,n){return e+(t-e)*n}function q(e){return Number.isFinite(e)?e:0}function Ie(e){return Math.max(0,Math.min(1,e))}function Le(e,t){return e?.length?t?0:e.length-1:0}function Re(e,t,n=0){if(!e?.length)return 0;if(!t)return e.length-1;let r=Le(e,t),i=e.length-1,a=Ie(((n||0)-.08)/.92)**.82,o=r+(i-r)*a;return Math.max(r,Math.min(i,Math.floor(o+32)))}function J(e,t){return Array.isArray(e?.data)?e.data:Array.isArray(e)?e:e?.data?.[t]||e?.data?.total||[]}function Y(e,t){return t?.length?e===`d7`?t.slice(-7):e===`d30`?t.slice(-30):t:[]}function X(e,t,n){return e.map(e=>({key:e?.[t]||``,label:e?.[n]||``,tokens:q(e?.tokens)})).filter(e=>e.key)}function ze(e,t){let n=G(e);if(!n.length)return{dates:[],series:[]};let r=Y(t,n.map(e=>e.date)),{series:i}=Fe(e,{split:`model`,metric:`tokens`,dates:r});return{dates:r,series:i}}function Be(e,t){let n=G(e);if(!n.length)return[];let r=new Set(Y(t,n.map(e=>e.date)));return n.filter(e=>r.has(e.date))}function Ve(e,t){let n=Be(e,t);return{tokens:n.reduce((e,t)=>e+q(t?.tokens),0),elapsed:n.reduce((e,t)=>e+q(t?.elapsed_seconds),0),cost:n.reduce((e,t)=>e+q(t?.cost),0),days:n.length||1}}function Z(e,t,n){let r={};for(let[i,a]of Object.entries(e||{})){r[i]={};for(let e of n)r[i][e]=q(a?.[e])*t}return r}function He(e,t){return t>=.999?e:{...e,tokens:q(e?.tokens)*t,elapsed_seconds:q(e?.elapsed_seconds)*t,cost:q(e?.cost)*t,sessions:q(e?.sessions)*t,by_model:Z(e?.by_model,t,[`tokens`,`cost`,`elapsed_seconds`]),by_family:Z(e?.by_family,t,[`tokens`,`cost`,`elapsed_seconds`,`sessions`]),by_repo:Z(e?.by_repo,t,[`tokens`,`cost`,`elapsed_seconds`,`sessions`])}}function Ue(e,t){let n=G(e);if(!n.length)return[];let r=n.length-1,i=Math.max(0,Math.min(r,Number.isFinite(t)?t:r)),a=Math.floor(i),o=Math.min(r,Math.ceil(i)),s=i-a;return n.slice(0,o+1).map((e,t)=>t<=a?e:He(e,s))}function Q(e,t,n){let r=new Map;for(let i of e)for(let[e,a]of Object.entries(i?.[t]||{}))r.has(e)||r.set(e,{key:e,label:e,[n]:e,tokens:0}),r.get(e).tokens+=q(a?.tokens);return[...r.values()].sort((e,t)=>t.tokens-e.tokens)}function We({daily:e,range:t,cursor:n,fallback:r}){let i=Ue(e,n),a=t===`d7`?i.slice(-7):t===`d30`?i.slice(-30):i;if(!a.length)return r;let o={...r?.stats||{},tokens:a.reduce((e,t)=>e+q(t?.tokens),0),elapsed:a.reduce((e,t)=>e+q(t?.elapsed_seconds),0),cost:a.reduce((e,t)=>e+q(t?.cost),0),sessions:a.reduce((e,t)=>e+q(t?.sessions),0),days:a.length||1};return{...r||{},ready:!0,stats:o,topRepos:Q(a,`by_repo`,`repo_label`).slice(0,6),topFamilies:Q(a,`by_family`,`family`),topModels:Q(a,`by_model`,`model_name`).slice(0,6)}}function Ge(e){let t=e?.data&&typeof e.data==`object`?e.data:{},n={};for(let[e,r]of Object.entries(t))n[e]={tokens:q(r?.tokens),elapsed:q(r?.elapsed),cost:q(r?.cost)};return n}function Ke({overview:e,heatmap:t,daily:n,families:r,repos:i,models:a,range:o}){let s=e?.data;if(!s)return{ready:!0,stats:{tokens:0,elapsed:0,cost:0,sessions:0,enriched:0,priced:0,exactPriced:0,fallbackPriced:0,unpriced:0,days:1},topRepos:[],topFamilies:[],topModels:[],daily:{dates:[],series:[]},heatmap:{}};let c=s?.[o]||s?.total||{},l=c.coverage||{},u=q(l.thread_rows??l.total),d=q(l.root_sessions??c.total_sessions),f=q(l.priced),p=q(l.priced_exact),m=q(l.priced_fallback),h=q(l.unpriced??Math.max(u-f,0)),g=c.date_range,_=g?.from!=null&&g?.to!=null?Math.max(1,Math.ceil((g.to-g.from)/86400)):1,v=Ve(n,o),y=o===`d7`||o===`d30`;return{ready:!0,stats:{tokens:y?v.tokens:q(c.total_tokens),elapsed:y?v.elapsed:q(c.total_elapsed_seconds),cost:y?v.cost:q(c.total_cost),sessions:d,enriched:q(l.enriched),priced:f,exactPriced:p,fallbackPriced:m,unpriced:h,days:y?v.days:_},topRepos:X(J(i,o).slice(0,6),`repo_label`,`repo_label`),topFamilies:X(J(r,o),`family`,`family`),topModels:X(J(a,o).slice(0,6),`model_name`,`model_name`),daily:ze(n,o),heatmap:Ge(t)}}function $(e,t,n){let r=new Map((e||[]).map(e=>[e.key,e])),i=new Map((t||[]).map(e=>[e.key,e])),a=[],o=new Set;for(let e of t||[])o.has(e.key)||(o.add(e.key),a.push(e.key));for(let t of e||[])o.has(t.key)||(o.add(t.key),a.push(t.key));let s=[];for(let e of a){let t=r.get(e),a=i.get(e),o=a?.label||t?.label||e,c=K(q(t?.tokens),q(a?.tokens),n);c<=.001&&!a||s.push({key:e,label:o,tokens:c})}return s}function qe(e,t,n){let r=(t?.dates?.length?t.dates:e?.dates||[]).slice(),i=new Map((e?.series||[]).map(e=>[e.key,e])),a=new Map((t?.series||[]).map(e=>[e.key,e])),o=new Set([...i.keys(),...a.keys()]),s=[];for(let c of o){let o=i.get(c),l=a.get(c),u=new Map((o?.data||[]).map((t,n)=>[e?.dates?.[n],t])),d=new Map((l?.data||[]).map((e,n)=>[t?.dates?.[n],e])),f=r.map(e=>K(q(u.get(e)),q(d.get(e)),n));f.every(e=>e<=.001)&&!l||s.push({key:c,label:l?.label||o?.label||c,data:f})}return{dates:r,series:s}}function Je(e){return{dates:e.dates,series:(e.series||[]).map(e=>({key:e.key,label:e.label,data:e.data.map(()=>0)}))}}function Ye(e,t,n){let r=new Set([...Object.keys(e||{}),...Object.keys(t||{})]),i={};for(let a of r){let r=e?.[a],o=t?.[a];i[a]={tokens:K(q(r?.tokens),q(o?.tokens),n),elapsed:K(q(r?.elapsed),q(o?.elapsed),n),cost:K(q(r?.cost),q(o?.cost),n)}}return i}function Xe(e,t,n){return{ready:t.ready,stats:{tokens:K(q(e?.stats?.tokens),q(t?.stats?.tokens),n),elapsed:K(q(e?.stats?.elapsed),q(t?.stats?.elapsed),n),cost:K(q(e?.stats?.cost),q(t?.stats?.cost),n),sessions:K(q(e?.stats?.sessions),q(t?.stats?.sessions),n),enriched:K(q(e?.stats?.enriched),q(t?.stats?.enriched),n),priced:K(q(e?.stats?.priced),q(t?.stats?.priced),n),exactPriced:K(q(e?.stats?.exactPriced),q(t?.stats?.exactPriced),n),fallbackPriced:K(q(e?.stats?.fallbackPriced),q(t?.stats?.fallbackPriced),n),unpriced:K(q(e?.stats?.unpriced),q(t?.stats?.unpriced),n),days:q(t?.stats?.days)||1},topRepos:$(e?.topRepos,t?.topRepos,n),topFamilies:$(e?.topFamilies,t?.topFamilies,n),topModels:$(e?.topModels,t?.topModels,n),daily:qe(e?.daily,t?.daily,n),heatmap:Ye(e?.heatmap,t?.heatmap,n)}}function Ze(e,t){let n=new Map((e?.series||[]).map(e=>[e.key,e])),r=0;for(let e of t?.series||[]){let t=n.get(e.key);for(let n=0;n<(e.data?.length||0);n+=1)r=Math.max(r,Math.abs((t?.data?.[n]||0)-(e.data[n]||0)))}return r}function Qe(e){let t=0;for(let n of e?.series||[])for(let e of n.data||[])t=Math.max(t,Math.abs(e||0));return t}function $e(e,t,n=``){let[r,i]=(0,W.useState)(e),a=(0,W.useRef)(e),o=(0,W.useRef)(e),s=(0,W.useRef)(0),c=(0,W.useRef)(0),l=(0,W.useRef)(n),u=(0,W.useRef)(t),d=t&&l.current!==n;return(0,W.useLayoutEffect)(()=>{o.current=e;let r=!u.current&&t;if(u.current=t,!t){s.current&&cancelAnimationFrame(s.current),s.current=0,c.current=0,a.current=e,l.current=n;return}if(l.current!==n){s.current&&cancelAnimationFrame(s.current),s.current=0,c.current=0;let t=Je(e);a.current=t,i(t),l.current=n;return}r&&(a.current=e,i(e))},[e,t,n]),(0,W.useEffect)(()=>{if(o.current=e,!t)return;let n=k,r=e=>{let t=o.current;c.current||=e;let l=Math.max(1,e-c.current);c.current=e;let u=1-Math.exp(-l/Math.max(n,1)),d=qe(a.current,t,u);a.current=d,i(d);let f=Math.max(1,Qe(t));if(Ze(d,t)<=f*.002||u>=.999){a.current=t,i(t),s.current=0,c.current=0;return}s.current=requestAnimationFrame(r)};s.current||=(c.current=0,requestAnimationFrame(r))},[e,t,n]),(0,W.useEffect)(()=>()=>{s.current&&cancelAnimationFrame(s.current),s.current=0,c.current=0},[]),t?d?Je(e):r:e}export{Xe as a,Fe as c,Y as i,G as l,We as n,Le as o,Ke as r,Re as s,$e as t,Me as u};
package/dist/index.html CHANGED
@@ -7,7 +7,7 @@
7
7
  <link rel="preconnect" href="https://fonts.googleapis.com" />
8
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
9
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
10
- <script type="module" crossorigin src="/assets/index-8ykzgYb0.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-Bxd44dxc.js"></script>
11
11
  <link rel="stylesheet" crossorigin href="/assets/index-DdbEQTfc.css">
12
12
  </head>
13
13
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexmeter",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Local telemetry dashboard for Codex CLI usage",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,7 @@ function normalizeEffortKey(effort) {
8
8
  if (k === 'medium') return 'medium';
9
9
  if (k === 'high') return 'high';
10
10
  if (k === 'xhigh') return 'xhigh';
11
+ if (k === 'max') return 'max';
11
12
  return k || 'unknown';
12
13
  }
13
14
 
@@ -39,12 +39,15 @@ export function calculateCostFromUsage(modelName, usage) {
39
39
 
40
40
  const inputTokens = usage.input_tokens || 0;
41
41
  const cachedInputTokens = usage.cached_input_tokens || 0;
42
+ const cacheWriteInputTokens = usage.cache_write_input_tokens || 0;
42
43
  const outputTokens = usage.output_tokens || 0;
43
- const uncachedInputTokens = Math.max(inputTokens - cachedInputTokens, 0);
44
+ const uncachedInputTokens = Math.max(inputTokens - cachedInputTokens - cacheWriteInputTokens, 0);
45
+ const cacheWriteRate = entry.cache_write ?? entry.input;
44
46
 
45
47
  return (
46
48
  (uncachedInputTokens * entry.input) +
47
49
  (cachedInputTokens * entry.cached_input) +
50
+ (cacheWriteInputTokens * cacheWriteRate) +
48
51
  (outputTokens * entry.output)
49
52
  ) / 1_000_000;
50
53
  }
@@ -77,7 +80,7 @@ export function getModelPricing(modelName) {
77
80
  return getPricing()[modelName] || null;
78
81
  }
79
82
 
80
- export const CATALOG_VERSION = '2026-04-23';
83
+ export const CATALOG_VERSION = '2026-07-08';
81
84
  export const CACHE_ASSUMPTIONS = {
82
85
  input_fraction: INPUT_FRACTION,
83
86
  output_fraction: OUTPUT_FRACTION,
@@ -36,7 +36,7 @@ export function beginReplayCapture(replay, ingestId, bootstrapPayload) {
36
36
 
37
37
  export function recordReplayEvent(replay, event, payload) {
38
38
  if (!replay?.active) return;
39
- if (!['progress', 'patch', 'snapshot', 'complete'].includes(event)) return;
39
+ if (!['progress', 'snapshot', 'complete'].includes(event)) return;
40
40
  replay.events.push({
41
41
  event,
42
42
  at_ms: Math.max(0, Date.now() - replay.started_at_ms),
@@ -73,7 +73,7 @@ export function getReplaySnapshot(replay) {
73
73
  events: rest.map((event) => ({
74
74
  event: event.event,
75
75
  at_ms: event.at_ms,
76
- mode: event.event === 'patch' || event.event === 'snapshot' ? event.event : 'progress',
76
+ mode: event.event === 'snapshot' ? 'snapshot' : 'progress',
77
77
  payload: clonePayload(event.payload),
78
78
  })),
79
79
  };
package/server/index.js CHANGED
@@ -160,23 +160,8 @@ export function createServer(codexHome, opts = {}) {
160
160
  res.download(job.output_path, job.file_name || `codexmeter-overview-${job.id}.mp4`);
161
161
  });
162
162
 
163
- app.get('/api/sessions', (req, res) => {
164
- const q = (req.query.q || '').toLowerCase();
165
- let sessions = state.sessions || [];
166
- if (q) {
167
- sessions = sessions.filter(s =>
168
- (s.repo_label?.toLowerCase().includes(q)) ||
169
- (s.model_name?.toLowerCase().includes(q)) ||
170
- (s.agent_role?.toLowerCase().includes(q)) ||
171
- (s.agent_nickname?.toLowerCase().includes(q)) ||
172
- (s.title?.toLowerCase().includes(q)) ||
173
- (s.descendant_models || []).some(v => v?.toLowerCase().includes(q)) ||
174
- (s.descendant_families || []).some(v => v?.toLowerCase().includes(q)) ||
175
- (s.descendant_roles || []).some(v => v?.toLowerCase().includes(q)) ||
176
- (s.descendant_nicknames || []).some(v => v?.toLowerCase().includes(q)) ||
177
- (s.related_titles || []).some(v => v?.toLowerCase().includes(q))
178
- );
179
- }
163
+ app.get('/api/sessions', (_req, res) => {
164
+ const sessions = state.sessions || [];
180
165
  res.json({
181
166
  data: sessions.map(s => ({
182
167
  thread_id: s.thread_id, root_thread_id: s.root_thread_id, repo_label: s.repo_label,
package/server/ingest.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  import { calculateCostFromUsage, initPricing, priceSession } from './cost-catalog.js';
8
8
  import { buildAggregates, buildSessionView } from './aggregator.js';
9
9
  import { createDayKeyFormatter } from './day-key.js';
10
- import { createLiveAggregateState, createEmptyLivePatch, applySessionToLiveState, buildLivePatch, buildLiveSnapshot } from './live-state.js';
10
+ import { createLiveAggregateState, applySessionToLiveState, buildLiveSnapshot } from './live-state.js';
11
11
  import { createRolloutWorkerPool } from './rollout-worker-pool.js';
12
12
  import { beginReplayCapture, createReplayCaptureState, failReplayCapture, getReplaySnapshot, recordReplayEvent, resetReplayCapture } from './export-replay.js';
13
13
  import { findUsageEntryAtOrBefore, hasUsageTotals, readUsageTimeline, subtractUsageTotals } from './rollout-reader.js';
@@ -22,6 +22,10 @@ const LIVE_SNAPSHOT_HZ = Math.max(
22
22
  Number(OVERVIEW_INGEST_ANIMATION.live?.snapshotHz) || 10
23
23
  );
24
24
  const LIVE_SNAPSHOT_CADENCE_MS = Math.round(1000 / LIVE_SNAPSHOT_HZ);
25
+ const ROLLOUT_READER_OPTIONS = { fastScan: true, rgScan: true };
26
+ const RESULT_CHUNK_SIZE = 16;
27
+ const ROOT_REFRESH_EVERY = 1000;
28
+ const FORK_CORRECTION_CONCURRENCY = 32;
25
29
 
26
30
  export function createIngestState() {
27
31
  return {
@@ -45,7 +49,7 @@ export function createIngestState() {
45
49
  live_seq: 0,
46
50
  live_subscribers: new Set(),
47
51
  live_pump_timer: null,
48
- live_pending_patch: createEmptyLivePatch(),
52
+ live_data_dirty: false,
49
53
  live_progress_dirty: false,
50
54
  live_last_emit_at: 0,
51
55
  live_last_snapshot_emit_at: 0,
@@ -54,25 +58,11 @@ export function createIngestState() {
54
58
  }
55
59
 
56
60
  export async function runIngest(codexHome, state, opts = {}) {
57
- const timingEnabled = opts.ingestTiming === true;
58
- const timingStartedAt = performance.now();
59
- let timingLastLogAt = timingStartedAt;
60
61
  const tz = opts.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
61
62
  const toDayKey = createDayKeyFormatter(tz);
62
63
  const runToken = state.run_token;
63
64
  const isCurrentRun = () => state.run_token === runToken;
64
- const fastRolloutReader = opts.fastRolloutReader === true;
65
- const rgRolloutReader = opts.rgRolloutReader === true;
66
- const streamRolloutChunks = opts.streamRolloutChunks === true;
67
- const readerOptions = {
68
- fastScan: fastRolloutReader || rgRolloutReader,
69
- rgScan: rgRolloutReader,
70
- rgMinBytes: opts.rgMinBytes,
71
- };
72
- const workerPool = createRolloutWorkerPool({
73
- size: opts.workerThreads,
74
- readerOptions,
75
- });
65
+ const workerPool = createRolloutWorkerPool({ readerOptions: ROLLOUT_READER_OPTIONS });
76
66
 
77
67
  try {
78
68
  state.live_state = createLiveAggregateState(tz);
@@ -154,37 +144,18 @@ export async function runIngest(codexHome, state, opts = {}) {
154
144
  if (bootstrapCandidates.length) {
155
145
  assignRootThreadIds(sessions);
156
146
  const bootstrapSessions = filterLiveSessions(bootstrapCandidates, opts);
157
- const bootstrapPatch = createEmptyLivePatch();
158
147
  for (const session of bootstrapSessions) {
159
148
  finalizeSessionMetrics(session, toDayKey);
160
- applySessionToLiveState(state.live_state, session, bootstrapPatch);
149
+ applySessionToLiveState(state.live_state, session);
161
150
  }
162
- queueLivePatch(state, bootstrapPatch);
151
+ queueLiveData(state);
163
152
  }
164
153
 
165
- const candidates = selectEnrichmentCandidates(sessions, {
166
- recentFirstDays: opts.recentFirstDays,
167
- warmupOldestCount: opts.warmupOldestCount,
168
- });
154
+ const candidates = selectEnrichmentCandidates(sessions);
169
155
 
170
156
  state.needs_enrichment = candidates.length;
171
157
  state.percent = candidates.length > 0 ? 0.08 : 0.90;
172
- const BATCH_SIZE = opts.batchSize || 40;
173
- const RESULT_CHUNK_SIZE = Math.max(1, Number(opts.resultChunkSize || Math.min(BATCH_SIZE, 16)) || 16);
174
- const ROOT_REFRESH_EVERY = opts.rootRefreshEvery || 1000;
175
- const FORK_CORRECTION_CONCURRENCY = Math.max(1, Number(opts.forkCorrectionConcurrency || 1) || 1);
176
- logIngestTiming(timingEnabled, 'start', {
177
- rollouts: candidates.length,
178
- workers: workerPool.size,
179
- rg: rgRolloutReader,
180
- stream: streamRolloutChunks,
181
- forkConcurrency: FORK_CORRECTION_CONCURRENCY,
182
- });
183
- const resolveForkUsageSnapshot = createForkUsageSnapshotResolver(sessions, {
184
- fastScan: fastRolloutReader,
185
- rgScan: rgRolloutReader,
186
- rgMinBytes: opts.rgMinBytes,
187
- });
158
+ const resolveForkUsageSnapshot = createForkUsageSnapshotResolver(sessions);
188
159
  let lastRootRefreshCount = 0;
189
160
  let enrichedCount = 0;
190
161
 
@@ -255,11 +226,10 @@ export async function runIngest(codexHome, state, opts = {}) {
255
226
  }
256
227
  const liveReady = filterLiveSessions(batch, opts);
257
228
  state.current_date_bucket = pickVisibleDateBucket([], liveReady);
258
- const livePatch = createEmptyLivePatch();
259
229
  for (const session of liveReady) {
260
- applySessionToLiveState(state.live_state, session, livePatch);
230
+ applySessionToLiveState(state.live_state, session);
261
231
  }
262
- queueLivePatch(state, livePatch);
232
+ queueLiveData(state);
263
233
 
264
234
  state.enriched = enrichedCount;
265
235
  state.percent = candidates.length > 0
@@ -267,43 +237,22 @@ export async function runIngest(codexHome, state, opts = {}) {
267
237
  : 0.90;
268
238
  queueLiveProgress(state);
269
239
 
270
- const now = performance.now();
271
- if (timingEnabled && now - timingLastLogAt >= 5000) {
272
- timingLastLogAt = now;
273
- const elapsedSeconds = Math.max((now - timingStartedAt) / 1000, 0.001);
274
- logIngestTiming(true, 'progress', {
275
- enriched: state.enriched,
276
- rollouts: candidates.length,
277
- rate: Math.round(state.enriched / elapsedSeconds),
278
- currentDate: state.current_date_bucket,
279
- });
280
- }
281
240
  };
282
241
 
283
- if (streamRolloutChunks) {
284
- await workerPool.mapRolloutsInChunks(
285
- candidates.map((session) => session.rollout_path),
286
- tz,
287
- {
288
- chunkSize: RESULT_CHUNK_SIZE,
289
- onChunk: async (chunk) => {
290
- const orderedChunk = chunk.slice().sort((a, b) => a.index - b.index);
291
- const batch = orderedChunk.map(({ index }) => candidates[index]);
292
- const results = orderedChunk.map(({ result }) => result);
293
- await handleEnrichedBatch(batch, results);
294
- },
295
- }
296
- );
297
- if (!isCurrentRun()) return;
298
- } else {
299
- for (let i = 0; i < candidates.length; i += BATCH_SIZE) {
300
- const batch = candidates.slice(i, i + BATCH_SIZE);
301
- const results = await workerPool.mapRollouts(batch.map((session) => session.rollout_path), tz);
302
- await handleEnrichedBatch(batch, results);
303
-
304
- if (!isCurrentRun()) return;
242
+ await workerPool.mapRolloutsInChunks(
243
+ candidates.map((session) => session.rollout_path),
244
+ tz,
245
+ {
246
+ chunkSize: RESULT_CHUNK_SIZE,
247
+ onChunk: async (chunk) => {
248
+ const orderedChunk = chunk.slice().sort((a, b) => a.index - b.index);
249
+ const batch = orderedChunk.map(({ index }) => candidates[index]);
250
+ const results = orderedChunk.map(({ result }) => result);
251
+ await handleEnrichedBatch(batch, results);
252
+ },
305
253
  }
306
- }
254
+ );
255
+ if (!isCurrentRun()) return;
307
256
 
308
257
  inheritMissingLineageModels(sessions, sessionById);
309
258
  for (const s of sessions) {
@@ -312,11 +261,10 @@ export async function runIngest(codexHome, state, opts = {}) {
312
261
 
313
262
  assignRootThreadIds(sessions);
314
263
  state.live_state = createLiveAggregateState(tz);
315
- const finalLivePatch = createEmptyLivePatch();
316
264
  for (const session of filterLiveSessions(sessions, opts)) {
317
- applySessionToLiveState(state.live_state, session, finalLivePatch);
265
+ applySessionToLiveState(state.live_state, session);
318
266
  }
319
- queueLivePatch(state, finalLivePatch);
267
+ queueLiveData(state);
320
268
 
321
269
  state.phase = 'aggregation';
322
270
  state.percent = state.needs_enrichment > 0 ? 0.95 : 0.90;
@@ -331,11 +279,6 @@ export async function runIngest(codexHome, state, opts = {}) {
331
279
  state.current_date_bucket = null;
332
280
  queueLiveProgress(state);
333
281
  finalizeWithoutSubscribers(state);
334
- logIngestTiming(timingEnabled, 'finalizing', {
335
- elapsedSeconds: Number(((performance.now() - timingStartedAt) / 1000).toFixed(1)),
336
- rollouts: candidates.length,
337
- events: state.replay_capture.events.length,
338
- });
339
282
 
340
283
  } catch (err) {
341
284
  if (!isCurrentRun()) return;
@@ -373,7 +316,7 @@ export function restartIngest(codexHome, state, opts = {}) {
373
316
  state.presentation_complete_pending = false;
374
317
  state.live_state = null;
375
318
  state.live_seq = 0;
376
- state.live_pending_patch = createEmptyLivePatch();
319
+ state.live_data_dirty = false;
377
320
  state.live_progress_dirty = false;
378
321
  state.live_last_emit_at = 0;
379
322
  state.live_last_snapshot_emit_at = 0;
@@ -440,27 +383,10 @@ function filterLiveSessions(sessions, opts) {
440
383
  return applyFilters(filterVisibleSessions(sessions), opts);
441
384
  }
442
385
 
443
- export function selectEnrichmentCandidates(sessions, opts = {}) {
444
- const sorted = sessions
386
+ export function selectEnrichmentCandidates(sessions) {
387
+ return sessions
445
388
  .filter((session) => session.rollout_path)
446
389
  .sort((a, b) => (a.started_at || 0) - (b.started_at || 0));
447
- const recentFirstDays = Number(opts.recentFirstDays || 0);
448
- const warmupOldestCount = Math.max(0, Number(opts.warmupOldestCount || 0) || 0);
449
- if (!Number.isFinite(recentFirstDays) || recentFirstDays <= 0) return sorted;
450
-
451
- const warmup = sorted.slice(0, warmupOldestCount);
452
- const remaining = sorted.slice(warmupOldestCount);
453
- const cutoff = (Date.now() / 1000) - recentFirstDays * 86400;
454
- const recent = [];
455
- const older = [];
456
- for (const session of remaining) {
457
- if ((session.ended_at || session.started_at || 0) >= cutoff) {
458
- recent.push(session);
459
- } else {
460
- older.push(session);
461
- }
462
- }
463
- return [...warmup, ...recent, ...older];
464
390
  }
465
391
 
466
392
  export function inheritMissingLineageModels(targets, sessionById = new Map(targets.map((session) => [session.thread_id, session]))) {
@@ -624,14 +550,9 @@ function buildUsageByDayMetrics(modelName, usageByDay) {
624
550
  return entries;
625
551
  }
626
552
 
627
- function createForkUsageSnapshotResolver(sessions, opts = {}) {
553
+ function createForkUsageSnapshotResolver(sessions) {
628
554
  const byId = new Map(sessions.map((session) => [session.thread_id, session]));
629
555
  const timelineCache = new Map();
630
- const timelineOptions = {
631
- fastScan: opts.fastScan === true || opts.rgScan === true,
632
- rgScan: opts.rgScan === true,
633
- rgMinBytes: opts.rgMinBytes,
634
- };
635
556
 
636
557
  return async function resolveForkUsageSnapshot(parentThreadId, boundary) {
637
558
  if (!parentThreadId || !boundary) return null;
@@ -640,7 +561,7 @@ function createForkUsageSnapshotResolver(sessions, opts = {}) {
640
561
 
641
562
  let timelinePromise = timelineCache.get(parentThreadId);
642
563
  if (!timelinePromise) {
643
- timelinePromise = readUsageTimeline(parent.rollout_path, timelineOptions);
564
+ timelinePromise = readUsageTimeline(parent.rollout_path, ROLLOUT_READER_OPTIONS);
644
565
  timelineCache.set(parentThreadId, timelinePromise);
645
566
  }
646
567
 
@@ -726,6 +647,7 @@ function subtractUsageFromDayBuckets(usageByDay, inheritedUsage) {
726
647
  const remaining = {
727
648
  input_tokens: inheritedUsage?.input_tokens || 0,
728
649
  cached_input_tokens: inheritedUsage?.cached_input_tokens || 0,
650
+ cache_write_input_tokens: inheritedUsage?.cache_write_input_tokens || 0,
729
651
  output_tokens: inheritedUsage?.output_tokens || 0,
730
652
  reasoning_output_tokens: inheritedUsage?.reasoning_output_tokens || 0,
731
653
  total_tokens: inheritedUsage?.total_tokens || 0,
@@ -737,6 +659,7 @@ function subtractUsageFromDayBuckets(usageByDay, inheritedUsage) {
737
659
  const adjusted = subtractUsageTotals({
738
660
  input_tokens: current.input_tokens || 0,
739
661
  cached_input_tokens: current.cached_input_tokens || 0,
662
+ cache_write_input_tokens: current.cache_write_input_tokens || 0,
740
663
  output_tokens: current.output_tokens || 0,
741
664
  total_tokens: (current.input_tokens || 0) + (current.output_tokens || 0),
742
665
  }, remaining);
@@ -744,6 +667,7 @@ function subtractUsageFromDayBuckets(usageByDay, inheritedUsage) {
744
667
  const consumed = subtractUsageTotals({
745
668
  input_tokens: current.input_tokens || 0,
746
669
  cached_input_tokens: current.cached_input_tokens || 0,
670
+ cache_write_input_tokens: current.cache_write_input_tokens || 0,
747
671
  output_tokens: current.output_tokens || 0,
748
672
  total_tokens: (current.input_tokens || 0) + (current.output_tokens || 0),
749
673
  }, adjusted);
@@ -751,17 +675,22 @@ function subtractUsageFromDayBuckets(usageByDay, inheritedUsage) {
751
675
  Object.assign(remaining, subtractUsageTotals(remaining, consumed));
752
676
 
753
677
  if (adjusted.input_tokens > 0 || adjusted.cached_input_tokens > 0 || adjusted.output_tokens > 0) {
754
- next[dayKey] = {
678
+ next[dayKey] = maybeWithCacheWrite({
755
679
  input_tokens: adjusted.input_tokens,
756
680
  cached_input_tokens: adjusted.cached_input_tokens,
757
681
  output_tokens: adjusted.output_tokens,
758
- };
682
+ }, adjusted.cache_write_input_tokens);
759
683
  }
760
684
  }
761
685
 
762
686
  return next;
763
687
  }
764
688
 
689
+ function maybeWithCacheWrite(usage, cacheWriteInputTokens) {
690
+ if (cacheWriteInputTokens > 0) usage.cache_write_input_tokens = cacheWriteInputTokens;
691
+ return usage;
692
+ }
693
+
765
694
  function deriveLiveSortDay(session, toDayKey) {
766
695
  if (session.has_usage_by_day && session.usage_by_day?.length) {
767
696
  let best = session.usage_by_day[0];
@@ -787,8 +716,8 @@ function queueLiveProgress(state) {
787
716
  ensureLivePump(state);
788
717
  }
789
718
 
790
- function queueLivePatch(state, patch) {
791
- mergePatchInto(state.live_pending_patch, patch);
719
+ function queueLiveData(state) {
720
+ state.live_data_dirty = true;
792
721
  state.live_progress_dirty = true;
793
722
  ensureLivePump(state);
794
723
  }
@@ -816,12 +745,12 @@ function finalizeWithoutSubscribers(state) {
816
745
  state.complete = true;
817
746
  state.presentation_complete_pending = false;
818
747
  state.live_progress_dirty = false;
819
- state.live_pending_patch = createEmptyLivePatch();
748
+ state.live_data_dirty = false;
820
749
  }
821
750
 
822
751
  function flushLive(state, forcedEvent = null) {
823
752
  if (!state.live_subscribers.size && !state.replay_capture.active) {
824
- state.live_pending_patch = createEmptyLivePatch();
753
+ state.live_data_dirty = false;
825
754
  state.live_progress_dirty = false;
826
755
  stopLivePumpIfIdle(state);
827
756
  return;
@@ -835,13 +764,11 @@ function flushLive(state, forcedEvent = null) {
835
764
  }
836
765
  }
837
766
 
838
- const patchPending = !isPatchEmpty(state.live_pending_patch);
839
- const readyForSnapshot = forcedEvent || (patchPending && readyForSnapshotEmit(state, Date.now()));
767
+ const readyForSnapshot = forcedEvent || (state.live_data_dirty && readyForSnapshotEmit(state, Date.now()));
840
768
  if (!forcedEvent && !readyForSnapshot && !state.live_progress_dirty && !state.presentation_complete_pending) {
841
769
  return;
842
770
  }
843
771
 
844
- const flushablePatch = readyForSnapshot ? takeAllPendingPatch(state) : createEmptyLivePatch();
845
772
  const shouldEmitComplete = !forcedEvent && state.presentation_complete_pending;
846
773
  const event = forcedEvent || (shouldEmitComplete ? 'complete' : (readyForSnapshot ? 'snapshot' : 'progress'));
847
774
 
@@ -860,8 +787,6 @@ function flushLive(state, forcedEvent = null) {
860
787
 
861
788
  if (event === 'snapshot' || event === 'complete') {
862
789
  payload.data = buildLiveSnapshot(state.live_state);
863
- } else if (event === 'patch') {
864
- payload.data = buildLivePatch(state.live_state, flushablePatch);
865
790
  }
866
791
 
867
792
  recordReplayEvent(state.replay_capture, event, payload);
@@ -875,8 +800,8 @@ function flushLive(state, forcedEvent = null) {
875
800
  state.live_progress_dirty = event === 'progress' || event === 'snapshot' || event === 'complete'
876
801
  ? false
877
802
  : state.live_progress_dirty;
878
- if (forcedEvent || event === 'complete') {
879
- state.live_pending_patch = createEmptyLivePatch();
803
+ if (event === 'snapshot' || event === 'complete' || forcedEvent) {
804
+ state.live_data_dirty = false;
880
805
  }
881
806
  stopLivePumpIfIdle(state);
882
807
  }
@@ -892,56 +817,10 @@ function broadcastLive(state, event, payload) {
892
817
  }
893
818
  }
894
819
 
895
- function mergePatchInto(target, source) {
896
- for (const key of source.overview) target.overview.add(key);
897
- mergeRangePatchSets(target.repos, source.repos);
898
- mergeRangePatchSets(target.models, source.models);
899
- mergeRangePatchSets(target.families, source.families);
900
- for (const key of source.daily) target.daily.add(key);
901
- for (const key of source.heatmap) target.heatmap.add(key);
902
- }
903
-
904
- function mergeRangePatchSets(target, source) {
905
- for (const rangeKey of ['total', 'd7', 'd30']) {
906
- for (const key of source[rangeKey]) target[rangeKey].add(key);
907
- }
908
- }
909
-
910
- function isPatchEmpty(patch) {
911
- return patch.overview.size === 0 &&
912
- patch.repos.total.size === 0 && patch.repos.d7.size === 0 && patch.repos.d30.size === 0 &&
913
- patch.models.total.size === 0 && patch.models.d7.size === 0 && patch.models.d30.size === 0 &&
914
- patch.families.total.size === 0 && patch.families.d7.size === 0 && patch.families.d30.size === 0 &&
915
- patch.daily.size === 0 &&
916
- patch.heatmap.size === 0;
917
- }
918
-
919
820
  function readyForSnapshotEmit(state, now) {
920
821
  return (now - state.live_last_snapshot_emit_at) >= LIVE_SNAPSHOT_CADENCE_MS;
921
822
  }
922
823
 
923
- function moveSet(from, to) {
924
- for (const value of from) to.add(value);
925
- from.clear();
926
- }
927
-
928
- function moveRangeSets(fromRanges, toRanges) {
929
- for (const rangeKey of ['total', 'd7', 'd30']) {
930
- moveSet(fromRanges[rangeKey], toRanges[rangeKey]);
931
- }
932
- }
933
-
934
- function takeAllPendingPatch(state) {
935
- const sent = createEmptyLivePatch();
936
- moveSet(state.live_pending_patch.overview, sent.overview);
937
- moveRangeSets(state.live_pending_patch.repos, sent.repos);
938
- moveRangeSets(state.live_pending_patch.models, sent.models);
939
- moveRangeSets(state.live_pending_patch.families, sent.families);
940
- moveSet(state.live_pending_patch.daily, sent.daily);
941
- moveSet(state.live_pending_patch.heatmap, sent.heatmap);
942
- return sent;
943
- }
944
-
945
824
  function progressPayload(state) {
946
825
  return {
947
826
  phase: state.phase,
@@ -958,11 +837,6 @@ function progressPayload(state) {
958
837
  };
959
838
  }
960
839
 
961
- function logIngestTiming(enabled, event, payload) {
962
- if (!enabled) return;
963
- console.log(`codexmeter ingest timing ${event}: ${JSON.stringify(payload)}`);
964
- }
965
-
966
840
  export function attachLiveSubscriber(state, res) {
967
841
  state.live_subscribers.add(res);
968
842
  ensureLivePump(state);