@hydra-acp/budgeter 0.1.19 → 0.1.20
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/cost/aggregate.js +1 -1
- package/package.json +3 -3
package/dist/cost/aggregate.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{relative as H,resolve as R}from"node:path";import{homedir as L}from"node:os";import{realpathSync as $}from"node:fs";function V(w){const c=w.match(/^(\d+)\s*([dhmwy])$/i);if(c!==null){const y=c[1],a=c[2];if(y===void 0||a===void 0)throw new Error(`invalid since spec: ${w}`);const h=parseInt(y,10),k=a.toLowerCase(),r=new Date;return k==="d"?r.setDate(r.getDate()-h):k==="h"?r.setHours(r.getHours()-h):k==="w"?r.setDate(r.getDate()-h*7):k==="m"?r.setMonth(r.getMonth()-h):k==="y"&&r.setFullYear(r.getFullYear()-h),r}const t=new Date(w);if(Number.isNaN(t.getTime()))throw new Error(`invalid since spec: ${w}`);return t}function q(w){const c=w.locByFiletype;if(c===void 0)return 0;let t=0;for(const y of Object.keys(c)){const a=c[y];a!==void 0&&(t+=a.added-a.removed)}return t}const I=new Map;function D(w){if(I.has(w))return I.get(w);try{const c=$(w);return I.set(w,c),c}catch{return I.set(w,w),w}}function P(w,c){let t=w;if(c.since!==void 0){const h=c.since.getTime(),k=[];for(const r of t)new Date(r.updatedAt).getTime()<h||k.push(r);t=k}if(c.dir!==void 0){const h=D(R(c.dir)),k=[];for(const r of t)r.cwd===void 0||r.cwd===""||(r.cwd.startsWith(h+"/")||r.cwd===h)&&k.push(r);t=k}if(c.host!==void 0&&c.host!=="all"){const h=c.host,k=[];for(const r of t)h==="local"?(!r.importedFromMachine||r.upstreamSessionId)&&k.push(r):r.importedFromMachine===h&&!r.upstreamSessionId&&k.push(r);t=k}if(c.interactive!==void 0){const h=c.interactive,k=[];for(const r of t)r.interactive===h&&k.push(r);t=k}const y=c.min??0,a=[];for(const h of t){let k;c.minMetric==="tokens"?k=h.contextTokens:c.minMetric==="loc"?k=q(h):k=h.costAmount,k>y&&a.push(h)}return a}function Y(w){return w.dir!==void 0?R(w.dir):R(L())}function K(w,c,t){if(w===void 0||w==="")return"<unknown>";const y=D(R(w));if(c===void 0){const S=D(R(L()));return y===S?"~":y.startsWith(S+"/")?"~/"+y.slice(S.length+1):y}const a=D(R(t));let h=H(a,y);if(h===""||h===".")return"<root>";if(h.startsWith(".."))return"<unknown>";const k=h.split("/");if(k.length===0)return"<root>";const r=Math.min(c,k.length),C=k.slice(0,r);return C.length===0?"<root>":C.join("/")}function X(w,c,t={},y){let a=t.since;if(a===void 0&&t.bucket!==void 0){const e=new Date;t.bucket==="hour"?(e.setHours(e.getHours()-24),a=e):t.bucket==="day"||t.bucket==="weekday"?(e.setDate(e.getDate()-30),a=e):t.bucket==="week"?(e.setMonth(e.getMonth()-6),a=e):t.bucket==="month"&&(e.setFullYear(e.getFullYear()-2),a=e)}if(!(a!==void 0||t.bucket!==void 0||t.tokens===!0||t.loc===!0||t.by!==void 0||t.dir!==void 0||t.interactive!==void 0)){let e=0;for(const i of w)e+=i.costAmount;let s="";for(const i of w){s=i.costCurrency;break}return{kind:"total",row:{label:"All sessions",costAmount:e,sessionCount:w.length},currency:s}}const k={since:a,dir:t.dir,interactive:t.interactive,min:t.min,minMetric:t.loc===!0?"loc":t.tokens===!0?"tokens":"cost"},r=P(w,k),C=new Map;if(c!==void 0)for(const e of c){const s=C.get(e.sessionId);s===void 0?C.set(e.sessionId,[e]):s.push(e)}let S="";if(c!==void 0&&c.length>0)for(const e of c){S=e.currency;break}else if(r.length>0)for(const e of r){S=e.costCurrency;break}if(t.by==="filetype"&&t.bucket===void 0){const e=new Map,s=new Set;for(const u of r){const n=u.locByFiletype;if(n===void 0)continue;let l=!1;for(const m of Object.keys(n)){const f=n[m];if(f===void 0)continue;let b=e.get(m);b===void 0&&(b={added:0,removed:0,sessions:new Set},e.set(m,b)),b.added+=f.added,b.removed+=f.removed,(f.added>0||f.removed>0)&&(b.sessions.add(u.sessionId),l=!0)}l&&s.add(u.sessionId)}const i=[];for(const[u,n]of e){const l={label:u,costAmount:0,sessionCount:n.sessions.size,linesAdded:n.added,linesRemoved:n.removed};i.push({label:u,items:[l],sessionCount:n.sessions.size})}return{kind:"grouped",groups:i,currency:S,totalSessions:s.size}}const E=e=>t.by==="dir"?K(e.cwd,t.depth,Y(t)):t.by==="session"?e.sessionId.startsWith("hydra_session_")?e.sessionId.slice(14):e.sessionId:t.by==="model"?e.model===""?"<unknown>":e.model:t.by==="agent"?e.agentId===""?"<unknown>":e.agentId:"<all>",B=e=>{const s=new Date(e);if(Number.isNaN(s.getTime()))return"<invalid>";if(t.bucket==="hour"){const i=s.toLocaleDateString(void 0,{month:"2-digit",day:"2-digit"}),u=String(s.getHours()).padStart(2,"0");return`${i} ${u}:00`}if(t.bucket==="day")return s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"});if(t.bucket==="weekday")return s.toLocaleDateString(void 0,{weekday:"short"});if(t.bucket==="week"){const i=new Date(s),u=i.getDay(),n=i.getDate()-u+(u===0?-6:1);return i.setDate(n),i.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})}return t.bucket==="month"?s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit"}):s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})},x=new Map;if(t.bucket==="weekday"){const e=new Date(2024,0,1);for(let s=0;s<7;s++){const i=new Date(e);i.setDate(e.getDate()+s),x.set(i.toLocaleDateString(void 0,{weekday:"short"}),s)}}const M=(e,s)=>{if(t.bucket==="weekday"){const i=x.get(e.bucket)??7,u=x.get(s.bucket)??7;if(i!==u)return i-u}return e.bucket.localeCompare(s.bucket)},F=new Map;for(const e of r)F.set(e.sessionId,e);const A=new Map;if(c!==void 0){for(const e of c){if(!F.has(e.sessionId))continue;const s=A.get(e.sessionId);s===void 0?A.set(e.sessionId,[e]):s.push(e)}for(const e of A.values())e.sort((s,i)=>s.ts.localeCompare(i.ts))}if(t.by===void 0&&t.bucket===void 0){let e=0,s=0,i=0,u=0,n=0,l=0;for(const f of r){const b=A.get(f.sessionId);if(b===void 0||b.length<2)e+=f.costAmount,l++;else{let d=b[0].cumulativeCost,g=!1;for(let p=1;p<b.length;p++){const v=b[p];if(v===void 0)continue;const T=Math.max(0,v.cumulativeCost-d);d=v.cumulativeCost,!(a!==void 0&&new Date(v.ts)<a)&&(e+=T,g=!0)}g&&l++}if(t.tokens===!0){const o=C.get(f.sessionId);if(o!==void 0)for(const d of o)d.inputTokens!==void 0&&(s+=d.inputTokens),d.outputTokens!==void 0&&(i+=d.outputTokens),d.cacheReadTokens!==void 0&&(u+=d.cacheReadTokens),d.cacheWriteTokens!==void 0&&(n+=d.cacheWriteTokens)}}const m={label:"All sessions",costAmount:e,deltaCost:e,sessionCount:l};if(t.tokens===!0&&(m.inputTokens=s,m.outputTokens=i,m.cacheReadTokens=u,m.cacheWriteTokens=n),t.loc===!0){let f=0,b=0;for(const o of r){const d=o.locByFiletype;if(d!==void 0)for(const g of Object.keys(d)){const p=d[g];p!==void 0&&(f+=p.added,b+=p.removed)}}m.linesAdded=f,m.linesRemoved=b}return{kind:"total",row:m,currency:S}}if(t.by!==void 0&&t.bucket===void 0){const e=new Map;for(const i of r){const u=E(i);let n=e.get(u);if(n===void 0&&(n={label:u,rows:{label:u,costAmount:0,deltaCost:0,sessionCount:0},sessions:new Set},e.set(u,n)),t.tokens===!0&&(n.rows.inputTokens===void 0&&(n.rows.inputTokens=0),n.rows.inputTokens+=i.contextTokens),t.loc===!0){const m=i.locByFiletype;if(m!==void 0){n.rows.linesAdded===void 0&&(n.rows.linesAdded=0),n.rows.linesRemoved===void 0&&(n.rows.linesRemoved=0);for(const f of Object.keys(m)){const b=m[f];b!==void 0&&(n.rows.linesAdded+=b.added,n.rows.linesRemoved+=b.removed)}}}const l=A.get(i.sessionId);if(l===void 0||l.length<2)n.rows.costAmount+=i.costAmount,n.rows.deltaCost+=i.costAmount,n.sessions.add(i.sessionId);else{let f=l[0].cumulativeCost,b=!1;for(let o=1;o<l.length;o++){const d=l[o];if(d===void 0)continue;const g=Math.max(0,d.cumulativeCost-f);f=d.cumulativeCost,!(a!==void 0&&new Date(d.ts)<a)&&(n.rows.costAmount+=g,n.rows.deltaCost+=g,b=!0)}b&&n.sessions.add(i.sessionId)}if(t.tokens===!0){const m=C.get(i.sessionId);if(m!==void 0)for(const f of m)n.rows.inputTokens===void 0&&(n.rows.inputTokens=0),n.rows.outputTokens===void 0&&(n.rows.outputTokens=0),n.rows.cacheReadTokens===void 0&&(n.rows.cacheReadTokens=0),n.rows.cacheWriteTokens===void 0&&(n.rows.cacheWriteTokens=0),f.inputTokens!==void 0&&(n.rows.inputTokens+=f.inputTokens),f.outputTokens!==void 0&&(n.rows.outputTokens+=f.outputTokens),f.cacheReadTokens!==void 0&&(n.rows.cacheReadTokens+=f.cacheReadTokens),f.cacheWriteTokens!==void 0&&(n.rows.cacheWriteTokens+=f.cacheWriteTokens)}}const s=[];for(const i of e.values())i.rows.sessionCount=i.sessions.size,s.push({label:i.label,items:[i.rows],sessionCount:i.sessions.size});return{kind:"grouped",groups:s,currency:S}}const j=(e,s)=>{e._sessions===void 0&&(e._sessions=new Set),e._sessions.add(s),e.sessionCount=e._sessions.size},G=e=>{delete e._sessions},W=(e,s,i)=>{const u=B(s.ts);let n=e.get(u);n===void 0&&(n={bucket:u,costAmount:0,deltaCost:0,sessionCount:0},e.set(u,n)),n.costAmount+=i,n.deltaCost+=i,j(n,s.sessionId),t.tokens===!0&&(n.inputTokens===void 0||(s.inputTokens??0)>n.inputTokens)&&(n.inputTokens=s.inputTokens??n.inputTokens??0)};if(t.loc===!0&&t.bucket!==void 0){const e=new Set;for(const o of r)e.add(o.sessionId);const s=new Map;for(const o of r)s.set(o.sessionId,o);const i=(o,d)=>{let g=o.get(d);return g===void 0&&(g={bucket:d,costAmount:0,deltaCost:0,sessionCount:0,linesAdded:0,linesRemoved:0},o.set(d,g)),(g.linesAdded??void 0)===void 0&&(g.linesAdded=0),(g.linesRemoved??void 0)===void 0&&(g.linesRemoved=0),g},u=(o,d)=>{o.linesAdded=(o.linesAdded??0)+d.linesAdded,o.linesRemoved=(o.linesRemoved??0)+d.linesRemoved,o._sessions===void 0&&(o._sessions=new Set),o._sessions.add(d.sessionId),o.sessionCount=o._sessions.size},n=o=>{delete o._sessions},l=y??[];if(t.by==="filetype"){const o=new Map,d=new Set;for(const p of l){if(!e.has(p.sessionId)||a!==void 0&&new Date(p.ts)<a)continue;let v=o.get(p.filetype);v===void 0&&(v={label:p.filetype,buckets:new Map,sessions:new Set},o.set(p.filetype,v));const T=i(v.buckets,B(p.ts));u(T,p),v.sessions.add(p.sessionId),d.add(p.sessionId)}const g=[];for(const p of o.values()){const v=Array.from(p.buckets.values());for(const T of v)n(T);v.sort(M),v.length>0&&g.push({label:p.label,items:v,sessionCount:p.sessions.size})}return{kind:"timeSeriesGrouped",groups:g,currency:S,totalSessions:d.size}}if(t.by!==void 0){const o=new Map;for(const g of l){if(!e.has(g.sessionId)||a!==void 0&&new Date(g.ts)<a)continue;const p=s.get(g.sessionId);if(p===void 0)continue;const v=E(p);let T=o.get(v);T===void 0&&(T={label:v,buckets:new Map,sessions:new Set},o.set(v,T));const N=i(T.buckets,B(g.ts));u(N,g),T.sessions.add(g.sessionId)}const d=[];for(const g of o.values()){const p=Array.from(g.buckets.values());for(const v of p)n(v);p.sort(M),p.length>0&&d.push({label:g.label,items:p,sessionCount:g.sessions.size})}return{kind:"timeSeriesGrouped",groups:d,currency:S}}const m=new Map,f=new Set;for(const o of l){if(!e.has(o.sessionId)||a!==void 0&&new Date(o.ts)<a)continue;const d=i(m,B(o.ts));u(d,o),f.add(o.sessionId)}const b=Array.from(m.values());for(const o of b)n(o);return b.sort(M),{kind:"timeSeries",timeSeries:b,currency:S,totalSessions:f.size}}if(t.by!==void 0&&t.bucket!==void 0){const e=new Map,s=u=>{const n=E(u);let l=e.get(n);return l===void 0&&(l={label:n,buckets:new Map,sessions:new Set},e.set(n,l)),l};for(const u of r){const n=A.get(u.sessionId);if(n===void 0||n.length===0)continue;const l=s(u),m=l.buckets;l.sessions.add(u.sessionId);const f=n[0];if(f===void 0)continue;let b=f.cumulativeCost;for(let o=1;o<n.length;o++){const d=n[o];if(d===void 0)continue;const g=Math.max(0,d.cumulativeCost-b);b=d.cumulativeCost,!(a!==void 0&&new Date(d.ts)<a)&&W(m,d,g)}}const i=[];for(const u of e.values()){const n=Array.from(u.buckets.values());for(const l of n)G(l);n.sort(M),n.length>0&&i.push({label:u.label,items:n,sessionCount:u.sessions.size})}return{kind:"timeSeriesGrouped",groups:i,currency:S}}const z=new Map,O=new Set;for(const e of r){const s=A.get(e.sessionId);if(s===void 0||s.length===0)continue;const i=s[0];if(i===void 0)continue;let u=i.cumulativeCost,n=!1;for(let l=1;l<s.length;l++){const m=s[l];if(m===void 0)continue;const f=Math.max(0,m.cumulativeCost-u);u=m.cumulativeCost,!(a!==void 0&&new Date(m.ts)<a)&&(W(z,m,f),n=!0)}n&&O.add(e.sessionId)}const _=Array.from(z.values());for(const e of _)G(e);return _.sort(M),{kind:"timeSeries",timeSeries:_,currency:S,totalSessions:O.size}}export{X as aggregate,P as applyFilters,V as parseSince};
|
|
1
|
+
import{relative as H,resolve as R,sep as $}from"node:path";import{homedir as L}from"node:os";import{realpathSync as q}from"node:fs";function X(w){const c=w.match(/^(\d+)\s*([dhmwy])$/i);if(c!==null){const y=c[1],a=c[2];if(y===void 0||a===void 0)throw new Error(`invalid since spec: ${w}`);const h=parseInt(y,10),k=a.toLowerCase(),r=new Date;return k==="d"?r.setDate(r.getDate()-h):k==="h"?r.setHours(r.getHours()-h):k==="w"?r.setDate(r.getDate()-h*7):k==="m"?r.setMonth(r.getMonth()-h):k==="y"&&r.setFullYear(r.getFullYear()-h),r}const t=new Date(w);if(Number.isNaN(t.getTime()))throw new Error(`invalid since spec: ${w}`);return t}function P(w){const c=w.locByFiletype;if(c===void 0)return 0;let t=0;for(const y of Object.keys(c)){const a=c[y];a!==void 0&&(t+=a.added-a.removed)}return t}const I=new Map;function D(w){if(I.has(w))return I.get(w);try{const c=q(w);return I.set(w,c),c}catch{return I.set(w,w),w}}function Y(w,c){let t=w;if(c.since!==void 0){const h=c.since.getTime(),k=[];for(const r of t)new Date(r.updatedAt).getTime()<h||k.push(r);t=k}if(c.dir!==void 0){const h=D(R(c.dir)),k=[];for(const r of t)r.cwd===void 0||r.cwd===""||(r.cwd===h||r.cwd.startsWith(h+$))&&k.push(r);t=k}if(c.host!==void 0&&c.host!=="all"){const h=c.host,k=[];for(const r of t)h==="local"?(!r.importedFromMachine||r.upstreamSessionId)&&k.push(r):r.importedFromMachine===h&&!r.upstreamSessionId&&k.push(r);t=k}if(c.interactive!==void 0){const h=c.interactive,k=[];for(const r of t)r.interactive===h&&k.push(r);t=k}const y=c.min??0,a=[];for(const h of t){let k;c.minMetric==="tokens"?k=h.contextTokens:c.minMetric==="loc"?k=P(h):k=h.costAmount,k>y&&a.push(h)}return a}function K(w){return w.dir!==void 0?R(w.dir):R(L())}function J(w,c,t){if(w===void 0||w==="")return"<unknown>";const y=D(R(w));if(c===void 0){const S=D(R(L()));return y===S?"~":y.startsWith(S+"/")?"~/"+y.slice(S.length+1):y}const a=D(R(t));let h=H(a,y);if(h===""||h===".")return"<root>";if(h.startsWith(".."))return"<unknown>";const k=h.split("/");if(k.length===0)return"<root>";const r=Math.min(c,k.length),C=k.slice(0,r);return C.length===0?"<root>":C.join("/")}function Z(w,c,t={},y){let a=t.since;if(a===void 0&&t.bucket!==void 0){const e=new Date;t.bucket==="hour"?(e.setHours(e.getHours()-24),a=e):t.bucket==="day"||t.bucket==="weekday"?(e.setDate(e.getDate()-30),a=e):t.bucket==="week"?(e.setMonth(e.getMonth()-6),a=e):t.bucket==="month"&&(e.setFullYear(e.getFullYear()-2),a=e)}if(!(a!==void 0||t.bucket!==void 0||t.tokens===!0||t.loc===!0||t.by!==void 0||t.dir!==void 0||t.interactive!==void 0)){let e=0;for(const i of w)e+=i.costAmount;let s="";for(const i of w){s=i.costCurrency;break}return{kind:"total",row:{label:"All sessions",costAmount:e,sessionCount:w.length},currency:s}}const k={since:a,dir:t.dir,interactive:t.interactive,min:t.min,minMetric:t.loc===!0?"loc":t.tokens===!0?"tokens":"cost"},r=Y(w,k),C=new Map;if(c!==void 0)for(const e of c){const s=C.get(e.sessionId);s===void 0?C.set(e.sessionId,[e]):s.push(e)}let S="";if(c!==void 0&&c.length>0)for(const e of c){S=e.currency;break}else if(r.length>0)for(const e of r){S=e.costCurrency;break}if(t.by==="filetype"&&t.bucket===void 0){const e=new Map,s=new Set;for(const u of r){const n=u.locByFiletype;if(n===void 0)continue;let l=!1;for(const m of Object.keys(n)){const f=n[m];if(f===void 0)continue;let b=e.get(m);b===void 0&&(b={added:0,removed:0,sessions:new Set},e.set(m,b)),b.added+=f.added,b.removed+=f.removed,(f.added>0||f.removed>0)&&(b.sessions.add(u.sessionId),l=!0)}l&&s.add(u.sessionId)}const i=[];for(const[u,n]of e){const l={label:u,costAmount:0,sessionCount:n.sessions.size,linesAdded:n.added,linesRemoved:n.removed};i.push({label:u,items:[l],sessionCount:n.sessions.size})}return{kind:"grouped",groups:i,currency:S,totalSessions:s.size}}const E=e=>t.by==="dir"?J(e.cwd,t.depth,K(t)):t.by==="session"?e.sessionId.startsWith("hydra_session_")?e.sessionId.slice(14):e.sessionId:t.by==="model"?e.model===""?"<unknown>":e.model:t.by==="agent"?e.agentId===""?"<unknown>":e.agentId:"<all>",B=e=>{const s=new Date(e);if(Number.isNaN(s.getTime()))return"<invalid>";if(t.bucket==="hour"){const i=s.toLocaleDateString(void 0,{month:"2-digit",day:"2-digit"}),u=String(s.getHours()).padStart(2,"0");return`${i} ${u}:00`}if(t.bucket==="day")return s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"});if(t.bucket==="weekday")return s.toLocaleDateString(void 0,{weekday:"short"});if(t.bucket==="week"){const i=new Date(s),u=i.getDay(),n=i.getDate()-u+(u===0?-6:1);return i.setDate(n),i.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})}return t.bucket==="month"?s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit"}):s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})},x=new Map;if(t.bucket==="weekday"){const e=new Date(2024,0,1);for(let s=0;s<7;s++){const i=new Date(e);i.setDate(e.getDate()+s),x.set(i.toLocaleDateString(void 0,{weekday:"short"}),s)}}const M=(e,s)=>{if(t.bucket==="weekday"){const i=x.get(e.bucket)??7,u=x.get(s.bucket)??7;if(i!==u)return i-u}return e.bucket.localeCompare(s.bucket)},F=new Map;for(const e of r)F.set(e.sessionId,e);const A=new Map;if(c!==void 0){for(const e of c){if(!F.has(e.sessionId))continue;const s=A.get(e.sessionId);s===void 0?A.set(e.sessionId,[e]):s.push(e)}for(const e of A.values())e.sort((s,i)=>s.ts.localeCompare(i.ts))}if(t.by===void 0&&t.bucket===void 0){let e=0,s=0,i=0,u=0,n=0,l=0;for(const f of r){const b=A.get(f.sessionId);if(b===void 0||b.length<2)e+=f.costAmount,l++;else{let d=b[0].cumulativeCost,g=!1;for(let p=1;p<b.length;p++){const v=b[p];if(v===void 0)continue;const T=Math.max(0,v.cumulativeCost-d);d=v.cumulativeCost,!(a!==void 0&&new Date(v.ts)<a)&&(e+=T,g=!0)}g&&l++}if(t.tokens===!0){const o=C.get(f.sessionId);if(o!==void 0)for(const d of o)d.inputTokens!==void 0&&(s+=d.inputTokens),d.outputTokens!==void 0&&(i+=d.outputTokens),d.cacheReadTokens!==void 0&&(u+=d.cacheReadTokens),d.cacheWriteTokens!==void 0&&(n+=d.cacheWriteTokens)}}const m={label:"All sessions",costAmount:e,deltaCost:e,sessionCount:l};if(t.tokens===!0&&(m.inputTokens=s,m.outputTokens=i,m.cacheReadTokens=u,m.cacheWriteTokens=n),t.loc===!0){let f=0,b=0;for(const o of r){const d=o.locByFiletype;if(d!==void 0)for(const g of Object.keys(d)){const p=d[g];p!==void 0&&(f+=p.added,b+=p.removed)}}m.linesAdded=f,m.linesRemoved=b}return{kind:"total",row:m,currency:S}}if(t.by!==void 0&&t.bucket===void 0){const e=new Map;for(const i of r){const u=E(i);let n=e.get(u);if(n===void 0&&(n={label:u,rows:{label:u,costAmount:0,deltaCost:0,sessionCount:0},sessions:new Set},e.set(u,n)),t.tokens===!0&&(n.rows.inputTokens===void 0&&(n.rows.inputTokens=0),n.rows.inputTokens+=i.contextTokens),t.loc===!0){const m=i.locByFiletype;if(m!==void 0){n.rows.linesAdded===void 0&&(n.rows.linesAdded=0),n.rows.linesRemoved===void 0&&(n.rows.linesRemoved=0);for(const f of Object.keys(m)){const b=m[f];b!==void 0&&(n.rows.linesAdded+=b.added,n.rows.linesRemoved+=b.removed)}}}const l=A.get(i.sessionId);if(l===void 0||l.length<2)n.rows.costAmount+=i.costAmount,n.rows.deltaCost+=i.costAmount,n.sessions.add(i.sessionId);else{let f=l[0].cumulativeCost,b=!1;for(let o=1;o<l.length;o++){const d=l[o];if(d===void 0)continue;const g=Math.max(0,d.cumulativeCost-f);f=d.cumulativeCost,!(a!==void 0&&new Date(d.ts)<a)&&(n.rows.costAmount+=g,n.rows.deltaCost+=g,b=!0)}b&&n.sessions.add(i.sessionId)}if(t.tokens===!0){const m=C.get(i.sessionId);if(m!==void 0)for(const f of m)n.rows.inputTokens===void 0&&(n.rows.inputTokens=0),n.rows.outputTokens===void 0&&(n.rows.outputTokens=0),n.rows.cacheReadTokens===void 0&&(n.rows.cacheReadTokens=0),n.rows.cacheWriteTokens===void 0&&(n.rows.cacheWriteTokens=0),f.inputTokens!==void 0&&(n.rows.inputTokens+=f.inputTokens),f.outputTokens!==void 0&&(n.rows.outputTokens+=f.outputTokens),f.cacheReadTokens!==void 0&&(n.rows.cacheReadTokens+=f.cacheReadTokens),f.cacheWriteTokens!==void 0&&(n.rows.cacheWriteTokens+=f.cacheWriteTokens)}}const s=[];for(const i of e.values())i.rows.sessionCount=i.sessions.size,s.push({label:i.label,items:[i.rows],sessionCount:i.sessions.size});return{kind:"grouped",groups:s,currency:S}}const j=(e,s)=>{e._sessions===void 0&&(e._sessions=new Set),e._sessions.add(s),e.sessionCount=e._sessions.size},G=e=>{delete e._sessions},W=(e,s,i)=>{const u=B(s.ts);let n=e.get(u);n===void 0&&(n={bucket:u,costAmount:0,deltaCost:0,sessionCount:0},e.set(u,n)),n.costAmount+=i,n.deltaCost+=i,j(n,s.sessionId),t.tokens===!0&&(n.inputTokens===void 0||(s.inputTokens??0)>n.inputTokens)&&(n.inputTokens=s.inputTokens??n.inputTokens??0)};if(t.loc===!0&&t.bucket!==void 0){const e=new Set;for(const o of r)e.add(o.sessionId);const s=new Map;for(const o of r)s.set(o.sessionId,o);const i=(o,d)=>{let g=o.get(d);return g===void 0&&(g={bucket:d,costAmount:0,deltaCost:0,sessionCount:0,linesAdded:0,linesRemoved:0},o.set(d,g)),(g.linesAdded??void 0)===void 0&&(g.linesAdded=0),(g.linesRemoved??void 0)===void 0&&(g.linesRemoved=0),g},u=(o,d)=>{o.linesAdded=(o.linesAdded??0)+d.linesAdded,o.linesRemoved=(o.linesRemoved??0)+d.linesRemoved,o._sessions===void 0&&(o._sessions=new Set),o._sessions.add(d.sessionId),o.sessionCount=o._sessions.size},n=o=>{delete o._sessions},l=y??[];if(t.by==="filetype"){const o=new Map,d=new Set;for(const p of l){if(!e.has(p.sessionId)||a!==void 0&&new Date(p.ts)<a)continue;let v=o.get(p.filetype);v===void 0&&(v={label:p.filetype,buckets:new Map,sessions:new Set},o.set(p.filetype,v));const T=i(v.buckets,B(p.ts));u(T,p),v.sessions.add(p.sessionId),d.add(p.sessionId)}const g=[];for(const p of o.values()){const v=Array.from(p.buckets.values());for(const T of v)n(T);v.sort(M),v.length>0&&g.push({label:p.label,items:v,sessionCount:p.sessions.size})}return{kind:"timeSeriesGrouped",groups:g,currency:S,totalSessions:d.size}}if(t.by!==void 0){const o=new Map;for(const g of l){if(!e.has(g.sessionId)||a!==void 0&&new Date(g.ts)<a)continue;const p=s.get(g.sessionId);if(p===void 0)continue;const v=E(p);let T=o.get(v);T===void 0&&(T={label:v,buckets:new Map,sessions:new Set},o.set(v,T));const N=i(T.buckets,B(g.ts));u(N,g),T.sessions.add(g.sessionId)}const d=[];for(const g of o.values()){const p=Array.from(g.buckets.values());for(const v of p)n(v);p.sort(M),p.length>0&&d.push({label:g.label,items:p,sessionCount:g.sessions.size})}return{kind:"timeSeriesGrouped",groups:d,currency:S}}const m=new Map,f=new Set;for(const o of l){if(!e.has(o.sessionId)||a!==void 0&&new Date(o.ts)<a)continue;const d=i(m,B(o.ts));u(d,o),f.add(o.sessionId)}const b=Array.from(m.values());for(const o of b)n(o);return b.sort(M),{kind:"timeSeries",timeSeries:b,currency:S,totalSessions:f.size}}if(t.by!==void 0&&t.bucket!==void 0){const e=new Map,s=u=>{const n=E(u);let l=e.get(n);return l===void 0&&(l={label:n,buckets:new Map,sessions:new Set},e.set(n,l)),l};for(const u of r){const n=A.get(u.sessionId);if(n===void 0||n.length===0)continue;const l=s(u),m=l.buckets;l.sessions.add(u.sessionId);const f=n[0];if(f===void 0)continue;let b=f.cumulativeCost;for(let o=1;o<n.length;o++){const d=n[o];if(d===void 0)continue;const g=Math.max(0,d.cumulativeCost-b);b=d.cumulativeCost,!(a!==void 0&&new Date(d.ts)<a)&&W(m,d,g)}}const i=[];for(const u of e.values()){const n=Array.from(u.buckets.values());for(const l of n)G(l);n.sort(M),n.length>0&&i.push({label:u.label,items:n,sessionCount:u.sessions.size})}return{kind:"timeSeriesGrouped",groups:i,currency:S}}const z=new Map,O=new Set;for(const e of r){const s=A.get(e.sessionId);if(s===void 0||s.length===0)continue;const i=s[0];if(i===void 0)continue;let u=i.cumulativeCost,n=!1;for(let l=1;l<s.length;l++){const m=s[l];if(m===void 0)continue;const f=Math.max(0,m.cumulativeCost-u);u=m.cumulativeCost,!(a!==void 0&&new Date(m.ts)<a)&&(W(z,m,f),n=!0)}n&&O.add(e.sessionId)}const _=Array.from(z.values());for(const e of _)G(e);return _.sort(M),{kind:"timeSeries",timeSeries:_,currency:S,totalSessions:O.size}}export{Z as aggregate,Y as applyFilters,X as parseSince};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydra-acp/budgeter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "Cost-budget transformer extension for hydra-acp — warns on soft limit, rejects further prompts/sessions on hard limit.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"watch": "tsup --watch",
|
|
23
23
|
"start": "node dist/index.js",
|
|
24
24
|
"dev": "tsup && node dist/index.js",
|
|
25
|
-
"test": "node
|
|
25
|
+
"test": "node scripts/run-tests.mjs",
|
|
26
26
|
"lint": "tsc -p . --noEmit",
|
|
27
27
|
"prepublishOnly": "npm run build && npm test"
|
|
28
28
|
},
|
|
29
29
|
"engines": {
|
|
30
|
-
"node": ">=
|
|
30
|
+
"node": ">=22.5.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"ws": "^8.20.0"
|