@hydra-acp/budgeter 0.1.7 → 0.1.9

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.
@@ -1 +1 @@
1
- import{relative as G,resolve as w}from"node:path";import{homedir as W}from"node:os";import{realpathSync as E}from"node:fs";function P(c){const d=c.match(/^(\d+)\s*([dhmwy])$/i);if(d!==null){const a=d[1],h=d[2];if(a===void 0||h===void 0)throw new Error(`invalid since spec: ${c}`);const k=parseInt(a,10),r=h.toLowerCase(),u=new Date;return r==="d"?u.setDate(u.getDate()-k):r==="h"?u.setHours(u.getHours()-k):r==="w"?u.setDate(u.getDate()-k*7):r==="m"?u.setMonth(u.getMonth()-k):r==="y"&&u.setFullYear(u.getFullYear()-k),u}const n=new Date(c);if(Number.isNaN(n.getTime()))throw new Error(`invalid since spec: ${c}`);return n}const v=new Map;function C(c){if(v.has(c))return v.get(c);try{const d=E(c);return v.set(c,d),d}catch{return v.set(c,c),c}}function F(c,d){let n=c;if(d.since!==void 0){const r=d.since.getTime(),u=[];for(const f of n)new Date(f.updatedAt).getTime()<r||u.push(f);n=u}if(d.dir!==void 0){const r=C(w(d.dir)),u=[];for(const f of n)f.cwd===void 0||f.cwd===""||(f.cwd.startsWith(r+"/")||f.cwd===r)&&u.push(f);n=u}if(d.interactive!==void 0){const r=d.interactive,u=[];for(const f of n)f.interactive===r&&u.push(f);n=u}const a=d.min??0,h=d.minMetric==="tokens",k=[];for(const r of n)(h?r.contextTokens:r.costAmount)>a&&k.push(r);return k}function O(c){return c.dir!==void 0?w(c.dir):w(W())}function L(c,d,n){if(c===void 0||c==="")return"<unknown>";const a=C(w(c));if(d===void 0){const p=C(w(W()));return a===p?"~":a.startsWith(p+"/")?"~/"+a.slice(p.length+1):a}const h=C(w(n));let k=G(h,a);if(k===""||k===".")return"<root>";if(k.startsWith(".."))return"<unknown>";const r=k.split("/");if(r.length===0)return"<root>";const u=Math.min(d,r.length),f=r.slice(0,u);return f.length===0?"<root>":f.join("/")}function Y(c,d,n={}){let a=n.since;if(a===void 0&&n.bucket!==void 0){const e=new Date;n.bucket==="hour"?(e.setHours(e.getHours()-24),a=e):n.bucket==="day"?(e.setDate(e.getDate()-30),a=e):n.bucket==="week"?(e.setMonth(e.getMonth()-6),a=e):n.bucket==="month"&&(e.setFullYear(e.getFullYear()-2),a=e)}if(!(a!==void 0||n.bucket!==void 0||n.tokens===!0||n.by!==void 0||n.dir!==void 0||n.interactive!==void 0)){let e=0;for(const i of c)e+=i.costAmount;let s="";for(const i of c){s=i.costCurrency;break}return{kind:"total",row:{label:"All sessions",costAmount:e,sessionCount:c.length},currency:s}}const k={since:a,dir:n.dir,interactive:n.interactive,min:n.min,minMetric:n.tokens===!0?"tokens":"cost"},r=F(c,k),u=new Map;if(d!==void 0)for(const e of d){const s=u.get(e.sessionId);s===void 0?u.set(e.sessionId,[e]):s.push(e)}let f="";if(d!==void 0&&d.length>0)for(const e of d){f=e.currency;break}else if(r.length>0)for(const e of r){f=e.costCurrency;break}const p=e=>n.by==="dir"?L(e.cwd,n.depth,O(n)):n.by==="session"?e.sessionId.startsWith("hydra_session_")?e.sessionId.slice(14):e.sessionId:n.by==="model"?e.model===""?"<unknown>":e.model:n.by==="agent"?e.agentId===""?"<unknown>":e.agentId:"<all>",R=e=>{const s=new Date(e);if(Number.isNaN(s.getTime()))return"<invalid>";if(n.bucket==="hour"){const i=s.toLocaleDateString(void 0,{month:"2-digit",day:"2-digit"}),o=String(s.getHours()).padStart(2,"0");return`${i} ${o}:00`}if(n.bucket==="day")return s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"});if(n.bucket==="week"){const i=new Date(s),o=i.getDay(),t=i.getDate()-o+(o===0?-6:1);return i.setDate(t),i.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})}return n.bucket==="month"?s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit"}):s.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})};if(n.by===void 0&&n.bucket===void 0){let e=0,s=0,i=0,o=0,t=0,l=0;for(const b of r){e+=b.costAmount;const T=u.get(b.sessionId);if(T!==void 0)for(const m of T)s+=m.deltaCost,n.tokens===!0&&(m.inputTokens!==void 0&&(i+=m.inputTokens),m.outputTokens!==void 0&&(o+=m.outputTokens),m.cacheReadTokens!==void 0&&(t+=m.cacheReadTokens),m.cacheWriteTokens!==void 0&&(l+=m.cacheWriteTokens))}const g={label:"All sessions",costAmount:e,deltaCost:s,sessionCount:r.length};return n.tokens===!0&&(g.inputTokens=i,g.outputTokens=o,g.cacheReadTokens=t,g.cacheWriteTokens=l),{kind:"total",row:g,currency:f}}if(n.by!==void 0&&n.bucket===void 0){const e=new Map;for(const i of r){const o=p(i);let t=e.get(o);t===void 0&&(t={label:o,rows:{label:o,costAmount:0,deltaCost:0,sessionCount:0}},e.set(o,t)),t.rows.costAmount+=i.costAmount,t.rows.sessionCount=(t.rows.sessionCount??0)+1,n.tokens===!0&&(t.rows.inputTokens===void 0&&(t.rows.inputTokens=0),t.rows.inputTokens+=i.contextTokens);const l=u.get(i.sessionId);if(l!==void 0)for(const g of l)t.rows.deltaCost+=g.deltaCost,n.tokens===!0&&(t.rows.inputTokens===void 0&&(t.rows.inputTokens=0),t.rows.outputTokens===void 0&&(t.rows.outputTokens=0),t.rows.cacheReadTokens===void 0&&(t.rows.cacheReadTokens=0),t.rows.cacheWriteTokens===void 0&&(t.rows.cacheWriteTokens=0),g.inputTokens!==void 0&&(t.rows.inputTokens+=g.inputTokens),g.outputTokens!==void 0&&(t.rows.outputTokens+=g.outputTokens),g.cacheReadTokens!==void 0&&(t.rows.cacheReadTokens+=g.cacheReadTokens),g.cacheWriteTokens!==void 0&&(t.rows.cacheWriteTokens+=g.cacheWriteTokens))}const s=[];for(const i of e.values())s.push({label:i.label,items:[i.rows]});return{kind:"grouped",groups:s,currency:f}}const _=(e,s)=>{n.tokens===!0&&(e.inputTokens===void 0&&(e.inputTokens=0),e.inputTokens+=s.contextTokens)},M=new Map;for(const e of r)M.set(e.sessionId,e);const y=new Map;if(d!==void 0){for(const e of d){if(!M.has(e.sessionId))continue;const s=y.get(e.sessionId);s===void 0?y.set(e.sessionId,[e]):s.push(e)}for(const e of y.values())e.sort((s,i)=>s.ts.localeCompare(i.ts))}const D=(e,s)=>{e._sessions===void 0&&(e._sessions=new Set),e._sessions.add(s),e.sessionCount=e._sessions.size},B=e=>{delete e._sessions},I=(e,s,i)=>{const o=R(s.ts);let t=e.get(o);t===void 0&&(t={bucket:o,costAmount:0,deltaCost:0,sessionCount:0},e.set(o,t)),t.costAmount+=i,t.deltaCost+=i,D(t,s.sessionId),n.tokens===!0&&(t.inputTokens===void 0||(s.inputTokens??0)>t.inputTokens)&&(t.inputTokens=s.inputTokens??t.inputTokens??0)},x=(e,s)=>{const i=R(s.updatedAt);let o=e.get(i);o===void 0&&(o={bucket:i,costAmount:0,deltaCost:0,sessionCount:0},e.set(i,o)),o.costAmount+=s.costAmount,o.deltaCost+=s.costAmount,D(o,s.sessionId),_(o,s)};if(n.by!==void 0&&n.bucket!==void 0){const e=new Map,s=o=>{const t=p(o);let l=e.get(t);return l===void 0&&(l={label:t,buckets:new Map},e.set(t,l)),l.buckets};for(const o of r){const t=s(o),l=y.get(o.sessionId);if(l!==void 0&&l.length>0){let g=l[0].cumulativeCost;for(let b=1;b<l.length;b++){const T=l[b],m=Math.max(0,T.cumulativeCost-g);g=T.cumulativeCost,!(a!==void 0&&new Date(T.ts)<a)&&I(t,T,m)}}else x(t,o)}const i=[];for(const o of e.values()){const t=Array.from(o.buckets.values());for(const l of t)B(l);t.sort((l,g)=>l.bucket.localeCompare(g.bucket)),t.length>0&&i.push({label:o.label,items:t})}return{kind:"timeSeriesGrouped",groups:i,currency:f}}const S=new Map;for(const e of r){const s=y.get(e.sessionId);if(s!==void 0&&s.length>0){let i=s[0].cumulativeCost;for(let o=1;o<s.length;o++){const t=s[o],l=Math.max(0,t.cumulativeCost-i);i=t.cumulativeCost,!(a!==void 0&&new Date(t.ts)<a)&&I(S,t,l)}}else x(S,e)}const A=Array.from(S.values());for(const e of A)B(e);return A.sort((e,s)=>e.bucket.localeCompare(s.bucket)),{kind:"timeSeries",timeSeries:A,currency:f}}export{Y as aggregate,F as applyFilters,P as parseSince};
1
+ import{relative as F,resolve as C}from"node:path";import{homedir as L}from"node:os";import{realpathSync as j}from"node:fs";function K(m){const a=m.match(/^(\d+)\s*([dhmwy])$/i);if(a!==null){const v=a[1],l=a[2];if(v===void 0||l===void 0)throw new Error(`invalid since spec: ${m}`);const k=parseInt(v,10),g=l.toLowerCase(),i=new Date;return g==="d"?i.setDate(i.getDate()-k):g==="h"?i.setHours(i.getHours()-k):g==="w"?i.setDate(i.getDate()-k*7):g==="m"?i.setMonth(i.getMonth()-k):g==="y"&&i.setFullYear(i.getFullYear()-k),i}const t=new Date(m);if(Number.isNaN(t.getTime()))throw new Error(`invalid since spec: ${m}`);return t}function z(m){const a=m.locByLanguage;if(a===void 0)return 0;let t=0;for(const v of Object.keys(a)){const l=a[v];l!==void 0&&(t+=l.added-l.removed)}return t}const M=new Map;function B(m){if(M.has(m))return M.get(m);try{const a=j(m);return M.set(m,a),a}catch{return M.set(m,m),m}}function N(m,a){let t=m;if(a.since!==void 0){const k=a.since.getTime(),g=[];for(const i of t)new Date(i.updatedAt).getTime()<k||g.push(i);t=g}if(a.dir!==void 0){const k=B(C(a.dir)),g=[];for(const i of t)i.cwd===void 0||i.cwd===""||(i.cwd.startsWith(k+"/")||i.cwd===k)&&g.push(i);t=g}if(a.host!==void 0&&a.host!=="all"){const k=a.host,g=[];for(const i of t)k==="local"?(!i.importedFromMachine||i.upstreamSessionId)&&g.push(i):i.importedFromMachine===k&&!i.upstreamSessionId&&g.push(i);t=g}if(a.interactive!==void 0){const k=a.interactive,g=[];for(const i of t)i.interactive===k&&g.push(i);t=g}const v=a.min??0,l=[];for(const k of t){let g;a.minMetric==="tokens"?g=k.contextTokens:a.minMetric==="loc"?g=z(k):g=k.costAmount,g>v&&l.push(k)}return l}function H(m){return m.dir!==void 0?C(m.dir):C(L())}function $(m,a,t){if(m===void 0||m==="")return"<unknown>";const v=B(C(m));if(a===void 0){const T=B(C(L()));return v===T?"~":v.startsWith(T+"/")?"~/"+v.slice(T.length+1):v}const l=B(C(t));let k=F(l,v);if(k===""||k===".")return"<root>";if(k.startsWith(".."))return"<unknown>";const g=k.split("/");if(g.length===0)return"<root>";const i=Math.min(a,g.length),S=g.slice(0,i);return S.length===0?"<root>":S.join("/")}function J(m,a,t={},v){let l=t.since;if(l===void 0&&t.bucket!==void 0){const e=new Date;t.bucket==="hour"?(e.setHours(e.getHours()-24),l=e):t.bucket==="day"?(e.setDate(e.getDate()-30),l=e):t.bucket==="week"?(e.setMonth(e.getMonth()-6),l=e):t.bucket==="month"&&(e.setFullYear(e.getFullYear()-2),l=e)}if(!(l!==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 r of m)e+=r.costAmount;let o="";for(const r of m){o=r.costCurrency;break}return{kind:"total",row:{label:"All sessions",costAmount:e,sessionCount:m.length},currency:o}}const g={since:l,dir:t.dir,interactive:t.interactive,min:t.min,minMetric:t.loc===!0?"loc":t.tokens===!0?"tokens":"cost"},i=N(m,g),S=new Map;if(a!==void 0)for(const e of a){const o=S.get(e.sessionId);o===void 0?S.set(e.sessionId,[e]):o.push(e)}let T="";if(a!==void 0&&a.length>0)for(const e of a){T=e.currency;break}else if(i.length>0)for(const e of i){T=e.costCurrency;break}if(t.by==="language"&&t.bucket===void 0){const e=new Map,o=new Set;for(const u of i){const n=u.locByLanguage;if(n===void 0)continue;let f=!1;for(const d of Object.keys(n)){const w=n[d];if(w===void 0)continue;let s=e.get(d);s===void 0&&(s={added:0,removed:0,sessions:new Set},e.set(d,s)),s.added+=w.added,s.removed+=w.removed,(w.added>0||w.removed>0)&&(s.sessions.add(u.sessionId),f=!0)}f&&o.add(u.sessionId)}const r=[];for(const[u,n]of e){const f={label:u,costAmount:0,sessionCount:n.sessions.size,linesAdded:n.added,linesRemoved:n.removed};r.push({label:u,items:[f]})}return{kind:"grouped",groups:r,currency:T,totalSessions:o.size}}const I=e=>t.by==="dir"?$(e.cwd,t.depth,H(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>",R=e=>{const o=new Date(e);if(Number.isNaN(o.getTime()))return"<invalid>";if(t.bucket==="hour"){const r=o.toLocaleDateString(void 0,{month:"2-digit",day:"2-digit"}),u=String(o.getHours()).padStart(2,"0");return`${r} ${u}:00`}if(t.bucket==="day")return o.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"});if(t.bucket==="week"){const r=new Date(o),u=r.getDay(),n=r.getDate()-u+(u===0?-6:1);return r.setDate(n),r.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})}return t.bucket==="month"?o.toLocaleDateString(void 0,{year:"numeric",month:"2-digit"}):o.toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit"})};if(t.by===void 0&&t.bucket===void 0){let e=0,o=0,r=0,u=0,n=0,f=0;for(const w of i){e+=w.costAmount;const s=S.get(w.sessionId);if(s!==void 0)for(const c of s)o+=c.deltaCost,t.tokens===!0&&(c.inputTokens!==void 0&&(r+=c.inputTokens),c.outputTokens!==void 0&&(u+=c.outputTokens),c.cacheReadTokens!==void 0&&(n+=c.cacheReadTokens),c.cacheWriteTokens!==void 0&&(f+=c.cacheWriteTokens))}const d={label:"All sessions",costAmount:e,deltaCost:o,sessionCount:i.length};if(t.tokens===!0&&(d.inputTokens=r,d.outputTokens=u,d.cacheReadTokens=n,d.cacheWriteTokens=f),t.loc===!0){let w=0,s=0;for(const c of i){const b=c.locByLanguage;if(b!==void 0)for(const p of Object.keys(b)){const h=b[p];h!==void 0&&(w+=h.added,s+=h.removed)}}d.linesAdded=w,d.linesRemoved=s}return{kind:"total",row:d,currency:T}}if(t.by!==void 0&&t.bucket===void 0){const e=new Map;for(const r of i){const u=I(r);let n=e.get(u);if(n===void 0&&(n={label:u,rows:{label:u,costAmount:0,deltaCost:0,sessionCount:0}},e.set(u,n)),n.rows.costAmount+=r.costAmount,n.rows.sessionCount=(n.rows.sessionCount??0)+1,t.tokens===!0&&(n.rows.inputTokens===void 0&&(n.rows.inputTokens=0),n.rows.inputTokens+=r.contextTokens),t.loc===!0){const d=r.locByLanguage;if(d!==void 0){n.rows.linesAdded===void 0&&(n.rows.linesAdded=0),n.rows.linesRemoved===void 0&&(n.rows.linesRemoved=0);for(const w of Object.keys(d)){const s=d[w];s!==void 0&&(n.rows.linesAdded+=s.added,n.rows.linesRemoved+=s.removed)}}}const f=S.get(r.sessionId);if(f!==void 0)for(const d of f)n.rows.deltaCost+=d.deltaCost,t.tokens===!0&&(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),d.inputTokens!==void 0&&(n.rows.inputTokens+=d.inputTokens),d.outputTokens!==void 0&&(n.rows.outputTokens+=d.outputTokens),d.cacheReadTokens!==void 0&&(n.rows.cacheReadTokens+=d.cacheReadTokens),d.cacheWriteTokens!==void 0&&(n.rows.cacheWriteTokens+=d.cacheWriteTokens))}const o=[];for(const r of e.values())o.push({label:r.label,items:[r.rows]});return{kind:"grouped",groups:o,currency:T}}const E=new Map;for(const e of i)E.set(e.sessionId,e);const A=new Map;if(a!==void 0){for(const e of a){if(!E.has(e.sessionId))continue;const o=A.get(e.sessionId);o===void 0?A.set(e.sessionId,[e]):o.push(e)}for(const e of A.values())e.sort((o,r)=>o.ts.localeCompare(r.ts))}const O=(e,o)=>{e._sessions===void 0&&(e._sessions=new Set),e._sessions.add(o),e.sessionCount=e._sessions.size},_=e=>{delete e._sessions},G=(e,o,r)=>{const u=R(o.ts);let n=e.get(u);n===void 0&&(n={bucket:u,costAmount:0,deltaCost:0,sessionCount:0},e.set(u,n)),n.costAmount+=r,n.deltaCost+=r,O(n,o.sessionId),t.tokens===!0&&(n.inputTokens===void 0||(o.inputTokens??0)>n.inputTokens)&&(n.inputTokens=o.inputTokens??n.inputTokens??0)};if(t.loc===!0&&t.bucket!==void 0){const e=new Set;for(const s of i)e.add(s.sessionId);const o=new Map;for(const s of i)o.set(s.sessionId,s);const r=(s,c)=>{let b=s.get(c);return b===void 0&&(b={bucket:c,costAmount:0,deltaCost:0,sessionCount:0,linesAdded:0,linesRemoved:0},s.set(c,b)),(b.linesAdded??void 0)===void 0&&(b.linesAdded=0),(b.linesRemoved??void 0)===void 0&&(b.linesRemoved=0),b},u=(s,c)=>{s.linesAdded=(s.linesAdded??0)+c.linesAdded,s.linesRemoved=(s.linesRemoved??0)+c.linesRemoved,s._sessions===void 0&&(s._sessions=new Set),s._sessions.add(c.sessionId),s.sessionCount=s._sessions.size},n=s=>{delete s._sessions},f=v??[];if(t.by==="language"){const s=new Map,c=new Set;for(const p of f){if(!e.has(p.sessionId)||l!==void 0&&new Date(p.ts)<l)continue;let h=s.get(p.language);h===void 0&&(h={label:p.language,buckets:new Map},s.set(p.language,h));const y=r(h.buckets,R(p.ts));u(y,p),c.add(p.sessionId)}const b=[];for(const p of s.values()){const h=Array.from(p.buckets.values());for(const y of h)n(y);h.sort((y,x)=>y.bucket.localeCompare(x.bucket)),h.length>0&&b.push({label:p.label,items:h})}return{kind:"timeSeriesGrouped",groups:b,currency:T,totalSessions:c.size}}if(t.by!==void 0){const s=new Map;for(const b of f){if(!e.has(b.sessionId)||l!==void 0&&new Date(b.ts)<l)continue;const p=o.get(b.sessionId);if(p===void 0)continue;const h=I(p);let y=s.get(h);y===void 0&&(y={label:h,buckets:new Map},s.set(h,y));const x=r(y.buckets,R(b.ts));u(x,b)}const c=[];for(const b of s.values()){const p=Array.from(b.buckets.values());for(const h of p)n(h);p.sort((h,y)=>h.bucket.localeCompare(y.bucket)),p.length>0&&c.push({label:b.label,items:p})}return{kind:"timeSeriesGrouped",groups:c,currency:T}}const d=new Map;for(const s of f){if(!e.has(s.sessionId)||l!==void 0&&new Date(s.ts)<l)continue;const c=r(d,R(s.ts));u(c,s)}const w=Array.from(d.values());for(const s of w)n(s);return w.sort((s,c)=>s.bucket.localeCompare(c.bucket)),{kind:"timeSeries",timeSeries:w,currency:T}}if(t.by!==void 0&&t.bucket!==void 0){const e=new Map,o=u=>{const n=I(u);let f=e.get(n);return f===void 0&&(f={label:n,buckets:new Map},e.set(n,f)),f.buckets};for(const u of i){const n=A.get(u.sessionId);if(n===void 0||n.length===0)continue;const f=o(u),d=n[0];if(d===void 0)continue;let w=d.cumulativeCost;for(let s=1;s<n.length;s++){const c=n[s];if(c===void 0)continue;const b=Math.max(0,c.cumulativeCost-w);w=c.cumulativeCost,!(l!==void 0&&new Date(c.ts)<l)&&G(f,c,b)}}const r=[];for(const u of e.values()){const n=Array.from(u.buckets.values());for(const f of n)_(f);n.sort((f,d)=>f.bucket.localeCompare(d.bucket)),n.length>0&&r.push({label:u.label,items:n})}return{kind:"timeSeriesGrouped",groups:r,currency:T}}const W=new Map;for(const e of i){const o=A.get(e.sessionId);if(o===void 0||o.length===0)continue;const r=o[0];if(r===void 0)continue;let u=r.cumulativeCost;for(let n=1;n<o.length;n++){const f=o[n];if(f===void 0)continue;const d=Math.max(0,f.cumulativeCost-u);u=f.cumulativeCost,!(l!==void 0&&new Date(f.ts)<l)&&G(W,f,d)}}const D=Array.from(W.values());for(const e of D)_(e);return D.sort((e,o)=>e.bucket.localeCompare(o.bucket)),{kind:"timeSeries",timeSeries:D,currency:T}}export{J as aggregate,N as applyFilters,K as parseSince};
@@ -1,2 +1,2 @@
1
- import{readFileSync as m}from"node:fs";import{homedir as y}from"node:os";import{resolve as g}from"node:path";import{logger as E}from"../util/log.js";const i=E("cost/daemon-client");function b(){if(process.env.HYDRA_ACP_TOKEN)return process.env.HYDRA_ACP_TOKEN;const e=g(process.env.HYDRA_ACP_HOME??g(y(),".hydra-acp"),"auth-token");try{const t=m(e,"utf8").trim();if(t.length>0)return t}catch(t){const n=t;n.code!=="ENOENT"&&i.debug(`auth-token read failed: ${n.message}`)}}function R(){if(process.env.HYDRA_ACP_DAEMON_URL)return process.env.HYDRA_ACP_DAEMON_URL;const e=g(process.env.HYDRA_ACP_HOME??g(y(),".hydra-acp"),"daemon.pid");try{const t=m(e,"utf8"),n=JSON.parse(t);if(typeof n.host=="string"&&typeof n.port=="number")return`http://${n.host}:${n.port}`}catch(t){const n=t;n.code!=="ENOENT"&&i.debug(`daemon.pid read failed: ${n.message}`)}return"http://127.0.0.1:8765"}function l(){const e=b();if(e!==void 0)return{daemonUrl:R(),token:e}}function C(e){const t=typeof e.sessionId=="string"?e.sessionId:void 0;if(t===void 0)return;const n=typeof e.updatedAt=="string"?e.updatedAt:"",s=(e._meta??{})["hydra-acp"]??{},d=typeof e.cwd=="string"?e.cwd:typeof s.cwd=="string"?s.cwd:void 0,o=typeof e.agentId=="string"?e.agentId:typeof s.agentId=="string"?s.agentId:"",u=typeof e.currentModel=="string"?e.currentModel:typeof s.currentModel=="string"?s.currentModel:"",f=typeof e.title=="string"?e.title:"",c=e.interactive===!0||s.interactive===!0,p=e.currentUsage,h=s.currentUsage,a=p??h,k=typeof a?.costAmount=="number"?a.costAmount:0,A=typeof a?.costCurrency=="string"?a.costCurrency:"",v=typeof a?.used=="number"?a.used:0;return{sessionId:t,cwd:d,agentId:o,model:u,interactive:c,costAmount:k,costCurrency:A,contextTokens:v,title:f,createdAt:"",updatedAt:n}}async function T(){const e=l();if(e===void 0){i.debug("no daemon token resolved; skipping daemon fetch");return}const t=`${e.daemonUrl.replace(/\/$/,"")}/v1/sessions?includeNonInteractive=1`;let n;try{n=await fetch(t,{headers:{Authorization:`Bearer ${e.token}`}})}catch(o){i.debug(`daemon fetch failed (${t}): ${o.message}`);return}if(!n.ok){i.debug(`daemon returned HTTP ${n.status} for ${t}`);return}let r;try{r=await n.json()}catch(o){i.debug(`daemon response not JSON: ${o.message}`);return}const s=r;if(!Array.isArray(s.sessions)){i.debug("daemon response missing sessions[]");return}const d=[];for(const o of s.sessions)if(o&&typeof o=="object"&&!Array.isArray(o)){const u=C(o);u!==void 0&&d.push(u)}return d}function $(e){const t=typeof e.sessionId=="string"?e.sessionId:void 0,n=typeof e.ts=="string"?e.ts:void 0;if(t===void 0||n===void 0)return;const r=e.update??void 0,s=typeof r?.cost?.amount=="number"?r.cost.amount:0,d=typeof r?.cost?.currency=="string"?r.cost.currency:"USD",o=typeof r?.used=="number"?r.used:0;return{sessionId:t,ts:n,costCumulative:s,costCurrency:d,contextTokens:o}}async function I(e){const t=l();if(t===void 0)return;const n=new URLSearchParams({kinds:"usage_update"});e!==void 0&&n.set("since",e.toISOString());const r=`${t.daemonUrl.replace(/\/$/,"")}/v1/sessions/events?${n.toString()}`;let s;try{s=await fetch(r,{headers:{Authorization:`Bearer ${t.token}`}})}catch(u){i.debug(`events fetch failed: ${u.message}`);return}if(!s.ok){i.debug(`events endpoint HTTP ${s.status}`);return}const d=await s.text(),o=[];for(const u of d.split(`
2
- `)){const f=u.trim();if(f.length===0)continue;let c;try{c=JSON.parse(f)}catch{continue}if(c&&typeof c=="object"&&!Array.isArray(c)){const p=$(c);p!==void 0&&o.push(p)}}return o}export{I as fetchUsageEventsFromDaemon,T as listSessionsFromDaemon};
1
+ import{readFileSync as y}from"node:fs";import{homedir as l}from"node:os";import{resolve as m}from"node:path";import{logger as C}from"../util/log.js";const i=C("cost/daemon-client");function I(){if(process.env.HYDRA_ACP_TOKEN)return process.env.HYDRA_ACP_TOKEN;const e=m(process.env.HYDRA_ACP_HOME??m(l(),".hydra-acp"),"auth-token");try{const t=y(e,"utf8").trim();if(t.length>0)return t}catch(t){const n=t;n.code!=="ENOENT"&&i.debug(`auth-token read failed: ${n.message}`)}}function $(){if(process.env.HYDRA_ACP_DAEMON_URL)return process.env.HYDRA_ACP_DAEMON_URL;const e=m(process.env.HYDRA_ACP_HOME??m(l(),".hydra-acp"),"daemon.pid");try{const t=y(e,"utf8"),n=JSON.parse(t);if(typeof n.host=="string"&&typeof n.port=="number")return`http://${n.host}:${n.port}`}catch(t){const n=t;n.code!=="ENOENT"&&i.debug(`daemon.pid read failed: ${n.message}`)}return"http://127.0.0.1:8765"}function h(){const e=I();if(e!==void 0)return{daemonUrl:$(),token:e}}function U(e){const t=typeof e.sessionId=="string"?e.sessionId:void 0;if(t===void 0)return;const n=typeof e.updatedAt=="string"?e.updatedAt:"",s=(e._meta??{})["hydra-acp"]??{},d=typeof e.cwd=="string"?e.cwd:typeof s.cwd=="string"?s.cwd:void 0,o=typeof e.agentId=="string"?e.agentId:typeof s.agentId=="string"?s.agentId:"",c=typeof e.currentModel=="string"?e.currentModel:typeof s.currentModel=="string"?s.currentModel:"",p=typeof e.title=="string"?e.title:"",u=e.interactive===!0||s.interactive===!0,f=typeof e.importedFromMachine=="string"?e.importedFromMachine:typeof s.importedFromMachine=="string"?s.importedFromMachine:"",k=f.length>0?f:void 0,g=typeof e.upstreamSessionId=="string"?e.upstreamSessionId:typeof s.upstreamSessionId=="string"?s.upstreamSessionId:"",A=g.length>0?g:void 0,v=e.currentUsage,R=s.currentUsage,a=v??R,E=typeof a?.costAmount=="number"?a.costAmount:0,b=typeof a?.costCurrency=="string"?a.costCurrency:"",S=typeof a?.used=="number"?a.used:0;return{sessionId:t,cwd:d,agentId:o,model:c,interactive:u,costAmount:E,costCurrency:b,contextTokens:S,title:p,createdAt:"",updatedAt:n,importedFromMachine:k,upstreamSessionId:A}}async function P(){const e=h();if(e===void 0){i.debug("no daemon token resolved; skipping daemon fetch");return}const t=`${e.daemonUrl.replace(/\/$/,"")}/v1/sessions?includeNonInteractive=1`;let n;try{n=await fetch(t,{headers:{Authorization:`Bearer ${e.token}`}})}catch(o){i.debug(`daemon fetch failed (${t}): ${o.message}`);return}if(!n.ok){i.debug(`daemon returned HTTP ${n.status} for ${t}`);return}let r;try{r=await n.json()}catch(o){i.debug(`daemon response not JSON: ${o.message}`);return}const s=r;if(!Array.isArray(s.sessions)){i.debug("daemon response missing sessions[]");return}const d=[];for(const o of s.sessions)if(o&&typeof o=="object"&&!Array.isArray(o)){const c=U(o);c!==void 0&&d.push(c)}return d}function _(e){const t=typeof e.sessionId=="string"?e.sessionId:void 0,n=typeof e.ts=="string"?e.ts:void 0;if(t===void 0||n===void 0)return;const r=e.update??void 0,s=typeof r?.cost?.amount=="number"?r.cost.amount:0,d=typeof r?.cost?.currency=="string"?r.cost.currency:"USD",o=typeof r?.used=="number"?r.used:0;return{sessionId:t,ts:n,costCumulative:s,costCurrency:d,contextTokens:o}}async function x(e){const t=h();if(t===void 0)return;const n=new URLSearchParams({kinds:"usage_update"});e!==void 0&&n.set("since",e.toISOString());const r=`${t.daemonUrl.replace(/\/$/,"")}/v1/sessions/events?${n.toString()}`;let s;try{s=await fetch(r,{headers:{Authorization:`Bearer ${t.token}`}})}catch(c){i.debug(`events fetch failed: ${c.message}`);return}if(!s.ok){i.debug(`events endpoint HTTP ${s.status}`);return}const d=await s.text(),o=[];for(const c of d.split(`
2
+ `)){const p=c.trim();if(p.length===0)continue;let u;try{u=JSON.parse(p)}catch{continue}if(u&&typeof u=="object"&&!Array.isArray(u)){const f=_(u);f!==void 0&&o.push(f)}}return o}export{x as fetchUsageEventsFromDaemon,P as listSessionsFromDaemon};
@@ -1,16 +1,16 @@
1
- function h(e){return"label"in e?e.label:e.bucket}function R(e){let t=0,u=!1;for(const c of e){if(c===void 0)continue;const o=String(c);o.length>t&&(t=o.length),c!==1&&(u=!0)}const s=u?8:7,i=e.map(c=>{if(c===void 0)return"";const o=String(c).padStart(t),n=(c===1?"session":"sessions").padEnd(s);return`${o} ${n}`}),r=t+1+s;return{strs:i,width:r}}function g(e){if(e<1e3)return String(e);let t,u;return e<1e6?(t=e/1e3,u="k"):e<1e9?(t=e/1e6,u="M"):(t=e/1e9,u="B"),(t%1===0?t.toFixed(0):t.toFixed(2)).replace(/\.?0+$/,"")+u}function _(e,t){let u=0;for(const r of e)r>u&&(u=r);if(u<=0||t<=0)return e.map(()=>"");const s=Math.max(1,t),i=[];for(const r of e){const c=r/u,o=Math.round(c*s),n=s-o;i.push("\u2588".repeat(o)+"\u2591".repeat(n))}return i}function v(e,t={}){const u=process.stdout.columns??80,s=t.histogram===!0,i=t.tokens===!0;let r="";const c=o=>`${o} session${o===1?"":"s"}`;if(e.kind==="total"){const o=m(e.row.costAmount),n=e.row.sessionCount,l=n!==void 0?c(n):e.row.label??"all sessions";r+=`Total: ${o} across ${l}
2
- `}else if(e.kind==="grouped"){const o=x(e.groups),n=m(o);let l=0;for(const a of e.groups)for(const d of a.items)l+=d.sessionCount??0;r+=`Total: ${n} across ${c(l)}
3
- `}else if(e.kind==="timeSeries"){const o=e.timeSeries.reduce((a,d)=>a+d.costAmount,0),n=m(o),l=e.timeSeries.reduce((a,d)=>a+(d.sessionCount??0),0);r+=`Total: ${n} across ${c(l)}
4
- `}else if(e.kind==="timeSeriesGrouped"){const o=x(e.groups),n=m(o);let l=0;for(const a of e.groups)for(const d of a.items)l+=d.sessionCount??0;r+=`Total: ${n} across ${c(l)}
5
- `}if(e.kind==="grouped")if(e.groups.every(n=>n.items.length===1)){const n=[];for(const l of e.groups){const a=l.items[0];a!==void 0&&n.push({...a,label:l.label})}n.sort((l,a)=>{const d=i?p(l):l.costAmount;return(i?p(a):a.costAmount)-d}),s?r+=T(n,u,i):r+=w(n,i)}else for(const n of e.groups){r+=`
6
- ${n.label}:
7
- `;const l=n.items,a=l.some(d=>d.inputTokens!==void 0||d.outputTokens!==void 0);s?r+=T(l,u,i):r+=S(l,a,i)}else if(e.kind==="timeSeries"){const o=e.timeSeries.some(n=>n.inputTokens!==void 0||n.outputTokens!==void 0);s?r+=T(e.timeSeries,u,i):r+=S(e.timeSeries,o,i)}else if(e.kind==="timeSeriesGrouped")for(const o of e.groups){r+=`
8
- ${o.label}:
9
- `;const n=o.items.some(l=>l.inputTokens!==void 0||l.outputTokens!==void 0);s?r+=T(o.items,u,i):r+=S(o.items,n,i)}return r}function w(e,t){if(e.length===0)return` (no data)
10
- `;let u=0;for(const n of e)n.label.length>u&&(u=n.label.length);const s=e.map(n=>t?g(p(n)):m(n.costAmount));let i=0;for(const n of s)n.length>i&&(i=n.length);const{strs:r,width:c}=R(e.map(n=>n.sessionCount)),o=[];for(let n=0;n<e.length;n++){const l=e[n];if(l===void 0)continue;let a=` ${l.label.padEnd(u)} ${s[n].padStart(i)}`;c>0&&(a+=` ${r[n]}`),o.push(a+`
11
- `)}return o.join("")}function T(e,t,u){if(e.length===0)return` (no data)
12
- `;let s=0;for(const f of e){const k=h(f);k.length>s&&(s=k.length)}const i=e.map(f=>u?p(f):f.costAmount),r=i.map(f=>u?g(f):m(f));let c=0;for(const f of r)f.length>c&&(c=f.length);const{strs:o,width:n}=R(e.map(f=>f.sessionCount)),l=n>0?n+2:0;let a=t-s-c-l-8;a<1&&(a=e.length>1?1:0);const d=_(i,a),b=[];for(let f=0;f<e.length;f++){const k=e[f];if(k===void 0)continue;const L=h(k).padEnd(s),W=r[f].padStart(c);let C=` ${L} ${W} ${d[f]}`;n>0&&(C+=` ${o[f]}`),b.push(C+`
13
- `)}return b.join("")}function S(e,t,u){if(e.length===0)return` (no data)
14
- `;let s=28;for(const r of e){const c=h(r);c.length>s&&(s=c.length)}let i=" ";i+=B("Label",s),i+=" ",u?i+=" Tokens":(i+=" Cost",t&&(i+=" Tokens")),i+=`
15
- `;for(const r of e){const c=h(r).padEnd(s);let o=" ";if(o+=c,o+=" ",u){const n=p(r);o+=g(n).padStart(12)}else{const n=r.costAmount??0;if(o+=m(n).padStart(10),t){const l=p(r);o+=" ".padStart(2),o+=g(l).padStart(12)}}i+=o+`
16
- `}return i}function G(e){const t={kind:e.kind,currency:e.currency};if(e.kind==="total")t.row=A(e.row);else if(e.kind==="grouped"){const u=e.groups.slice().sort((s,i)=>s.label.localeCompare(i.label));t.groups=u.map(s=>({label:s.label,items:s.items.map(A)}))}else if(e.kind==="timeSeries")t.timeSeries=e.timeSeries.map($);else if(e.kind==="timeSeriesGrouped"){const u=e.groups.slice().sort((s,i)=>s.label.localeCompare(i.label));t.groups=u.map(s=>({label:s.label,items:s.items.map($)}))}return JSON.stringify(t,null,2)}function A(e){const t={label:e.label,costAmount:e.costAmount};return e.deltaCost!==void 0&&(t.deltaCost=e.deltaCost),e.inputTokens!==void 0&&(t.inputTokens=e.inputTokens),e.outputTokens!==void 0&&(t.outputTokens=e.outputTokens),e.cacheReadTokens!==void 0&&(t.cacheReadTokens=e.cacheReadTokens),e.cacheWriteTokens!==void 0&&(t.cacheWriteTokens=e.cacheWriteTokens),t}function $(e){const t={bucket:e.bucket,costAmount:e.costAmount,deltaCost:e.deltaCost};return e.inputTokens!==void 0&&(t.inputTokens=e.inputTokens),e.outputTokens!==void 0&&(t.outputTokens=e.outputTokens),e.cacheReadTokens!==void 0&&(t.cacheReadTokens=e.cacheReadTokens),e.cacheWriteTokens!==void 0&&(t.cacheWriteTokens=e.cacheWriteTokens),t}function m(e){return`$${e.toFixed(2)}`}function p(e){let t=0;return e.inputTokens!==void 0&&(t+=e.inputTokens),e.outputTokens!==void 0&&(t+=e.outputTokens),t}function B(e,t){return e.length>=t?e:e+" ".repeat(t-e.length)}function x(e){let t=0;for(const u of e)for(const s of u.items)t+=s.costAmount;return t}export{G as renderJson,v as renderText};
1
+ function h(e){return"label"in e?e.label:e.bucket}function x(e){let n=0,i=!1;for(const o of e){if(o===void 0)continue;const f=String(o);f.length>n&&(n=f.length),o!==1&&(i=!0)}const r=i?8:7,l=e.map(o=>{if(o===void 0)return"";const f=String(o).padStart(n),a=(o===1?"session":"sessions").padEnd(r);return`${f} ${a}`}),u=n+1+r;return{strs:l,width:u}}function b(e){if(e<1e3)return String(e);let n,i;return e<1e6?(n=e/1e3,i="k"):e<1e9?(n=e/1e6,i="M"):(n=e/1e9,i="B"),(n%1===0?n.toFixed(0):n.toFixed(2)).replace(/\.?0+$/,"")+i}function w(e,n){let i=0;for(const u of e)u>i&&(i=u);if(i<=0||n<=0)return e.map(()=>"");const r=Math.max(1,n),l=[];for(const u of e){const o=u/i,f=Math.round(o*r),a=r-f;l.push("\u2588".repeat(f)+"\u2591".repeat(a))}return l}function E(e,n={}){const i=process.stdout.columns??80,r=n.histogram===!0,l=n.tokens===!0,u=n.loc===!0;let o="";const f=t=>`${t} session${t===1?"":"s"}`,a=(t,s)=>{if(u){let d=0;for(const c of s)d+=v(c);return`${$(d)} lines`}return A(t)};if(e.kind==="total"){const t=e.row.sessionCount,s=t!==void 0?f(t):e.row.label??"all sessions";o+=`Total: ${a(e.row.costAmount,[e.row])} across ${s}
2
+ `}else if(e.kind==="grouped"){const t=[];let s=0;for(const c of e.groups)for(const p of c.items)t.push(p),s+=p.sessionCount??0;e.totalSessions!==void 0&&(s=e.totalSessions);const d=_(e.groups);o+=`Total: ${a(d,t)} across ${f(s)}
3
+ `}else if(e.kind==="timeSeries"){const t=e.timeSeries.reduce((d,c)=>d+c.costAmount,0),s=e.timeSeries.reduce((d,c)=>d+(c.sessionCount??0),0);o+=`Total: ${a(t,e.timeSeries)} across ${f(s)}
4
+ `}else if(e.kind==="timeSeriesGrouped"){const t=[];let s=0;for(const c of e.groups)for(const p of c.items)t.push(p),s+=p.sessionCount??0;e.totalSessions!==void 0&&(s=e.totalSessions);const d=_(e.groups);o+=`Total: ${a(d,t)} across ${f(s)}
5
+ `}if(e.kind==="grouped")if(e.groups.every(s=>s.items.length===1)){const s=[];for(const d of e.groups){const c=d.items[0];c!==void 0&&s.push({...c,label:d.label})}s.sort((d,c)=>{const p=S(d,l,u);return S(c,l,u)-p}),r?o+=k(s,i,l,u):o+=j(s,l,u)}else for(const s of e.groups){o+=`
6
+ ${s.label}:
7
+ `;const d=s.items,c=d.some(p=>p.inputTokens!==void 0||p.outputTokens!==void 0);r?o+=k(d,i,l,u):o+=R(d,c,l,u)}else if(e.kind==="timeSeries"){const t=e.timeSeries.some(s=>s.inputTokens!==void 0||s.outputTokens!==void 0);r?o+=k(e.timeSeries,i,l,u):o+=R(e.timeSeries,t,l,u)}else if(e.kind==="timeSeriesGrouped")for(const t of e.groups){o+=`
8
+ ${t.label}:
9
+ `;const s=t.items.some(d=>d.inputTokens!==void 0||d.outputTokens!==void 0);r?o+=k(t.items,i,l,u):o+=R(t.items,s,l,u)}return o}function S(e,n,i){return i?v(e):n?T(e):e.costAmount}function L(e,n,i){return i?$(v(e)):n?b(T(e)):A(e.costAmount)}function j(e,n,i){if(e.length===0)return` (no data)
10
+ `;let r=0;for(const t of e)t.label.length>r&&(r=t.label.length);const l=e.map(t=>L(t,n,i));let u=0;for(const t of l)t.length>u&&(u=t.length);const{strs:o,width:f}=x(e.map(t=>t.sessionCount)),a=[];for(let t=0;t<e.length;t++){const s=e[t];if(s===void 0)continue;const d=l[t]??"";let c=` ${s.label.padEnd(r)} ${d.padStart(u)}`;f>0&&(c+=` ${o[t]}`),a.push(c+`
11
+ `)}return a.join("")}function k(e,n,i,r){if(e.length===0)return` (no data)
12
+ `;let l=0;for(const m of e){const g=h(m);g.length>l&&(l=g.length)}const u=e.map(m=>{const g=S(m,i,r);return r?Math.abs(g):g}),o=e.map(m=>L(m,i,r));let f=0;for(const m of o)m.length>f&&(f=m.length);const{strs:a,width:t}=x(e.map(m=>m.sessionCount)),s=t>0?t+2:0;let d=n-l-f-s-8;d<1&&(d=e.length>1?1:0);const c=w(u,d),p=[];for(let m=0;m<e.length;m++){const g=e[m];if(g===void 0)continue;const G=h(g).padEnd(l),y=(o[m]??"").padStart(f);let C=` ${G} ${y} ${c[m]??""}`;t>0&&(C+=` ${a[m]}`),p.push(C+`
13
+ `)}return p.join("")}function R(e,n,i,r){if(e.length===0)return` (no data)
14
+ `;let l=28;for(const o of e){const f=h(o);f.length>l&&(l=f.length)}let u=" ";u+=N("Label",l),u+=" ",r?u+=" +Added -Removed Net":i?u+=" Tokens":(u+=" Cost",n&&(u+=" Tokens")),u+=`
15
+ `;for(const o of e){const f=h(o).padEnd(l);let a=" ";if(a+=f,a+=" ",r){const t=o.linesAdded??0,s=o.linesRemoved??0;a+=t.toLocaleString().padStart(10),a+=" ",a+=s.toLocaleString().padStart(8),a+=" ",a+=$(t-s).padStart(8)}else if(i){const t=T(o);a+=b(t).padStart(12)}else{const t=o.costAmount??0;if(a+=A(t).padStart(10),n){const s=T(o);a+=" ".padStart(2),a+=b(s).padStart(12)}}u+=a+`
16
+ `}return u}function F(e){const n={kind:e.kind,currency:e.currency};if(e.kind==="total")n.row=B(e.row);else if(e.kind==="grouped"){const i=e.groups.slice().sort((r,l)=>r.label.localeCompare(l.label));n.groups=i.map(r=>({label:r.label,items:r.items.map(B)}))}else if(e.kind==="timeSeries")n.timeSeries=e.timeSeries.map(W);else if(e.kind==="timeSeriesGrouped"){const i=e.groups.slice().sort((r,l)=>r.label.localeCompare(l.label));n.groups=i.map(r=>({label:r.label,items:r.items.map(W)}))}return JSON.stringify(n,null,2)}function B(e){const n={label:e.label,costAmount:e.costAmount};return e.deltaCost!==void 0&&(n.deltaCost=e.deltaCost),e.inputTokens!==void 0&&(n.inputTokens=e.inputTokens),e.outputTokens!==void 0&&(n.outputTokens=e.outputTokens),e.cacheReadTokens!==void 0&&(n.cacheReadTokens=e.cacheReadTokens),e.cacheWriteTokens!==void 0&&(n.cacheWriteTokens=e.cacheWriteTokens),e.linesAdded!==void 0&&(n.linesAdded=e.linesAdded),e.linesRemoved!==void 0&&(n.linesRemoved=e.linesRemoved),(e.linesAdded!==void 0||e.linesRemoved!==void 0)&&(n.linesNet=(e.linesAdded??0)-(e.linesRemoved??0)),n}function W(e){const n={bucket:e.bucket,costAmount:e.costAmount,deltaCost:e.deltaCost};return e.inputTokens!==void 0&&(n.inputTokens=e.inputTokens),e.outputTokens!==void 0&&(n.outputTokens=e.outputTokens),e.cacheReadTokens!==void 0&&(n.cacheReadTokens=e.cacheReadTokens),e.cacheWriteTokens!==void 0&&(n.cacheWriteTokens=e.cacheWriteTokens),e.linesAdded!==void 0&&(n.linesAdded=e.linesAdded),e.linesRemoved!==void 0&&(n.linesRemoved=e.linesRemoved),(e.linesAdded!==void 0||e.linesRemoved!==void 0)&&(n.linesNet=(e.linesAdded??0)-(e.linesRemoved??0)),n}function A(e){return`$${e.toFixed(2)}`}function v(e){const n=e.linesAdded??0,i=e.linesRemoved??0;return n-i}function $(e){return`${e>0?"+":""}${e.toLocaleString()}`}function T(e){let n=0;return e.inputTokens!==void 0&&(n+=e.inputTokens),e.outputTokens!==void 0&&(n+=e.outputTokens),n}function N(e,n){return e.length>=n?e:e+" ".repeat(n-e.length)}function _(e){let n=0;for(const i of e)for(const r of i.items)n+=r.costAmount;return n}export{F as renderJson,E as renderText};
@@ -1 +1 @@
1
- import{createInterface as j}from"node:readline";import{createReadStream as E,statSync as N}from"node:fs";import{resolve as x}from"node:path";import{logger as O}from"../util/log.js";import{sessionsDir as $}from"./session-store.js";const b=O("cost/history-stream");function D(t){if(!t||typeof t!="object"||Array.isArray(t))return;const n=t["hydra-acp"];if(!n||typeof n!="object"||Array.isArray(n))return;const e=n.cumulativeCost;return typeof e=="number"?e:void 0}function J(t){const n=D(t._meta),e=t.cost??void 0,s=n!==void 0?n:typeof e?.amount=="number"?e.amount:void 0;if(s===void 0)return;const u=typeof e?.currency=="string"?e.currency:void 0;return{amount:s,currency:u}}function M(t){const n=t.recordedAt;return typeof n=="number"?new Date(n).toISOString():typeof n=="string"?n:""}async function*L(t){const n=Array.isArray(t)?t:[t];for(const e of n){const s=x($(),e.sessionId,"history.jsonl");try{N(s)}catch(c){const o=c;if(o.code==="ENOENT"){b.debug(`no history for ${e.sessionId}`);continue}b.debug(`stat failed for ${s}: ${o.message}`);continue}const u=E(s,{encoding:"utf8"}),k=j({input:u,crlfDelay:1/0}),h=new Map;try{for await(const c of k){if(c.length===0)continue;let o;try{o=JSON.parse(c)}catch{b.debug(`malformed JSON in history.jsonl for ${e.sessionId}`);continue}if(!o||typeof o!="object"||Array.isArray(o))continue;const a=o;if(a.method!=="session/update")continue;const d=a.params??void 0;if(!d||typeof d!="object"||Array.isArray(d))continue;const i=d.update??void 0;if(!i||typeof i!="object"||Array.isArray(i)||i.sessionUpdate!=="usage_update")continue;const I=M(a),f=J(i);if(f===void 0)continue;const T=f.currency??"",m=f.amount,C=h.get(e.sessionId)??0,S=Math.max(0,m-C);h.set(e.sessionId,m);const r=i.usage??void 0;let y,p,l,g;if(r&&typeof r=="object"&&!Array.isArray(r)){const w=r.inputTokens;typeof w=="number"&&(y=w);const A=r.outputTokens;typeof A=="number"&&(p=A);const R=r.cacheReadInputTokens;typeof R=="number"&&(l=R);const v=r.cacheCreationInputTokens;typeof v=="number"&&(g=v)}yield{sessionId:e.sessionId,ts:I,deltaCost:S,cumulativeCost:m,currency:T,...y!==void 0&&{inputTokens:y},...p!==void 0&&{outputTokens:p},...l!==void 0&&{cacheReadTokens:l},...g!==void 0&&{cacheWriteTokens:g}}}}finally{k.close(),u.destroy()}}}export{L as streamHistoryEvents};
1
+ import{createInterface as S}from"node:readline";import{createReadStream as x,statSync as C}from"node:fs";import{resolve as N}from"node:path";import{logger as _}from"../util/log.js";import{sessionsDir as O}from"./session-store.js";import{languageForPath as D}from"./language.js";const g=_("cost/history-stream");function L(n){if(!n||typeof n!="object"||Array.isArray(n))return;const t=n["hydra-acp"];if(!t||typeof t!="object"||Array.isArray(t))return;const e=t.cumulativeCost;return typeof e=="number"?e:void 0}function M(n){const t=L(n._meta),e=n.cost??void 0,i=t!==void 0?t:typeof e?.amount=="number"?e.amount:void 0;if(i===void 0)return;const f=typeof e?.currency=="string"?e.currency:void 0;return{amount:i,currency:f}}function $(n){const t=n.recordedAt;return typeof t=="number"?new Date(t).toISOString():typeof t=="string"?t:""}async function*q(n){const t=Array.isArray(n)?n:[n];for(const e of t){const i=N(O(),e.sessionId,"history.jsonl");try{C(i)}catch(o){const r=o;if(r.code==="ENOENT"){g.debug(`no history for ${e.sessionId}`);continue}g.debug(`stat failed for ${i}: ${r.message}`);continue}const f=x(i,{encoding:"utf8"}),l=S({input:f,crlfDelay:1/0}),y=new Map;try{for await(const o of l){if(o.length===0)continue;let r;try{r=JSON.parse(o)}catch{g.debug(`malformed JSON in history.jsonl for ${e.sessionId}`);continue}if(!r||typeof r!="object"||Array.isArray(r))continue;const d=r;if(d.method!=="session/update")continue;const s=d.params??void 0;if(!s||typeof s!="object"||Array.isArray(s))continue;const c=s.update??void 0;if(!c||typeof c!="object"||Array.isArray(c)||c.sessionUpdate!=="usage_update")continue;const b=$(d),a=M(c);if(a===void 0)continue;const u=a.currency??"",p=a.amount,h=y.get(e.sessionId)??0,A=Math.max(0,p-h);y.set(e.sessionId,p);const m=c.usage??void 0;let k,w,R,v;if(m&&typeof m=="object"&&!Array.isArray(m)){const T=m.inputTokens;typeof T=="number"&&(k=T);const I=m.outputTokens;typeof I=="number"&&(w=I);const E=m.cacheReadInputTokens;typeof E=="number"&&(R=E);const j=m.cacheCreationInputTokens;typeof j=="number"&&(v=j)}yield{sessionId:e.sessionId,ts:b,deltaCost:A,cumulativeCost:p,currency:u,...k!==void 0&&{inputTokens:k},...w!==void 0&&{outputTokens:w},...R!==void 0&&{cacheReadTokens:R},...v!==void 0&&{cacheWriteTokens:v}}}}finally{l.close(),f.destroy()}}}function J(n){if(n.length===0)return 0;let t=1;for(let e=0;e<n.length;e++)n.charCodeAt(e)===10&&t++;return n.charCodeAt(n.length-1)===10&&t--,t}async function*z(n){const t=Array.isArray(n)?n:[n];for(const e of t){const i=N(O(),e.sessionId,"history.jsonl");try{C(i)}catch(y){const o=y;if(o.code==="ENOENT")continue;g.debug(`stat failed for ${i}: ${o.message}`);continue}const f=x(i,{encoding:"utf8"}),l=S({input:f,crlfDelay:1/0});try{for await(const y of l){if(y.length===0)continue;let o;try{o=JSON.parse(y)}catch{continue}if(!o||typeof o!="object"||Array.isArray(o))continue;const r=o;if(r.method!=="session/update")continue;const d=r.params??void 0;if(!d||typeof d!="object"||Array.isArray(d))continue;const s=d.update??void 0;if(!s||typeof s!="object"||Array.isArray(s)||s.sessionUpdate!=="tool_call"&&s.sessionUpdate!=="tool_call_update")continue;const c=s.content;if(!Array.isArray(c)||c.length===0)continue;const b=$(r);for(const a of c){if(!a||typeof a!="object"||Array.isArray(a))continue;const u=a;if(u.type!=="diff")continue;const p=typeof u.path=="string"?u.path:"";if(p==="")continue;const h=typeof u.oldText=="string"?u.oldText:"",A=typeof u.newText=="string"?u.newText:"";yield{sessionId:e.sessionId,ts:b,path:p,language:D(p),linesAdded:J(A),linesRemoved:J(h)}}}}finally{l.close(),f.destroy()}}}export{z as streamHistoryEditEvents,q as streamHistoryEvents};
@@ -0,0 +1 @@
1
+ const a={".ts":"TypeScript",".tsx":"TypeScript",".mts":"TypeScript",".cts":"TypeScript",".js":"JavaScript",".jsx":"JavaScript",".mjs":"JavaScript",".cjs":"JavaScript",".py":"Python",".pyi":"Python",".rb":"Ruby",".go":"Go",".rs":"Rust",".java":"Java",".kt":"Kotlin",".kts":"Kotlin",".scala":"Scala",".swift":"Swift",".m":"Objective-C",".mm":"Objective-C++",".c":"C",".h":"C",".cc":"C++",".cpp":"C++",".cxx":"C++",".hpp":"C++",".hh":"C++",".hxx":"C++",".cs":"C#",".fs":"F#",".php":"PHP",".pl":"Perl",".pm":"Perl",".lua":"Lua",".r":"R",".jl":"Julia",".dart":"Dart",".ex":"Elixir",".exs":"Elixir",".erl":"Erlang",".hrl":"Erlang",".clj":"Clojure",".cljs":"Clojure",".hs":"Haskell",".ml":"OCaml",".mli":"OCaml",".el":"Emacs Lisp",".lisp":"Lisp",".scm":"Scheme",".sh":"Shell",".bash":"Shell",".zsh":"Shell",".fish":"Shell",".ps1":"PowerShell",".sql":"SQL",".html":"HTML",".htm":"HTML",".css":"CSS",".scss":"SCSS",".sass":"Sass",".less":"Less",".vue":"Vue",".svelte":"Svelte",".md":"Markdown",".mdx":"Markdown",".rst":"reStructuredText",".tex":"TeX",".json":"JSON",".jsonc":"JSON",".yaml":"YAML",".yml":"YAML",".toml":"TOML",".xml":"XML",".proto":"Protobuf",".graphql":"GraphQL",".gql":"GraphQL",".dockerfile":"Dockerfile",".tf":"Terraform",".hcl":"HCL",".vim":"Vim Script",".zig":"Zig",".nim":"Nim",".cr":"Crystal"},c={Dockerfile:"Dockerfile",Makefile:"Makefile",GNUmakefile:"Makefile",Rakefile:"Ruby",Gemfile:"Ruby","CMakeLists.txt":"CMake"};function o(e){const t=e.lastIndexOf("/"),s=t>=0?e.slice(t+1):e,l=c[s];if(l!==void 0)return l;const r=s.lastIndexOf(".");if(r<=0)return"Other";const i=s.slice(r).toLowerCase();return a[i]??"Other"}export{o as languageForPath};
@@ -1 +1 @@
1
- import{readdirSync as C,readFileSync as I,realpathSync as R,statSync as h}from"node:fs";import{isAbsolute as j,resolve as a}from"node:path";import{homedir as x}from"node:os";import{logger as E}from"../util/log.js";const d=E("cost/session-store"),f=new Map;function $(n){if(f.has(n))return f.get(n);try{const s=R(n);return f.set(n,s),s}catch{f.set(n,void 0);return}}function N(){const n=process.env.HYDRA_ACP_HOME??a(x(),".hydra-acp");return a(n,"sessions")}function J(n){const s=a(n,"meta.json");let i;try{i=I(s,"utf8")}catch(g){const p=g;if(p.code==="ENOENT")return;d.debug(`skipping ${n}: read meta.json failed: ${p.message}`);return}let t;try{t=JSON.parse(i)}catch{d.debug(`skipping ${n}: meta.json is not valid JSON`);return}if(!t||typeof t!="object"||Array.isArray(t)){d.debug(`skipping ${n}: meta.json is not an object`);return}const e=t,c=typeof e.sessionId=="string"?e.sessionId:void 0;if(c===void 0){d.debug(`skipping ${n}: missing sessionId`);return}let r;const u=typeof e.cwd=="string"?e.cwd:void 0;u!==void 0&&(j(u)?r=$(u):r=u);const y=typeof e.agentId=="string"?e.agentId:"",m=typeof e.currentModel=="string"?e.currentModel:"",l=e.interactive===!0,o=e.currentUsage??void 0,A=typeof o?.costAmount=="number"?o.costAmount:0,w=typeof o?.costCurrency=="string"?o.costCurrency:"",b=typeof o?.used=="number"?o.used:0,S=typeof e.title=="string"?e.title:"",k=typeof e.createdAt=="string"?e.createdAt:"",v=typeof e.updatedAt=="string"?e.updatedAt:"";return{sessionId:c,cwd:r,agentId:y,model:m,interactive:l,costAmount:A,costCurrency:w,contextTokens:b,title:S,createdAt:k,updatedAt:v}}function U(){const n=N();let s;try{s=C(n)}catch(t){const e=t;return d.debug(`session store not found at ${n}: ${e.message}`),[]}const i=[];for(const t of s){const e=a(n,t);let c;try{c=h(e)}catch{continue}if(!c.isDirectory())continue;const r=J(e);r!==void 0&&i.push(r)}return i}export{U as scanSessions,N as sessionsDir};
1
+ import{readdirSync as k,readFileSync as M,realpathSync as C,statSync as E}from"node:fs";import{isAbsolute as x,resolve as a}from"node:path";import{homedir as j}from"node:os";import{logger as $}from"../util/log.js";const c=$("cost/session-store"),g=new Map;function F(n){if(g.has(n))return g.get(n);try{const s=C(n);return g.set(n,s),s}catch{g.set(n,void 0);return}}function N(){const n=process.env.HYDRA_ACP_HOME??a(j(),".hydra-acp");return a(n,"sessions")}function J(n){const s=a(n,"meta.json");let o;try{o=M(s,"utf8")}catch(f){const m=f;if(m.code==="ENOENT")return;c.debug(`skipping ${n}: read meta.json failed: ${m.message}`);return}let t;try{t=JSON.parse(o)}catch{c.debug(`skipping ${n}: meta.json is not valid JSON`);return}if(!t||typeof t!="object"||Array.isArray(t)){c.debug(`skipping ${n}: meta.json is not an object`);return}const e=t,r=typeof e.sessionId=="string"?e.sessionId:void 0;if(r===void 0){c.debug(`skipping ${n}: missing sessionId`);return}let i;const u=typeof e.cwd=="string"?e.cwd:void 0;u!==void 0&&(x(u)?i=F(u):i=u);const p=typeof e.agentId=="string"?e.agentId:"",y=typeof e.currentModel=="string"?e.currentModel:"",l=e.interactive===!0,d=e.currentUsage??void 0,S=typeof d?.costAmount=="number"?d.costAmount:0,A=typeof d?.costCurrency=="string"?d.costCurrency:"",b=typeof d?.used=="number"?d.used:0,w=typeof e.title=="string"?e.title:"",h=typeof e.createdAt=="string"?e.createdAt:"",v=typeof e.updatedAt=="string"?e.updatedAt:"",I=typeof e.importedFromMachine=="string"&&e.importedFromMachine.length>0?e.importedFromMachine:void 0,R=typeof e.upstreamSessionId=="string"&&e.upstreamSessionId.length>0?e.upstreamSessionId:void 0;return{sessionId:r,cwd:i,agentId:p,model:y,interactive:l,costAmount:S,costCurrency:A,contextTokens:b,title:w,createdAt:h,updatedAt:v,importedFromMachine:I,upstreamSessionId:R}}async function B(n){const{streamHistoryEditEvents:s}=await import("./history-stream.js");for(const o of n){const t={};for await(const e of s(o)){const r=t[e.language]??{added:0,removed:0};r.added+=e.linesAdded,r.removed+=e.linesRemoved,t[e.language]=r}o.locByLanguage=t}return n}function U(){const n=N();let s;try{s=k(n)}catch(t){const e=t;return c.debug(`session store not found at ${n}: ${e.message}`),[]}const o=[];for(const t of s){const e=a(n,t);let r;try{r=E(e)}catch{continue}if(!r.isDirectory())continue;const i=J(e);i!==void 0&&o.push(i)}return o}export{B as enrichSessionsWithLoc,U as scanSessions,N as sessionsDir};
package/dist/index.js CHANGED
@@ -1,24 +1,30 @@
1
1
  #!/usr/bin/env node
2
- import{readFileSync as C}from"node:fs";import{dirname as F,resolve as R}from"node:path";import{fileURLToPath as U}from"node:url";import{loadConfig as $}from"./config.js";import{BudgeterBridge as L}from"./bridge.js";import{stateFilePath as v}from"./paths.js";import{DEFAULT_RULE as P}from"./rule.js";import{deleteStateFile as N}from"./tracker.js";import{logger as x,setDebug as G}from"./util/log.js";import{scanSessions as M}from"./cost/session-store.js";import{listSessionsFromDaemon as j,fetchUsageEventsFromDaemon as H}from"./cost/daemon-client.js";import{aggregate as A,applyFilters as _,parseSince as J}from"./cost/aggregate.js";import{renderText as W,renderJson as Y}from"./cost/format.js";const k=x("main");function S(){try{const e=F(U(import.meta.url));return JSON.parse(C(R(e,"../package.json"),"utf8")).version??"unknown"}catch{return"unknown"}}function B(){N(v()),process.stdout.write(`hydra-acp-budgeter accumulated cost reset
3
- `)}const V=`Usage: hydra budgeter usage [OPTIONS]
2
+ import{readFileSync as C}from"node:fs";import{dirname as U,resolve as $}from"node:path";import{fileURLToPath as P}from"node:url";import{loadConfig as N}from"./config.js";import{BudgeterBridge as x}from"./bridge.js";import{stateFilePath as D}from"./paths.js";import{DEFAULT_RULE as G}from"./rule.js";import{deleteStateFile as H}from"./tracker.js";import{logger as M,setDebug as W}from"./util/log.js";import{scanSessions as j,enrichSessionsWithLoc as A}from"./cost/session-store.js";import{listSessionsFromDaemon as _,fetchUsageEventsFromDaemon as J}from"./cost/daemon-client.js";import{streamHistoryEditEvents as Y}from"./cost/history-stream.js";import{aggregate as q,applyFilters as B,parseSince as V}from"./cost/aggregate.js";import{renderText as K,renderJson as Z}from"./cost/format.js";const I=M("main");function O(){try{const t=U(P(import.meta.url));return JSON.parse(C($(t,"../package.json"),"utf8")).version??"unknown"}catch{return"unknown"}}function z(){H(D()),process.stdout.write(`hydra-acp-budgeter accumulated cost reset
3
+ `)}const Q=`Usage: hydra budgeter usage [OPTIONS]
4
4
 
5
5
  Options:
6
6
  --since <date|duration> Only include sessions updated after this date (e.g. 7d, 2024-01-01)
7
7
  --bucket <hour|day|week|month> Group results into time buckets (implies --since 24h/30d/6m/2y)
8
- --by <dir|session|model|agent> Group by dimension
8
+ --by <dir|session|model|agent|language> Group by dimension (language requires --metric loc)
9
9
  --depth <N> Depth for --by dir grouping (default: 1)
10
10
  --dir <path> Only include sessions under this directory prefix
11
11
  --interactive Only include interactive sessions (default: include both)
12
+ --host <name|local|all> Filter sessions by host. "local" (default) shows sessions
13
+ created here plus imports attached locally; "all" includes
14
+ every session; <name> shows passive mirrors imported from
15
+ that host.
12
16
  --min <N> Drop sessions whose active-metric value is <= N (default: 0)
13
17
  --histogram Show an ASCII histogram bar next to each row (implies --bucket week if no bucket given)
14
- --metric <cost|tokens> Display metric (default: cost)
18
+ --metric <cost|tokens|loc> Display metric (default: cost). "loc" counts net lines of code
19
+ from Edit/Write tool diffs in session history.
15
20
  --json Output as JSON
16
- --help Show this help message`;async function E(e){if(e.includes("--help")){process.stdout.write(V+`
17
- `);return}let r,s,d,a,c,l=!1,f,u=!1,o,m=!1;for(let t=0;t<e.length;t++){const n=e[t];if(n!==void 0){if(n==="--since")t+=1,r=e[t];else if(n==="--bucket")t+=1,s=e[t];else if(n==="--by")t+=1,d=e[t];else if(n==="--depth")t+=1,a=e[t];else if(n==="--dir")t+=1,c=e[t];else if(n==="--interactive")l=!0;else if(n==="--min")t+=1,f=e[t];else if(n==="--histogram")u=!0;else if(n==="--metric")t+=1,o=e[t];else if(n==="--json")m=!0;else if(n.startsWith("--"))throw new Error(`Unknown option: ${n}
18
- Run "hydra budgeter usage --help" for usage.`)}}if(o!==void 0&&o!=="cost"&&o!=="tokens")throw new Error(`Invalid --metric value. Must be 'cost' or 'tokens'.
19
- Run "hydra budgeter usage --help" for usage.`);let p;if(r!==void 0)try{p=J(r)}catch(t){const n=t;throw new Error(`Invalid --since value: ${n.message}
20
- Run "hydra budgeter usage --help" for usage.`)}e.length===0&&(s="hour",u=!0),u&&s===void 0&&(s="week");let i=p;if(i===void 0&&s!==void 0){const t=new Date;s==="hour"?(t.setHours(t.getHours()-24),i=t):s==="day"?(t.setDate(t.getDate()-30),i=t):s==="week"?(t.setMonth(t.getMonth()-6),i=t):s==="month"&&(t.setFullYear(t.getFullYear()-2),i=t)}const h=l?!0:void 0,g=o==="tokens",y=f!==void 0?parseFloat(f):void 0,T=await j()??M(),D=_(T,{since:i,dir:c,interactive:h,min:y,minMetric:g?"tokens":"cost"});let w;if(s!==void 0){const t=await H();t!==void 0&&(w=t.map(n=>({sessionId:n.sessionId,ts:n.ts,deltaCost:0,cumulativeCost:n.costCumulative,currency:n.costCurrency,inputTokens:n.contextTokens})))}const I=a!==void 0?parseInt(a,10):void 0,b=A(D,w,{by:d,depth:I,bucket:s,since:i,interactive:h,dir:c,tokens:g,min:y});if(m)process.stdout.write(Y(b)+`
21
- `);else{const t=W(b,{histogram:u,tokens:o==="tokens"});process.stdout.write(t)}}async function K(){const e=$();G(e.debug);const r=v(),s=new L({daemonWsUrl:e.hydraWsUrl,token:e.hydraToken,softLimit:e.softLimit,hardLimit:e.hardLimit,currency:e.currency,rule:P,statePath:r});s.start();const d=a=>{k.info(`${a} received \u2014 shutting down`),s.stop(),setTimeout(()=>process.exit(0),200).unref()};process.on("SIGINT",()=>d("SIGINT")),process.on("SIGTERM",()=>d("SIGTERM")),k.info(`hydra-acp-budgeter up; daemon=${e.hydraDaemonUrl} soft=${e.softLimit} hard=${e.hardLimit} ${e.currency} state=${r}`)}function Z(){process.stdout.write(`hydra-acp-budgeter ${S()}
21
+ --help Show this help message`;async function F(t){if(t.includes("--help")){process.stdout.write(Q+`
22
+ `);return}let i,n,r,u,l,p=!1,f,c=!1,o,g=!1,h;for(let e=0;e<t.length;e++){const s=t[e];if(s!==void 0){if(s==="--since")e+=1,i=t[e];else if(s==="--bucket")e+=1,n=t[e];else if(s==="--by")e+=1,r=t[e];else if(s==="--depth")e+=1,u=t[e];else if(s==="--dir")e+=1,l=t[e];else if(s==="--interactive")p=!0;else if(s==="--min")e+=1,f=t[e];else if(s==="--histogram")c=!0;else if(s==="--metric")e+=1,o=t[e];else if(s==="--json")g=!0;else if(s==="--host")e+=1,h=t[e];else if(s.startsWith("--host="))h=s.slice(7);else if(s.startsWith("--"))throw new Error(`Unknown option: ${s}
23
+ Run "hydra budgeter usage --help" for usage.`)}}if(o!==void 0&&o!=="cost"&&o!=="tokens"&&o!=="loc")throw new Error(`Invalid --metric value. Must be 'cost', 'tokens', or 'loc'.
24
+ Run "hydra budgeter usage --help" for usage.`);const d=o==="loc";if(r==="language"&&!d)throw new Error(`--by language requires --metric loc.
25
+ Run "hydra budgeter usage --help" for usage.`);let y;if(i!==void 0)try{y=V(i)}catch(e){const s=e;throw new Error(`Invalid --since value: ${s.message}
26
+ Run "hydra budgeter usage --help" for usage.`)}t.length===0&&(n="hour",c=!0),c&&n===void 0&&(n="week");let a=y;if(a===void 0&&n!==void 0){const e=new Date;n==="hour"?(e.setHours(e.getHours()-24),a=e):n==="day"?(e.setDate(e.getDate()-30),a=e):n==="week"?(e.setMonth(e.getMonth()-6),a=e):n==="month"&&(e.setFullYear(e.getFullYear()-2),a=e)}const w=p?!0:void 0,m=o==="tokens",v=f!==void 0?parseFloat(f):void 0,b=await _()??j();(d||r==="language")&&await A(b);const k=B(b,{since:a,dir:l,interactive:w,min:v,minMetric:d?"loc":m?"tokens":"cost",host:h??"local"});let E;if(n!==void 0){const e=await J();e!==void 0&&(E=e.map(s=>({sessionId:s.sessionId,ts:s.ts,deltaCost:0,cumulativeCost:s.costCumulative,currency:s.costCurrency,inputTokens:s.contextTokens})))}let S;if(d&&n!==void 0){const e=[];for await(const s of Y(k))e.push(s);S=e}const L=u!==void 0?parseInt(u,10):void 0,T=q(k,E,{by:r,depth:L,bucket:n,since:a,interactive:w,dir:l,tokens:m,loc:d,min:v},S);if(g)process.stdout.write(Z(T)+`
27
+ `);else{const e=K(T,{histogram:c,tokens:m,loc:d});process.stdout.write(e)}}async function X(){const t=N();W(t.debug);const i=D(),n=new x({daemonWsUrl:t.hydraWsUrl,token:t.hydraToken,softLimit:t.softLimit,hardLimit:t.hardLimit,currency:t.currency,rule:G,statePath:i});n.start();const r=u=>{I.info(`${u} received \u2014 shutting down`),n.stop(),setTimeout(()=>process.exit(0),200).unref()};process.on("SIGINT",()=>r("SIGINT")),process.on("SIGTERM",()=>r("SIGTERM")),I.info(`hydra-acp-budgeter up; daemon=${t.hydraDaemonUrl} soft=${t.softLimit} hard=${t.hardLimit} ${t.currency} state=${i}`)}function ee(){process.stdout.write(`hydra-acp-budgeter ${O()}
22
28
 
23
29
  Usage:
24
30
  hydra budgeter [usage] <flags> Report historical cost/usage across sessions
@@ -27,6 +33,6 @@ Usage:
27
33
  Flags:
28
34
  -v, --version Print version and exit
29
35
  -h, --help Show this help
30
- `)}async function q(){const e=process.argv.slice(2);if(e.includes("--version")||e.includes("-v")){process.stdout.write(`hydra-acp-budgeter ${S()}
31
- `);return}if((e[0]==="help"||e.includes("--help")||e.includes("-h"))&&e[0]!=="usage"&&e[0]!=="cost"){Z();return}if(e[0]==="reset"){B();return}if(e[0]==="usage"||e[0]==="cost"){await E(e.slice(1));return}if(e[0]==="run"||process.env.HYDRA_ACP_TOKEN){await K();return}await E(e)}q().catch(e=>{process.stderr.write(`hydra-acp-budgeter: ${e.message}
36
+ `)}async function te(){const t=process.argv.slice(2);if(t.includes("--version")||t.includes("-v")){process.stdout.write(`hydra-acp-budgeter ${O()}
37
+ `);return}if((t[0]==="help"||t.includes("--help")||t.includes("-h"))&&t[0]!=="usage"&&t[0]!=="cost"){ee();return}if(t[0]==="reset"){z();return}if(t[0]==="usage"||t[0]==="cost"){await F(t.slice(1));return}if(t[0]==="run"||process.env.HYDRA_ACP_TOKEN){await X();return}await F(t)}te().catch(t=>{process.stderr.write(`hydra-acp-budgeter: ${t.message}
32
38
  `),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydra-acp/budgeter",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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",