@sreetej510/pi-usage 0.12.4 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,11 @@ usage / rate-limit budgets — OpenAI Codex, Anthropic OAuth, and pi-auth-backed
24
24
  | `/usage --raw` | Show raw usage API responses (debugging) |
25
25
  | `/usage --consume-banked-reset` | Select and consume a Codex banked reset after confirmation |
26
26
 
27
+ Banked reset consumption sends one POST with `credit_id` and `redeem_request_id`, without the
28
+ list-only `OpenAI-Beta` / `originator` headers. It only reports success when Codex returns
29
+ `code: "reset"`. Failed or unclear requests are not automatically retried; run `/usage --refresh`
30
+ before deciding whether to try again.
31
+
27
32
  ## Install
28
33
 
29
34
  ```bash
@@ -78,5 +83,6 @@ Or, for local development, point at the file directly:
78
83
  ```bash
79
84
  npm install
80
85
  npm run --workspace @sreetej510/pi-usage check # biome + typecheck
86
+ npm run --workspace @sreetej510/pi-usage test # mocked requests; never spends real resets
81
87
  npm run --workspace @sreetej510/pi-usage format
82
88
  ```
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import{homedir as Cr}from"node:os";import{join as yr}from"node:path";var yt="usage",ze="openai-codex",Be="anthropic",we="https://chatgpt.com/backend-api/wham/usage",At="https://chatgpt.com/backend-api/wham/rate-limit-reset-credits",Rt="https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume",wt="codex-1",je="https://api.anthropic.com/api/oauth/usage",Se=15e3,b=180*1e3,We=3,St=1e3,bt=900*1e3,Et=30*1e3,ie=3600*1e3,W=yr(Cr(),".pi","agent","usage-cache.json"),He=1,se="provider-usage",qe=20,vt=29,ae=600,Ut="\x1B[39m",_t=new Set(["five_hour","seven_day","extra_usage"]),Ke=[{value:"--refresh",label:"--refresh",description:"Refresh usage instead of cached data"},{value:"--timeout ",label:"--timeout",description:"Set query timeout in seconds"},{value:"--raw",label:"--raw",description:"Show raw usage API responses (for debugging)"},{value:"--consume-banked-reset",label:"--consume-banked-reset",description:"Select and consume a Codex banked reset"}];function H(e){return e?.provider===ze}function de(e){return e?.provider===Be}function O(e){return H(e)||de(e)}function P(e,r){return r?e.provider==="codex"&&H(r)||e.provider==="anthropic"&&de(r):!1}function Ve(e){return de(e)?"anthropic":"codex"}function D(e){return kt(e,ze)}function I(e){return kt(e,Be)}function Mt(e,r){let t=D(e).length>0,n=I(e).length>0;return r.filter(o=>o.provider==="codex"&&t||o.provider==="anthropic"&&n)}function kt(e,r){let t=e.modelRegistry.getAvailable(),n=[],o=new Set,i=a=>{if(!a||a.provider!==r)return;let s=`${a.provider}/${a.id}`;o.has(s)||(o.add(s),n.push(a))};e.model&&i(t.find(a=>a.provider===e.model?.provider&&a.id===e.model.id));for(let a of t)i(a);return n}function Pt(e){return new Promise(r=>{setTimeout(r,e).unref?.()})}function x(e){return e instanceof Error?e.message:String(e)}function q(e,r){let t;try{t=JSON.parse(e)}catch(n){throw new Error(`${r} was not valid JSON: ${x(n)}`)}return g(t,r)}function g(e,r){if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`${r} was not an object.`);return e}function f(e){return typeof e=="string"?e:void 0}function m(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"&&e.trim()){let r=Number(e);return Number.isFinite(r)?r:void 0}}function F(e){return typeof e=="boolean"?e:void 0}function C(e,r){return Object.keys(e).some(t=>t.toLowerCase()===r.toLowerCase())}function K(e){return ue(e.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi,"Bearer <redacted>").replace(/"access_token"\s*:\s*"[^"]+"/gi,'"access_token":"<redacted>"').trim(),ae)}function ue(e,r){return e.length<=r?e:`${e.slice(0,r-1)}\u2026`}function Qe(e){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e.slice(0,ae*4)}}function be(e){let r=Math.round(e/6e4);if(r<60)return`${Math.max(1,r)}m`;let t=Math.floor(r/60);return t<24?`${t}h`:`${Math.floor(t/24)}d`}function v(e){return Number.isFinite(e)?Math.min(100,Math.max(0,e)):0}function $t(e,r){return Number.isFinite(e)?new Intl.NumberFormat(void 0,{maximumFractionDigits:2}).format(e):r}var Ar={USD:"$",CAD:"$",AUD:"$",EUR:"\u20AC",GBP:"\xA3",JPY:"\xA5"};function U(e,r,t=2){if(!Number.isFinite(e))return String(e);let n=new Intl.NumberFormat(void 0,{minimumFractionDigits:t,maximumFractionDigits:t}).format(e),o=Ar[r.toUpperCase()];return o?`${o}${n}`:`${r} ${n}`}function Ee(e){let r=e.replace(/[_-]+/g," ").trim();return(r.match(/\bcodex\s+(.+)$/i)?.[1]?.trim()||r).toLowerCase().replace(/\s+/g," ")}function V(e){return e?.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||void 0}function Je(e,r){let t=V(r);t&&e.add(t)}function Tt(e,r){return e===r||e.startsWith(`${r}-`)||e.endsWith(`-${r}`)||e.includes(`-${r}-`)}function Xe(e){return e.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()}async function Ye(e){let r=I(e),t=[];for(let n of r){let o=await e.modelRegistry.getApiKeyAndHeaders(n);if(!o.ok){t.push(o.error);continue}let i={};for(let[a,s]of Object.entries(o.headers??{}))typeof s=="string"&&(i[a]=s);if(!C(i,"Authorization")&&o.apiKey&&(i.Authorization=`Bearer ${o.apiKey}`),C(i,"Accept")||(i.Accept="application/json"),C(i,"User-Agent")||(i["User-Agent"]="pi-usage"),C(i,"Authorization"))return{headers:i}}if(t.length>0)throw new Error(t.join("; "))}import{readFileSync as Rr}from"node:fs";import{homedir as wr}from"node:os";import{join as Sr}from"node:path";async function ce(e){let r=D(e),t=[];for(let n of r){let o=await e.modelRegistry.getApiKeyAndHeaders(n);if(!o.ok){t.push(o.error);continue}let i={};for(let[a,s]of Object.entries(o.headers??{}))typeof s=="string"&&(i[a]=s);if(!C(i,"Authorization")&&o.apiKey&&(i.Authorization=`Bearer ${o.apiKey}`),C(i,"User-Agent")||(i["User-Agent"]="pi-codex-usage"),C(i,"Authorization"))return{headers:i}}if(t.length>0)throw new Error(t.join("; "))}async function Ge(e){let r=await ce(e);if(!r)return;let t={...r.headers};if(C(t,"Accept")||(t.Accept="application/json"),C(t,"Content-Type")||(t["Content-Type"]="application/json"),C(t,"OpenAI-Beta")||(t["OpenAI-Beta"]=wt),C(t,"originator")||(t.originator="Codex Desktop"),!C(t,"ChatGPT-Account-ID")){let n=br();n&&(t["ChatGPT-Account-ID"]=n)}return{headers:t}}function br(){try{let e=JSON.parse(Rr(Sr(wr(),".codex","auth.json"),"utf8"));return f(e.tokens?.account_id)??f(e.tokens?.accountId)}catch{return}}function y(e){return e instanceof Error&&e.message.includes("This extension ctx is stale after session replacement or reload")}var ve=class extends Error{retryAfterMs;constructor(r,t){super(r),this.name="UsageEndpointError",this.retryAfterMs=t}};function Q(e){return/\b429\b|rate_limit_error|rate.?limited/i.test(e)}function J(e,r,t){let n=`${e} usage endpoint returned ${r.status} ${r.statusText}: ${K(t)}`;throw new ve(n,r.status===429?Er(r):void 0)}function Er(e){let r=e.headers.get("retry-after");if(!r)return;let t=Number(r);if(Number.isFinite(t)&&t>=0)return t*1e3;let n=Date.parse(r);if(!Number.isNaN(n))return Math.max(0,n-Date.now())}function Ue(e){for(let r of e)if(r.cause instanceof ve&&r.cause.retryAfterMs!==void 0)return Math.min(Math.max(r.cause.retryAfterMs,Et),ie);return bt}async function _(e,r,t,n="usage"){let o=new AbortController,i=setTimeout(()=>o.abort(),t);try{return await fetch(e,{...r,signal:o.signal})}catch(a){throw o.signal.aborted?new Error(`Timed out after ${Math.round(t/1e3)}s while fetching ${n}.`):a}finally{clearTimeout(i)}}function Ot(e,r){let t=[" >_ OpenAI Codex Usage",""];for(let n of e.snapshots){let o=n.limitName??n.limitId;_e(n)||t.push(` ${o} limit:`),n.primary&&t.push(Lt("5h limit:",n.primary)),n.secondary&&t.push(Lt("7d limit:",n.secondary)),!n.primary&&!n.secondary&&t.push(" Limits unavailable for this account")}if(e.bankedResetsAvailable!==void 0){t.push("");let n=e.nextBankedResetExpiresAt?` (next expires ${Ft(e.nextBankedResetExpiresAt)})`:"";t.push(` Banked resets available: ${e.bankedResetsAvailable}${n}`)}return t.join(`
2
- `)}function Dt(e,r){let t=_r(e,r);if(!t)return"usage unavailable";let n=[Pr(t)];return t.primary&&n.push(`${v(t.primary.usedPercent).toFixed(0)}% 5h`),t.secondary&&n.push(`${v(t.secondary.usedPercent).toFixed(0)}% 7d`),n.length===1&&t.credits&&n.push(Lr(t.credits)),n.join(" ")}function It(e,r){return e.provider==="anthropic"?e.statusline:Dt(e,r)}function vr(e,r){return e.provider==="anthropic"?e.summaryLines.join(`
3
- `):Ot(e,r)}function Me(e,r,t){let o=$r(r,e.model).map(i=>vr(i,t?Date.now()-i.capturedAt:void 0)).join(`
1
+ import{homedir as Cr}from"node:os";import{join as yr}from"node:path";var yt="usage",ze="openai-codex",Be="anthropic",Re="https://chatgpt.com/backend-api/wham/usage",At="https://chatgpt.com/backend-api/wham/rate-limit-reset-credits",wt="https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume",Rt="codex-1",je="https://api.anthropic.com/api/oauth/usage",Se=15e3,b=180*1e3,We=3,St=1e3,bt=900*1e3,Et=30*1e3,ie=3600*1e3,H=yr(Cr(),".pi","agent","usage-cache.json"),He=1,se="provider-usage",Ke=20,vt=29,ae=600,Ut="\x1B[39m",Mt=new Set(["five_hour","seven_day","extra_usage"]),qe=[{value:"--refresh",label:"--refresh",description:"Refresh usage instead of cached data"},{value:"--timeout ",label:"--timeout",description:"Set query timeout in seconds"},{value:"--raw",label:"--raw",description:"Show raw usage API responses (for debugging)"},{value:"--consume-banked-reset",label:"--consume-banked-reset",description:"Select and consume a Codex banked reset"}];function K(e){return e?.provider===ze}function de(e){return e?.provider===Be}function I(e){return K(e)||de(e)}function P(e,r){return r?e.provider==="codex"&&K(r)||e.provider==="anthropic"&&de(r):!1}function Ve(e){return de(e)?"anthropic":"codex"}function O(e){return kt(e,ze)}function D(e){return kt(e,Be)}function _t(e,r){let t=O(e).length>0,n=D(e).length>0;return r.filter(o=>o.provider==="codex"&&t||o.provider==="anthropic"&&n)}function kt(e,r){let t=e.modelRegistry.getAvailable(),n=[],o=new Set,i=a=>{if(!a||a.provider!==r)return;let s=`${a.provider}/${a.id}`;o.has(s)||(o.add(s),n.push(a))};e.model&&i(t.find(a=>a.provider===e.model?.provider&&a.id===e.model.id));for(let a of t)i(a);return n}function Pt(e){return new Promise(r=>{setTimeout(r,e).unref?.()})}function x(e){return e instanceof Error?e.message:String(e)}function F(e,r){let t;try{t=JSON.parse(e)}catch(n){throw new Error(`${r} was not valid JSON: ${x(n)}`)}return g(t,r)}function g(e,r){if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`${r} was not an object.`);return e}function f(e){return typeof e=="string"?e:void 0}function m(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"&&e.trim()){let r=Number(e);return Number.isFinite(r)?r:void 0}}function z(e){return typeof e=="boolean"?e:void 0}function C(e,r){return Object.keys(e).some(t=>t.toLowerCase()===r.toLowerCase())}function q(e){return ue(e.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/gi,"Bearer <redacted>").replace(/"access_token"\s*:\s*"[^"]+"/gi,'"access_token":"<redacted>"').trim(),ae)}function ue(e,r){return e.length<=r?e:`${e.slice(0,r-1)}\u2026`}function Qe(e){try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e.slice(0,ae*4)}}function be(e){let r=Math.round(e/6e4);if(r<60)return`${Math.max(1,r)}m`;let t=Math.floor(r/60);return t<24?`${t}h`:`${Math.floor(t/24)}d`}function v(e){return Number.isFinite(e)?Math.min(100,Math.max(0,e)):0}function $t(e,r){return Number.isFinite(e)?new Intl.NumberFormat(void 0,{maximumFractionDigits:2}).format(e):r}var Ar={USD:"$",CAD:"$",AUD:"$",EUR:"\u20AC",GBP:"\xA3",JPY:"\xA5"};function U(e,r,t=2){if(!Number.isFinite(e))return String(e);let n=new Intl.NumberFormat(void 0,{minimumFractionDigits:t,maximumFractionDigits:t}).format(e),o=Ar[r.toUpperCase()];return o?`${o}${n}`:`${r} ${n}`}function Ee(e){let r=e.replace(/[_-]+/g," ").trim();return(r.match(/\bcodex\s+(.+)$/i)?.[1]?.trim()||r).toLowerCase().replace(/\s+/g," ")}function V(e){return e?.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||void 0}function Je(e,r){let t=V(r);t&&e.add(t)}function Tt(e,r){return e===r||e.startsWith(`${r}-`)||e.endsWith(`-${r}`)||e.includes(`-${r}-`)}function Xe(e){return e.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()}async function Ye(e){let r=D(e),t=[];for(let n of r){let o=await e.modelRegistry.getApiKeyAndHeaders(n);if(!o.ok){t.push(o.error);continue}let i={};for(let[a,s]of Object.entries(o.headers??{}))typeof s=="string"&&(i[a]=s);if(!C(i,"Authorization")&&o.apiKey&&(i.Authorization=`Bearer ${o.apiKey}`),C(i,"Accept")||(i.Accept="application/json"),C(i,"User-Agent")||(i["User-Agent"]="pi-usage"),C(i,"Authorization"))return{headers:i}}if(t.length>0)throw new Error(t.join("; "))}import{readFileSync as wr}from"node:fs";import{homedir as Rr}from"node:os";import{join as Sr}from"node:path";async function ce(e){let r=O(e),t=[];for(let n of r){let o=await e.modelRegistry.getApiKeyAndHeaders(n);if(!o.ok){t.push(o.error);continue}let i={};for(let[a,s]of Object.entries(o.headers??{}))typeof s=="string"&&(i[a]=s);if(!C(i,"Authorization")&&o.apiKey&&(i.Authorization=`Bearer ${o.apiKey}`),C(i,"User-Agent")||(i["User-Agent"]="pi-codex-usage"),C(i,"Authorization"))return{headers:i}}if(t.length>0)throw new Error(t.join("; "))}async function Ge(e){let r=await ce(e);if(!r)return;let t={...r.headers};if(C(t,"Accept")||(t.Accept="application/json"),C(t,"Content-Type")||(t["Content-Type"]="application/json"),C(t,"OpenAI-Beta")||(t["OpenAI-Beta"]=Rt),C(t,"originator")||(t.originator="Codex Desktop"),!C(t,"ChatGPT-Account-ID")){let n=br();n&&(t["ChatGPT-Account-ID"]=n)}return{headers:t}}function br(){try{let e=JSON.parse(wr(Sr(Rr(),".codex","auth.json"),"utf8"));return f(e.tokens?.account_id)??f(e.tokens?.accountId)}catch{return}}function y(e){return e instanceof Error&&e.message.includes("This extension ctx is stale after session replacement or reload")}var ve=class extends Error{retryAfterMs;constructor(r,t){super(r),this.name="UsageEndpointError",this.retryAfterMs=t}};function Q(e){return/\b429\b|rate_limit_error|rate.?limited/i.test(e)}function J(e,r,t){let n=`${e} usage endpoint returned ${r.status} ${r.statusText}: ${q(t)}`;throw new ve(n,r.status===429?Er(r):void 0)}function Er(e){let r=e.headers.get("retry-after");if(!r)return;let t=Number(r);if(Number.isFinite(t)&&t>=0)return t*1e3;let n=Date.parse(r);if(!Number.isNaN(n))return Math.max(0,n-Date.now())}function Ue(e){for(let r of e)if(r.cause instanceof ve&&r.cause.retryAfterMs!==void 0)return Math.min(Math.max(r.cause.retryAfterMs,Et),ie);return bt}async function M(e,r,t,n="usage"){let o=new AbortController,i=setTimeout(()=>o.abort(),t);try{return await fetch(e,{...r,signal:o.signal})}catch(a){throw o.signal.aborted?new Error(`Timed out after ${Math.round(t/1e3)}s while fetching ${n}.`):a}finally{clearTimeout(i)}}function It(e,r){let t=[" >_ OpenAI Codex Usage",""];for(let n of e.snapshots){let o=n.limitName??n.limitId;Me(n)||t.push(` ${o} limit:`),n.primary&&t.push(Lt("5h limit:",n.primary)),n.secondary&&t.push(Lt("7d limit:",n.secondary)),!n.primary&&!n.secondary&&t.push(" Limits unavailable for this account")}if(e.bankedResetsAvailable!==void 0){t.push("");let n=e.nextBankedResetExpiresAt?` (next expires ${Ft(e.nextBankedResetExpiresAt)})`:"";t.push(` Banked resets available: ${e.bankedResetsAvailable}${n}`)}return t.join(`
2
+ `)}function Ot(e,r){let t=Mr(e,r);if(!t)return"usage unavailable";let n=[Pr(t)];return t.primary&&n.push(`${v(t.primary.usedPercent).toFixed(0)}% 5h`),t.secondary&&n.push(`${v(t.secondary.usedPercent).toFixed(0)}% 7d`),n.length===1&&t.credits&&n.push(Lr(t.credits)),n.join(" ")}function Dt(e,r){return e.provider==="anthropic"?e.statusline:Ot(e,r)}function vr(e,r){return e.provider==="anthropic"?e.summaryLines.join(`
3
+ `):It(e,r)}function _e(e,r,t){let o=$r(r,e.model).map(i=>vr(i,t?Date.now()-i.capturedAt:void 0)).join(`
4
4
 
5
5
  `);e.ui.notify(e.hasUI?Tr(o):o,"info")}function Ze(e,r=!1){if(e.length===0)return"No logged-in Codex or Anthropic providers. Run /login to connect one.";let t=[r?"Some provider usage is unavailable:":"Usage unavailable:"];for(let n of e){let o=n.source==="pi-auth"?"Codex":n.source==="codex-app-server"?"Codex fallback":"Anthropic";t.push(`- ${o}: ${Ur(n.message)}`)}return t.join(`
6
- `)}function Ur(e){let r=e.replace(/\s+/g," ").trim();if(/invalid_grant|refresh token not found|token refresh request failed/i.test(r))return"login expired or invalid; run /login to reconnect.";if(/no .*auth|no api key|not logged in/i.test(r))return"not logged in; run /login to connect.";let t=r.split(/;\s*(?:details|stack)=/i,1)[0]??r;return ue(t,180)}function pe(e){let r=Math.round(v(e)/100*qe);return`[${"\u2588".repeat(r)}${"\u2591".repeat(qe-r)}]`}function _r(e,r){let t=e.snapshots.find(_e);if(!r||!H(r))return t??e.snapshots[0];let n=Mr(r),o=e.snapshots.find(a=>Nt(a).some(s=>n.has(s)));if(o)return o;let i=kr(n);for(let a of i){let s=e.snapshots.filter(u=>!_e(u)&&Nt(u).some(d=>Tt(d,a)));if(s.length===1)return s[0]}return t??e.snapshots[0]}function Mr(e){let r=new Set;Je(r,e.id),Je(r,e.name);for(let t of[...r]){let n=t.indexOf("codex");n>=0&&r.add(t.slice(n))}return r}function Nt(e){return[V(e.limitId),V(e.limitName)].filter(r=>r!==void 0)}function kr(e){let r=new Set;for(let t of e){let n=t.match(/(?:^|-)codex-(.+)$/);n?.[1]&&r.add(n[1])}return[...r]}function Pr(e){if(_e(e))return"codex";let r=e.limitName??e.limitId;return`codex ${Ee(r)}`}function $r(e,r){return[...e].sort((t,n)=>{let o=P(t,r)?0:1,i=P(n,r)?0:1;return o-i})}function Tr(e){return`${Ut}${e}`}function _e(e){return V(e.limitId)==="codex"||V(e.limitName)==="codex"}function Lt(e,r){return` ${e.padEnd(vt)}${Nr(r)}`}function Nr(e){let r=v(e.usedPercent),t=e.resetsAt?` (resets ${Ft(e.resetsAt)})`:"";return`${pe(r)} ${r.toFixed(0)}% used${t}`}function Lr(e){if(!e.hasCredits)return"no credits";if(e.unlimited)return"unlimited credits";let r=e.balance?.trim();return r?`${$t(Number(r),r)} credits`:"credits available"}function Ft(e){let r=new Date(e*1e3);if(Number.isNaN(r.getTime()))return"at an unknown time";let t=new Date,n=`${r.getHours().toString().padStart(2,"0")}:${r.getMinutes().toString().padStart(2,"0")}`;if(r.toDateString()===t.toDateString())return n;let o=r.getDate().toString(),i=r.toLocaleDateString(void 0,{month:"short"});return`${n} on ${o} ${i}`}function jt(e,r){let t=[" >_ Anthropic Usage",""],n=["claude"],o=[];for(let[d,c]of Object.entries(e)){if(_t.has(d)||!c||typeof c!="object"||Array.isArray(c))continue;let p=c,l=m(p.limit_dollars),h=m(p.used_dollars);l===void 0||h===void 0||o.push({key:d,usedPercent:v(m(p.utilization)??0),usedDollars:h,limitDollars:l,resetsAt:f(p.resets_at)})}let i=!1;if(o.length>0){i=!0,o.sort((c,p)=>c.limitDollars-p.limitDollars),t.push(" Enterprise budget windows:");for(let c of o){let p=Ee(c.key).replace(/\b\w/g,h=>h.toUpperCase()),l=c.resetsAt?` (resets ${et(c.resetsAt)})`:"";t.push(` ${p}: ${pe(c.usedPercent)} ${c.usedPercent.toFixed(0)}% used (${U(c.usedDollars,"USD")}/${U(c.limitDollars,"USD")})${l}`)}let d=[...o].sort((c,p)=>p.usedPercent-c.usedPercent)[0];n.push(`${d.usedPercent.toFixed(0)}%`),n.push(`${U(d.usedDollars,"USD",0)}/${U(d.limitDollars,"USD",0)}`)}let a=e.extra_usage;if(a){let d=g(a,"Anthropic extra usage"),c=F(d.is_enabled),p=m(d.used_credits);if(c&&p!==void 0){i&&t.push("");let l=n.length>1;i=!0;let h=f(d.currency)??"USD",te=p/100,w=m(d.monthly_limit)!==void 0?m(d.monthly_limit)/100:void 0,B=v(m(d.utilization)??0),Ae=`${U(te,h)}${w!==void 0?`/${U(w,h)}`:""}`,S=`${U(te,h,0)}${w!==void 0?`/${U(w,h,0)}`:""}`,re=f(d.reset_at)??f(d.resets_at),ne=re?` (resets ${et(re)})`:"";t.push(" Monthly extra usage:"),t.push(` ${pe(B)} ${B.toFixed(0)}% used ${Ae}${ne}`),n.push(`${B.toFixed(0)}%`),n.push(S),l&&n.push("extra")}}let s=zt(e.five_hour),u=zt(e.seven_day);if((s||u)&&(i&&t.push(""),i=!0,t.push(" Subscription usage:"),s&&t.push(` ${Bt("5h",s,!1)}`),u&&t.push(` ${Bt("7d",u,!0)}`),n.length===1&&(s&&n.push(`${s.usedPercent.toFixed(0)}% 5h`),u&&n.push(`${u.usedPercent.toFixed(0)}% 7d`))),!i)throw new Error("Anthropic usage endpoint returned no displayable usage data.");return{provider:"anthropic",source:"anthropic-oauth",capturedAt:r,summaryLines:t,statusline:n.join(" ")}}function zt(e){if(!e)return;let r=g(e,"Anthropic rolling usage window"),t=m(r.utilization);if(t!==void 0)return{usedPercent:v(t),resetsAt:f(r.resets_at)}}function Bt(e,r,t){let n=r.resetsAt?` (resets ${et(r.resetsAt,t)})`:"";return`${e}: ${pe(r.usedPercent)} ${r.usedPercent.toFixed(0)}% used${n}`}function et(e,r=!0){let t=new Date(e);if(Number.isNaN(t.getTime()))return"at an unknown time";let n=new Date,o=`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}`;if(!r&&t.toDateString()===n.toDateString())return o;let i=t.getDate().toString(),a=t.toLocaleDateString(void 0,{month:"short"});return`${o} on ${i} ${a}`}async function tt(e,r){let t=await Ye(e);if(!t)throw new Error("No Pi Anthropic subscription auth was available. Use a Pi Anthropic model and run /login for Anthropic.");let n=await _(je,{headers:t.headers},r,"Anthropic usage"),o=await n.text();n.ok||J("Anthropic",n,o);let i=q(o,"Anthropic usage endpoint response");return jt(i,Date.now())}async function Wt(e,r){let t=[];if(I(e).length>0)try{let n=await Ye(e);if(!n)throw new Error("No Anthropic auth available.");let o=await _(je,{headers:n.headers},r,"Anthropic usage"),i=await o.text();t.push(`>_ Anthropic raw (${o.status}):
7
- ${Qe(i)}`)}catch(n){if(y(n))throw n;t.push(`>_ Anthropic raw: error \u2014 ${x(n)}`)}if(D(e).length>0)try{let n=await ce(e);if(!n)throw new Error("No Codex auth available.");let o=await _(we,{headers:n.headers},r,"Codex usage"),i=await o.text();t.push(`>_ Codex raw (${o.status}):
6
+ `)}function Ur(e){let r=e.replace(/\s+/g," ").trim();if(/invalid_grant|refresh token not found|token refresh request failed/i.test(r))return"login expired or invalid; run /login to reconnect.";if(/no .*auth|no api key|not logged in/i.test(r))return"not logged in; run /login to connect.";let t=r.split(/;\s*(?:details|stack)=/i,1)[0]??r;return ue(t,180)}function pe(e){let r=Math.round(v(e)/100*Ke);return`[${"\u2588".repeat(r)}${"\u2591".repeat(Ke-r)}]`}function Mr(e,r){let t=e.snapshots.find(Me);if(!r||!K(r))return t??e.snapshots[0];let n=_r(r),o=e.snapshots.find(a=>Nt(a).some(s=>n.has(s)));if(o)return o;let i=kr(n);for(let a of i){let s=e.snapshots.filter(u=>!Me(u)&&Nt(u).some(d=>Tt(d,a)));if(s.length===1)return s[0]}return t??e.snapshots[0]}function _r(e){let r=new Set;Je(r,e.id),Je(r,e.name);for(let t of[...r]){let n=t.indexOf("codex");n>=0&&r.add(t.slice(n))}return r}function Nt(e){return[V(e.limitId),V(e.limitName)].filter(r=>r!==void 0)}function kr(e){let r=new Set;for(let t of e){let n=t.match(/(?:^|-)codex-(.+)$/);n?.[1]&&r.add(n[1])}return[...r]}function Pr(e){if(Me(e))return"codex";let r=e.limitName??e.limitId;return`codex ${Ee(r)}`}function $r(e,r){return[...e].sort((t,n)=>{let o=P(t,r)?0:1,i=P(n,r)?0:1;return o-i})}function Tr(e){return`${Ut}${e}`}function Me(e){return V(e.limitId)==="codex"||V(e.limitName)==="codex"}function Lt(e,r){return` ${e.padEnd(vt)}${Nr(r)}`}function Nr(e){let r=v(e.usedPercent),t=e.resetsAt?` (resets ${Ft(e.resetsAt)})`:"";return`${pe(r)} ${r.toFixed(0)}% used${t}`}function Lr(e){if(!e.hasCredits)return"no credits";if(e.unlimited)return"unlimited credits";let r=e.balance?.trim();return r?`${$t(Number(r),r)} credits`:"credits available"}function Ft(e){let r=new Date(e*1e3);if(Number.isNaN(r.getTime()))return"at an unknown time";let t=new Date,n=`${r.getHours().toString().padStart(2,"0")}:${r.getMinutes().toString().padStart(2,"0")}`;if(r.toDateString()===t.toDateString())return n;let o=r.getDate().toString(),i=r.toLocaleDateString(void 0,{month:"short"});return`${n} on ${o} ${i}`}function jt(e,r){let t=[" >_ Anthropic Usage",""],n=["claude"],o=[];for(let[d,c]of Object.entries(e)){if(Mt.has(d)||!c||typeof c!="object"||Array.isArray(c))continue;let p=c,l=m(p.limit_dollars),h=m(p.used_dollars);l===void 0||h===void 0||o.push({key:d,usedPercent:v(m(p.utilization)??0),usedDollars:h,limitDollars:l,resetsAt:f(p.resets_at)})}let i=!1;if(o.length>0){i=!0,o.sort((c,p)=>c.limitDollars-p.limitDollars),t.push(" Enterprise budget windows:");for(let c of o){let p=Ee(c.key).replace(/\b\w/g,h=>h.toUpperCase()),l=c.resetsAt?` (resets ${et(c.resetsAt)})`:"";t.push(` ${p}: ${pe(c.usedPercent)} ${c.usedPercent.toFixed(0)}% used (${U(c.usedDollars,"USD")}/${U(c.limitDollars,"USD")})${l}`)}let d=[...o].sort((c,p)=>p.usedPercent-c.usedPercent)[0];n.push(`${d.usedPercent.toFixed(0)}%`),n.push(`${U(d.usedDollars,"USD",0)}/${U(d.limitDollars,"USD",0)}`)}let a=e.extra_usage;if(a){let d=g(a,"Anthropic extra usage"),c=z(d.is_enabled),p=m(d.used_credits);if(c&&p!==void 0){i&&t.push("");let l=n.length>1;i=!0;let h=f(d.currency)??"USD",te=p/100,R=m(d.monthly_limit)!==void 0?m(d.monthly_limit)/100:void 0,j=v(m(d.utilization)??0),Ae=`${U(te,h)}${R!==void 0?`/${U(R,h)}`:""}`,S=`${U(te,h,0)}${R!==void 0?`/${U(R,h,0)}`:""}`,re=f(d.reset_at)??f(d.resets_at),ne=re?` (resets ${et(re)})`:"";t.push(" Monthly extra usage:"),t.push(` ${pe(j)} ${j.toFixed(0)}% used ${Ae}${ne}`),n.push(`${j.toFixed(0)}%`),n.push(S),l&&n.push("extra")}}let s=zt(e.five_hour),u=zt(e.seven_day);if((s||u)&&(i&&t.push(""),i=!0,t.push(" Subscription usage:"),s&&t.push(` ${Bt("5h",s,!1)}`),u&&t.push(` ${Bt("7d",u,!0)}`),n.length===1&&(s&&n.push(`${s.usedPercent.toFixed(0)}% 5h`),u&&n.push(`${u.usedPercent.toFixed(0)}% 7d`))),!i)throw new Error("Anthropic usage endpoint returned no displayable usage data.");return{provider:"anthropic",source:"anthropic-oauth",capturedAt:r,summaryLines:t,statusline:n.join(" ")}}function zt(e){if(!e)return;let r=g(e,"Anthropic rolling usage window"),t=m(r.utilization);if(t!==void 0)return{usedPercent:v(t),resetsAt:f(r.resets_at)}}function Bt(e,r,t){let n=r.resetsAt?` (resets ${et(r.resetsAt,t)})`:"";return`${e}: ${pe(r.usedPercent)} ${r.usedPercent.toFixed(0)}% used${n}`}function et(e,r=!0){let t=new Date(e);if(Number.isNaN(t.getTime()))return"at an unknown time";let n=new Date,o=`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}`;if(!r&&t.toDateString()===n.toDateString())return o;let i=t.getDate().toString(),a=t.toLocaleDateString(void 0,{month:"short"});return`${o} on ${i} ${a}`}async function tt(e,r){let t=await Ye(e);if(!t)throw new Error("No Pi Anthropic subscription auth was available. Use a Pi Anthropic model and run /login for Anthropic.");let n=await M(je,{headers:t.headers},r,"Anthropic usage"),o=await n.text();n.ok||J("Anthropic",n,o);let i=F(o,"Anthropic usage endpoint response");return jt(i,Date.now())}async function Wt(e,r){let t=[];if(D(e).length>0)try{let n=await Ye(e);if(!n)throw new Error("No Anthropic auth available.");let o=await M(je,{headers:n.headers},r,"Anthropic usage"),i=await o.text();t.push(`>_ Anthropic raw (${o.status}):
7
+ ${Qe(i)}`)}catch(n){if(y(n))throw n;t.push(`>_ Anthropic raw: error \u2014 ${x(n)}`)}if(O(e).length>0)try{let n=await ce(e);if(!n)throw new Error("No Codex auth available.");let o=await M(Re,{headers:n.headers},r,"Codex usage"),i=await o.text();t.push(`>_ Codex raw (${o.status}):
8
8
  ${Qe(i)}`)}catch(n){if(y(n))throw n;t.push(`>_ Codex raw: error \u2014 ${x(n)}`)}return t.length===0?"No providers with usable auth found.":t.join(`
9
9
 
10
- `)}function rt(e){let r=e.trimStart();if(r==="")return[...Ke];let t=/\s$/.test(r),n=r.trimEnd().split(/\s+/).filter(Boolean),o=n.at(-1);if(o==="--timeout"&&t||o==="--consume-banked-reset"&&t||!t&&n.at(-2)==="--timeout"||!t&&n.at(-2)==="--consume-banked-reset")return null;let i=t?"":o??"";if(i&&!i.startsWith("-"))return null;let a=t?"":r.match(/\S+$/)?.[0]??"",s=t?r:r.slice(0,r.length-a.length),u=Ke.filter(d=>d.value.startsWith(i));return u.length>0?u.map(d=>({...d,value:`${s}${d.value}`})):null}function nt(e){let r=e.trim().split(/\s+/).filter(Boolean),t=!1,n,o=!1,i=!1,a=Se;for(let s=0;s<r.length;s++){let u=r[s];if(u==="--raw"){o=!0;continue}if(u==="--consume-banked-reset"){t=!0;let d=r[s+1];d&&!d.startsWith("-")&&(n=d,s+=1);continue}if(u==="--refresh"){i=!0;continue}if(u==="--timeout"){let d=r[s+1];if(!d)return{ok:!1,error:"Usage: /usage [--refresh] [--raw] [--consume-banked-reset [id]] [--timeout seconds]"};let c=Number(d);if(!Number.isFinite(c)||c<=0||c>120)return{ok:!1,error:"--timeout must be a number of seconds between 1 and 120."};a=Math.round(c*1e3),s+=1;continue}return{ok:!1,error:`Unknown option: ${u}. Usage: /usage [--refresh] [--raw] [--consume-banked-reset [id]] [--timeout seconds]`}}return o&&t?{ok:!1,error:"Choose only one of: --raw, --consume-banked-reset."}:{ok:!0,value:{consumeBankedReset:t,consumeBankedResetId:n,raw:o,refresh:i,timeoutMs:a}}}import{randomUUID as Or}from"node:crypto";async function ke(e,r){let t=await Ge(e);if(!t)throw new Error("No Pi OpenAI Codex auth was available. Use a Pi OpenAI Codex model or run /login for OpenAI ChatGPT Plus/Pro (Codex).");let n=await _(At,{headers:t.headers},r,"Codex banked resets"),o=await n.text();n.ok||J("Codex banked resets",n,o);let i=q(o,"Codex banked reset credits response");return Dr(i)}async function Ht(e,r,t){let n=await Ge(e);if(!n)throw new Error("No Pi OpenAI Codex auth was available. Use a Pi OpenAI Codex model or run /login for OpenAI ChatGPT Plus/Pro (Codex).");let o=Or(),i=[{id:t,redeem_request_id:o},{credit_id:t,redeem_request_id:o},{rate_limit_reset_credit_id:t,redeem_request_id:o},{id:t,redeemRequestId:o},{credit_id:t,redeemRequestId:o},{rate_limit_reset_credit_id:t,redeemRequestId:o}],a;for(let s of i){let u=await _(Rt,{method:"POST",headers:n.headers,body:JSON.stringify(s)},r,"Codex consume banked reset"),d=await u.text();if(u.ok)return;if(a=new Error(`Codex consume banked reset returned ${u.status} ${u.statusText}: ${K(d)}`),u.status!==400&&u.status!==422)break}throw a??new Error("Failed to consume Codex banked reset.")}function Dr(e){let t=(Array.isArray(e.credits)?e.credits:[]).map(o=>Ir(o)).filter(o=>o!==void 0),n=m(e.available_count)??m(e.availableCount)??t.filter(o=>(o.status??"available")==="available").length;return{availableCount:Math.max(0,Math.trunc(n)),credits:t}}function Ir(e){if(!e)return;let r=g(e,"Codex reset credit"),t=f(r.id);if(t)return{id:t,resetType:f(r.reset_type)??f(r.resetType),status:f(r.status),grantedAt:f(r.granted_at)??f(r.grantedAt),expiresAt:f(r.expires_at)??f(r.expiresAt)}}function Pe(e){let r=e.expiresAt?`expires ${Fr(e.expiresAt)}`:"no expiry shown";return`${e.id} \u2014 ${r}`}function qt(e){let r=Date.now(),t=e.credits.filter(n=>(n.status??"available").toLowerCase()==="available").map(n=>n.expiresAt?Date.parse(n.expiresAt):Number.NaN).filter(n=>Number.isFinite(n)&&n>r);if(t.length!==0)return Math.min(...t)/1e3}function Fr(e,r=!0){let t=new Date(e);if(Number.isNaN(t.getTime()))return"at an unknown time";let n=new Date,o=`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}`;if(!r&&t.toDateString()===n.toDateString())return o;let i=t.getDate().toString(),a=t.toLocaleDateString(void 0,{month:"short"});return`${o} on ${i} ${a}`}import{spawn as Hr}from"node:child_process";import{createInterface as qr}from"node:readline";function ot(e,r,t){let n=[],o=f(e.plan_type),i=Xt(e.rate_limit_reset_credits),a=Kt("codex",void 0,e.rate_limit,e.credits);a&&n.push(a);let s=Array.isArray(e.additional_rate_limits)?e.additional_rate_limits:[];for(let u of s){let d=g(u,"additional rate limit"),c=f(d.metered_feature)??f(d.limit_name);if(!c)continue;let p=Kt(c,f(d.limit_name),d.rate_limit,void 0);p&&n.push(p)}if(n.length===0)throw new Error("Codex usage endpoint returned no displayable rate-limit windows.");return{provider:"codex",source:t,capturedAt:r,planType:o,bankedResetsAvailable:i,snapshots:n}}function Kt(e,r,t,n){if(t==null){let u=Qt(n);return u?{limitId:e,limitName:r,credits:u}:void 0}let o=g(t,"rate limit"),i=Vt(o.primary_window),a=Vt(o.secondary_window),s=Qt(n);if(!(!i&&!a&&!s))return{limitId:e,limitName:r,primary:i,secondary:a,credits:s}}function Vt(e){if(e==null)return;let r=g(e,"rate-limit window"),t=m(r.used_percent);if(t===void 0)return;let n=m(r.limit_window_seconds),o=m(r.reset_at);return{usedPercent:t,windowMinutes:n&&n>0?Math.ceil(n/60):void 0,resetsAt:o}}function Qt(e){if(e==null)return;let r=g(e,"credits"),t=F(r.has_credits),n=F(r.unlimited);if(!(t===void 0||n===void 0))return{hasCredits:t,unlimited:n,balance:f(r.balance)}}function it(e,r){let t=[],n=Xt(e.rateLimitResetCredits),o=(a,s)=>{let u=Br(a,s);if(!u)return;let d=t.findIndex(c=>c.limitId===u.limitId);d>=0?t[d]=Wr(t[d],u):t.push(u)};if(o(e.rateLimits,"codex"),e.rateLimitsByLimitId&&typeof e.rateLimitsByLimitId=="object")for(let[a,s]of Object.entries(e.rateLimitsByLimitId))o(s,a);if(t.length===0)throw new Error("codex app-server returned no displayable rate-limit windows.");let i=zr(e.rateLimits);return{provider:"codex",source:"codex-app-server",capturedAt:r,planType:i,bankedResetsAvailable:n,snapshots:t}}function zr(e){if(e==null)return;let r=g(e,"app-server rate-limit snapshot");return f(r.planType)}function Br(e,r){if(e==null)return;let t=g(e,"app-server rate-limit snapshot"),n=f(t.limitId)??r,o=f(t.limitName),i=Jt(t.primary),a=Jt(t.secondary),s=jr(t.credits);if(!(!i&&!a&&!s))return{limitId:n,limitName:o,primary:i,secondary:a,credits:s}}function Jt(e){if(e==null)return;let r=g(e,"app-server rate-limit window"),t=m(r.usedPercent);if(t!==void 0)return{usedPercent:t,windowMinutes:m(r.windowDurationMins),resetsAt:m(r.resetsAt)}}function jr(e){if(e==null)return;let r=g(e,"app-server credits"),t=F(r.hasCredits),n=F(r.unlimited);if(!(t===void 0||n===void 0))return{hasCredits:t,unlimited:n,balance:f(r.balance)}}function Xt(e){if(e==null)return;let r=g(e,"rate limit reset credits"),t=m(r.available_count)??m(r.availableCount);return t!==void 0?Math.max(0,Math.trunc(t)):void 0}function Wr(e,r){return{limitId:r.limitId||e.limitId,limitName:r.limitName??e.limitName,primary:r.primary??e.primary,secondary:r.secondary??e.secondary,credits:r.credits??e.credits}}async function $e(e){let r=new st(e);try{await r.start(),await r.request("initialize",{clientInfo:{name:"pi_codex_usage",title:"Pi Codex Usage",version:"0.1.0"},capabilities:{experimentalApi:!1,requestAttestation:!1,optOutNotificationMethods:[]}}),r.notify("initialized");let t=await r.request("account/rateLimits/read",void 0);return it(g(t,"account/rateLimits/read result"),Date.now())}finally{r.dispose()}}var st=class{child;nextId=1;stderr="";pending=new Map;startPromise;exitError;timeoutMs;constructor(r){this.timeoutMs=r}start(){return this.startPromise?this.startPromise:(this.startPromise=new Promise((r,t)=>{let n=Hr("codex",["app-server","--listen","stdio://"],{stdio:["pipe","pipe","pipe"]});this.child=n;let o=setTimeout(()=>{t(new Error(`Timed out after ${Math.round(this.timeoutMs/1e3)}s starting codex app-server.`))},this.timeoutMs);n.once("spawn",()=>{clearTimeout(o),r()}),n.once("error",a=>{clearTimeout(o),t(new Error(`Failed to start codex app-server: ${a.message}`)),this.rejectAll(a)}),n.once("exit",(a,s)=>{let u=this.stderr?` stderr: ${K(this.stderr)}`:"";this.exitError=new Error(`codex app-server exited before completing the request (code ${a??"unknown"}, signal ${s??"none"}).${u}`),this.rejectAll(this.exitError)}),n.stderr.setEncoding("utf8"),n.stderr.on("data",a=>{this.stderr=ue(this.stderr+a,ae)}),qr({input:n.stdout}).on("line",a=>this.handleLine(a))}),this.startPromise)}request(r,t){let n=this.child;if(!n?.stdin.writable)throw new Error("codex app-server is not running.");if(this.exitError)throw this.exitError;let o=this.nextId++,i=t===void 0?{method:r,id:o}:{method:r,id:o,params:t},a=new Promise((s,u)=>{let d=setTimeout(()=>{this.pending.delete(o),u(new Error(`Timed out after ${Math.round(this.timeoutMs/1e3)}s waiting for ${r}.`))},this.timeoutMs);this.pending.set(o,{resolve:c=>{clearTimeout(d),s(c)},reject:c=>{clearTimeout(d),u(c)}})});return n.stdin.write(`${JSON.stringify(i)}
10
+ `)}function rt(e){let r=e.trimStart();if(r==="")return[...qe];let t=/\s$/.test(r),n=r.trimEnd().split(/\s+/).filter(Boolean),o=n.at(-1);if(o==="--timeout"&&t||o==="--consume-banked-reset"&&t||!t&&n.at(-2)==="--timeout"||!t&&n.at(-2)==="--consume-banked-reset")return null;let i=t?"":o??"";if(i&&!i.startsWith("-"))return null;let a=t?"":r.match(/\S+$/)?.[0]??"",s=t?r:r.slice(0,r.length-a.length),u=qe.filter(d=>d.value.startsWith(i));return u.length>0?u.map(d=>({...d,value:`${s}${d.value}`})):null}function nt(e){let r=e.trim().split(/\s+/).filter(Boolean),t=!1,n,o=!1,i=!1,a=Se;for(let s=0;s<r.length;s++){let u=r[s];if(u==="--raw"){o=!0;continue}if(u==="--consume-banked-reset"){t=!0;let d=r[s+1];d&&!d.startsWith("-")&&(n=d,s+=1);continue}if(u==="--refresh"){i=!0;continue}if(u==="--timeout"){let d=r[s+1];if(!d)return{ok:!1,error:"Usage: /usage [--refresh] [--raw] [--consume-banked-reset [id]] [--timeout seconds]"};let c=Number(d);if(!Number.isFinite(c)||c<=0||c>120)return{ok:!1,error:"--timeout must be a number of seconds between 1 and 120."};a=Math.round(c*1e3),s+=1;continue}return{ok:!1,error:`Unknown option: ${u}. Usage: /usage [--refresh] [--raw] [--consume-banked-reset [id]] [--timeout seconds]`}}return o&&t?{ok:!1,error:"Choose only one of: --raw, --consume-banked-reset."}:{ok:!0,value:{consumeBankedReset:t,consumeBankedResetId:n,raw:o,refresh:i,timeoutMs:a}}}import{randomUUID as Ir}from"node:crypto";async function ke(e,r){let t=await Ge(e);if(!t)throw new Error("No Pi OpenAI Codex auth was available. Use a Pi OpenAI Codex model or run /login for OpenAI ChatGPT Plus/Pro (Codex).");let n=await M(At,{headers:t.headers},r,"Codex banked resets"),o=await n.text();n.ok||J("Codex banked resets",n,o);let i=F(o,"Codex banked reset credits response");return Or(i)}async function Ht(e,r,t){let n=await Ge(e);if(!n)throw new Error("No Pi OpenAI Codex auth was available. Use a Pi OpenAI Codex model or run /login for OpenAI ChatGPT Plus/Pro (Codex).");let o=new Headers(n.headers);o.delete("OpenAI-Beta"),o.delete("originator");let i=await M(wt,{method:"POST",headers:o,body:JSON.stringify({credit_id:t,redeem_request_id:Ir()})},r,"Codex consume banked reset"),a=await i.text();if(!i.ok)throw new Error(`Codex consume banked reset returned ${i.status} ${i.statusText}: ${q(a)}`);switch(F(a,"Codex consume banked reset response").code){case"reset":return;case"nothing_to_reset":throw new Error("Codex reports there are no usage windows to reset.");case"no_credit":throw new Error("No Codex banked reset credit is available. Run /usage --refresh.");case"already_redeemed":throw new Error("Codex reported this redemption was already processed. Run /usage --refresh before trying again.");default:throw new Error("Codex returned an unrecognized banked reset result. Run /usage --refresh before trying again.")}}function Or(e){let t=(Array.isArray(e.credits)?e.credits:[]).map(o=>Dr(o)).filter(o=>o!==void 0),n=m(e.available_count)??m(e.availableCount)??t.filter(o=>(o.status??"available")==="available").length;return{availableCount:Math.max(0,Math.trunc(n)),credits:t}}function Dr(e){if(!e)return;let r=g(e,"Codex reset credit"),t=f(r.id);if(t)return{id:t,resetType:f(r.reset_type)??f(r.resetType),status:f(r.status),grantedAt:f(r.granted_at)??f(r.grantedAt),expiresAt:f(r.expires_at)??f(r.expiresAt)}}function Pe(e){let r=e.expiresAt?`expires ${Fr(e.expiresAt)}`:"no expiry shown";return`${e.id} \u2014 ${r}`}function Kt(e){let r=Date.now(),t=e.credits.filter(n=>(n.status??"available").toLowerCase()==="available").map(n=>n.expiresAt?Date.parse(n.expiresAt):Number.NaN).filter(n=>Number.isFinite(n)&&n>r);if(t.length!==0)return Math.min(...t)/1e3}function Fr(e,r=!0){let t=new Date(e);if(Number.isNaN(t.getTime()))return"at an unknown time";let n=new Date,o=`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}`;if(!r&&t.toDateString()===n.toDateString())return o;let i=t.getDate().toString(),a=t.toLocaleDateString(void 0,{month:"short"});return`${o} on ${i} ${a}`}import{spawn as Hr}from"node:child_process";import{createInterface as Kr}from"node:readline";function ot(e,r,t){let n=[],o=f(e.plan_type),i=Xt(e.rate_limit_reset_credits),a=qt("codex",void 0,e.rate_limit,e.credits);a&&n.push(a);let s=Array.isArray(e.additional_rate_limits)?e.additional_rate_limits:[];for(let u of s){let d=g(u,"additional rate limit"),c=f(d.metered_feature)??f(d.limit_name);if(!c)continue;let p=qt(c,f(d.limit_name),d.rate_limit,void 0);p&&n.push(p)}if(n.length===0)throw new Error("Codex usage endpoint returned no displayable rate-limit windows.");return{provider:"codex",source:t,capturedAt:r,planType:o,bankedResetsAvailable:i,snapshots:n}}function qt(e,r,t,n){if(t==null){let u=Qt(n);return u?{limitId:e,limitName:r,credits:u}:void 0}let o=g(t,"rate limit"),i=Vt(o.primary_window),a=Vt(o.secondary_window),s=Qt(n);if(!(!i&&!a&&!s))return{limitId:e,limitName:r,primary:i,secondary:a,credits:s}}function Vt(e){if(e==null)return;let r=g(e,"rate-limit window"),t=m(r.used_percent);if(t===void 0)return;let n=m(r.limit_window_seconds),o=m(r.reset_at);return{usedPercent:t,windowMinutes:n&&n>0?Math.ceil(n/60):void 0,resetsAt:o}}function Qt(e){if(e==null)return;let r=g(e,"credits"),t=z(r.has_credits),n=z(r.unlimited);if(!(t===void 0||n===void 0))return{hasCredits:t,unlimited:n,balance:f(r.balance)}}function it(e,r){let t=[],n=Xt(e.rateLimitResetCredits),o=(a,s)=>{let u=Br(a,s);if(!u)return;let d=t.findIndex(c=>c.limitId===u.limitId);d>=0?t[d]=Wr(t[d],u):t.push(u)};if(o(e.rateLimits,"codex"),e.rateLimitsByLimitId&&typeof e.rateLimitsByLimitId=="object")for(let[a,s]of Object.entries(e.rateLimitsByLimitId))o(s,a);if(t.length===0)throw new Error("codex app-server returned no displayable rate-limit windows.");let i=zr(e.rateLimits);return{provider:"codex",source:"codex-app-server",capturedAt:r,planType:i,bankedResetsAvailable:n,snapshots:t}}function zr(e){if(e==null)return;let r=g(e,"app-server rate-limit snapshot");return f(r.planType)}function Br(e,r){if(e==null)return;let t=g(e,"app-server rate-limit snapshot"),n=f(t.limitId)??r,o=f(t.limitName),i=Jt(t.primary),a=Jt(t.secondary),s=jr(t.credits);if(!(!i&&!a&&!s))return{limitId:n,limitName:o,primary:i,secondary:a,credits:s}}function Jt(e){if(e==null)return;let r=g(e,"app-server rate-limit window"),t=m(r.usedPercent);if(t!==void 0)return{usedPercent:t,windowMinutes:m(r.windowDurationMins),resetsAt:m(r.resetsAt)}}function jr(e){if(e==null)return;let r=g(e,"app-server credits"),t=z(r.hasCredits),n=z(r.unlimited);if(!(t===void 0||n===void 0))return{hasCredits:t,unlimited:n,balance:f(r.balance)}}function Xt(e){if(e==null)return;let r=g(e,"rate limit reset credits"),t=m(r.available_count)??m(r.availableCount);return t!==void 0?Math.max(0,Math.trunc(t)):void 0}function Wr(e,r){return{limitId:r.limitId||e.limitId,limitName:r.limitName??e.limitName,primary:r.primary??e.primary,secondary:r.secondary??e.secondary,credits:r.credits??e.credits}}async function $e(e){let r=new st(e);try{await r.start(),await r.request("initialize",{clientInfo:{name:"pi_codex_usage",title:"Pi Codex Usage",version:"0.1.0"},capabilities:{experimentalApi:!1,requestAttestation:!1,optOutNotificationMethods:[]}}),r.notify("initialized");let t=await r.request("account/rateLimits/read",void 0);return it(g(t,"account/rateLimits/read result"),Date.now())}finally{r.dispose()}}var st=class{child;nextId=1;stderr="";pending=new Map;startPromise;exitError;timeoutMs;constructor(r){this.timeoutMs=r}start(){return this.startPromise?this.startPromise:(this.startPromise=new Promise((r,t)=>{let n=Hr("codex",["app-server","--listen","stdio://"],{stdio:["pipe","pipe","pipe"]});this.child=n;let o=setTimeout(()=>{t(new Error(`Timed out after ${Math.round(this.timeoutMs/1e3)}s starting codex app-server.`))},this.timeoutMs);n.once("spawn",()=>{clearTimeout(o),r()}),n.once("error",a=>{clearTimeout(o),t(new Error(`Failed to start codex app-server: ${a.message}`)),this.rejectAll(a)}),n.once("exit",(a,s)=>{let u=this.stderr?` stderr: ${q(this.stderr)}`:"";this.exitError=new Error(`codex app-server exited before completing the request (code ${a??"unknown"}, signal ${s??"none"}).${u}`),this.rejectAll(this.exitError)}),n.stderr.setEncoding("utf8"),n.stderr.on("data",a=>{this.stderr=ue(this.stderr+a,ae)}),Kr({input:n.stdout}).on("line",a=>this.handleLine(a))}),this.startPromise)}request(r,t){let n=this.child;if(!n?.stdin.writable)throw new Error("codex app-server is not running.");if(this.exitError)throw this.exitError;let o=this.nextId++,i=t===void 0?{method:r,id:o}:{method:r,id:o,params:t},a=new Promise((s,u)=>{let d=setTimeout(()=>{this.pending.delete(o),u(new Error(`Timed out after ${Math.round(this.timeoutMs/1e3)}s waiting for ${r}.`))},this.timeoutMs);this.pending.set(o,{resolve:c=>{clearTimeout(d),s(c)},reject:c=>{clearTimeout(d),u(c)}})});return n.stdin.write(`${JSON.stringify(i)}
11
11
  `),a}notify(r){let t=this.child;t?.stdin.writable&&t.stdin.write(`${JSON.stringify({method:r})}
12
- `)}dispose(){for(let[t,n]of this.pending)n.reject(new Error(`codex app-server request ${t} cancelled.`));this.pending.clear();let r=this.child;r&&(r.stdin.end(),r.killed||r.kill(),this.child=void 0)}handleLine(r){let t;try{t=JSON.parse(r)}catch{return}if(typeof t.id!="number")return;let n=this.pending.get(t.id);if(n){if(this.pending.delete(t.id),t.error){let o=typeof t.error.message=="string"?t.error.message:"unknown error";n.reject(new Error(`codex app-server request failed: ${o}`));return}n.resolve(t.result)}}rejectAll(r){for(let t of this.pending.values())t.reject(r);this.pending.clear()}};async function at(e,r){let t=await ce(e);if(!t)throw new Error("No Pi OpenAI Codex subscription auth was available. Use a Pi OpenAI Codex model or run /login for OpenAI ChatGPT Plus/Pro (Codex).");let n=await _(we,{headers:t.headers},r),o=await n.text();n.ok||J("Codex",n,o);let i=q(o,"Codex usage endpoint response"),a=ot(i,Date.now(),"pi-auth");return Gt(e,r,a)}async function Yt(e,r){try{return{report:await at(e,r),errors:[]}}catch(t){if(y(t))throw t;let n=[{source:"pi-auth",message:x(t),cause:t}];try{let o=await $e(r);return{report:await Gt(e,r,o),errors:[]}}catch(o){if(y(o))throw o;return n.push({source:"codex-app-server",message:x(o),cause:o}),{errors:n}}}}async function Gt(e,r,t){if(t.bankedResetsAvailable===0)return t;try{let n=await ke(e,r);return{...t,bankedResetsAvailable:n.availableCount,nextBankedResetExpiresAt:qt(n)}}catch{return t}}async function dt(e,r){let t=D(e).length>0,n=I(e).length>0,o={errors:[]},[i,a]=await Promise.allSettled([t?Yt(e,r.timeoutMs):Promise.resolve(o),n?tt(e,r.timeoutMs).then(c=>({report:c,errors:[]})):Promise.resolve(o)]),s=[],u=[],d=(c,p)=>{if(c.status==="rejected"){if(y(c.reason))throw c.reason;u.push({source:p,message:x(c.reason),cause:c.reason})}else c.value.report&&s.push(c.value.report),u.push(...c.value.errors)};return d(i,"pi-auth"),d(a,"anthropic-oauth"),{reports:s,errors:u}}async function Zt(e,r){let t;for(let n=1;n<=We;n+=1){if(t=await Kr(e,r),t.ok||t.errors.some(o=>Q(o.message)))return t;n<We&&await Pt(St)}return t??{ok:!1,errors:[{source:"pi-auth",message:"Usage query failed."}]}}async function Kr(e,r){if(de(e.model))try{return{ok:!0,report:await tt(e,r.timeoutMs)}}catch(n){if(y(n))throw n;return{ok:!1,errors:[{source:"anthropic-oauth",message:x(n),cause:n}]}}if(!H(e.model))return{ok:!1,errors:[{source:"pi-auth",message:"Current model provider is not supported."}]};let t=[];try{return{ok:!0,report:await at(e,r.timeoutMs)}}catch(n){if(y(n))throw n;t.push({source:"pi-auth",message:x(n),cause:n})}try{return{ok:!0,report:await $e(r.timeoutMs)}}catch(n){if(y(n))throw n;t.push({source:"codex-app-server",message:x(n),cause:n})}return{ok:!1,errors:t}}import{mkdirSync as Vr,readFileSync as Qr,renameSync as Jr,writeFileSync as er}from"node:fs";import{dirname as Xr}from"node:path";function X(){try{let e=JSON.parse(Qr(W,"utf8"));return!e||e.version!==He||!e.entries||typeof e.entries!="object"?void 0:e}catch{return}}function Te(e){try{let r=X()??{version:He,entries:{}};e(r),Vr(Xr(W),{recursive:!0});let t=`${W}.${process.pid}.tmp`;er(t,JSON.stringify(r));try{Jr(t,W)}catch{er(W,JSON.stringify(r))}}catch{}}function fe(e){Te(r=>{r.entries[e.provider]={createdAt:Date.now(),report:e},r.backoffUntil&&delete r.backoffUntil[e.provider]})}function Ne(e){Te(r=>{delete r.entries[e]})}function Le(e,r){let t=Math.min(r,Date.now()+ie);Te(n=>{n.backoffUntil={...n.backoffUntil??{},[e]:t}})}function tr(){Te(e=>{e.backoffUntil=void 0})}function rr(e){let r=X()?.backoffUntil?.[e]??0;return Math.min(r-Date.now(),ie)}var Y,le,R,$,M=0,G=!1,he;function ct(){return G}function pt(e){G=e}function nr(){return le}function ge(e){le=e}function or(){Y=void 0}var ir=()=>{R&&clearTimeout(R),$&&clearTimeout($),R=void 0,$=void 0};function T(e,r){return y(r)?(e===he&&(M+=1,ir(),he=void 0),!0):!1}var xe=e=>r=>{if(!T(e,r))throw r},k=(e,r)=>{try{return e.ui.setStatus(se,r),!0}catch(t){if(T(e,t))return!1;throw t}};function Z(e){M+=1,ir(),he=void 0,k(e,void 0)}var Yr=e=>{R&&clearTimeout(R);let r=M;R=setTimeout(()=>{R=void 0,!(!G||r!==M)&&k(e,void 0)},b),R.unref?.()},ut=(e,r,t=b)=>{$&&clearTimeout($);let n=M;$=setTimeout(()=>{$=void 0,!(!G||n!==M)&&Ce(e,r).catch(xe(e))},t),$.unref?.()},me=(e,r,t)=>{let n=It(r,t.model);t.staleAgeMs!==void 0&&t.staleAgeMs>b&&(n=`${n} (${be(t.staleAgeMs)} old)`),k(e,n)&&(he=e,R&&clearTimeout(R),R=void 0,t.autoRefresh?ut(e,t.model,t.refreshDelayMs):Yr(e))},Gr=e=>{let r=Y&&P(Y.report,e)?Y:void 0;if(le){let n=le.reports.find(o=>P(o,e));if(n){let o={createdAt:le.createdAt,report:n};(!r||o.createdAt>r.createdAt)&&(r=o)}}let t=X()?.entries?.[Ve(e)];return t?.report&&P(t.report,e)&&(!r||t.createdAt>r.createdAt)&&(r=t),r};async function Ce(e,r){if(!G)return;he=e;let t=r??e.model;if(!O(t)){Z(e);return}let n=M+1;M=n;let o=Gr(t),i=o&&Date.now()-o.createdAt<b?o:void 0;if(i){let d=b-(Date.now()-i.createdAt);me(e,i.report,{autoRefresh:!0,model:t,refreshDelayMs:Math.max(d,1e4)});return}let a=Ve(t),s=rr(a);if(s>0){o?me(e,o.report,{autoRefresh:!0,model:t,staleAgeMs:Date.now()-o.report.capturedAt,refreshDelayMs:Math.max(s,1e4)}):k(e,`usage rate-limited (${be(s)})`)&&ut(e,t,Math.max(s,1e4));return}if(!o&&!k(e,"checking"))return;let u=await Zt(e,{timeoutMs:Se});if(!(!G||n!==M)){if(!u.ok){let d=u.errors.some(l=>Q(l.message)),c=d?Ue(u.errors):b;if(d&&Le(a,Date.now()+c),o){me(e,o.report,{autoRefresh:!0,model:t,staleAgeMs:Date.now()-o.report.capturedAt,refreshDelayMs:c});return}let p=d?`usage rate-limited (${be(c)})`:"usage error";k(e,p)&&ut(e,t,c);return}Y={createdAt:Date.now(),report:u.report},fe(u.report),me(e,u.report,{autoRefresh:!0,model:t})}}function ft(e,r){let t=r.find(n=>P(n,e.model));return t?(Y={createdAt:Date.now(),report:t},me(e,t,{autoRefresh:O(e.model),model:e.model}),!0):(k(e,void 0),!1)}function sr(e){return k(e,"checking")}function Oe(e){return k(e,void 0)}function ar(e){e.registerCommand(yt,{description:"Show usage for all configured providers (Codex and Anthropic)",getArgumentCompletions:rt,handler:async(r,t)=>{try{let n=nt(r);if(!n.ok){t.ui.notify(n.error,"warning");return}if(n.value.raw){let s=n.value.timeoutMs;Wt(t,s).then(u=>{ct()&&t.ui.notify(u,"info")}).catch(u=>{T(t,u)||t.ui.notify(x(u),"error")});return}if(n.value.consumeBankedReset){let s=await ke(t,n.value.timeoutMs),u=s.credits.filter(l=>(l.status??"available").toLowerCase()==="available");if(s.availableCount<=0||u.length===0){t.ui.notify("No Codex banked resets are available.","info");return}if(!t.hasUI){t.ui.notify("Consuming a Codex banked reset requires interactive confirmation.","warning");return}let d=n.value.consumeBankedResetId;if(!d){let l=await t.ui.select("Choose a Codex banked reset to consume",u.map(h=>Pe(h)));if(!l)return;d=u.find(h=>Pe(h)===l)?.id}if(!d){t.ui.notify("Could not determine which banked reset to consume.","warning");return}let c=u.find(l=>l.id===d);if(!c){t.ui.notify(`Codex banked reset ${d} is not available.`,"warning");return}if(!await t.ui.confirm("Consume Codex banked reset?",`${Pe(c)}
12
+ `)}dispose(){for(let[t,n]of this.pending)n.reject(new Error(`codex app-server request ${t} cancelled.`));this.pending.clear();let r=this.child;r&&(r.stdin.end(),r.killed||r.kill(),this.child=void 0)}handleLine(r){let t;try{t=JSON.parse(r)}catch{return}if(typeof t.id!="number")return;let n=this.pending.get(t.id);if(n){if(this.pending.delete(t.id),t.error){let o=typeof t.error.message=="string"?t.error.message:"unknown error";n.reject(new Error(`codex app-server request failed: ${o}`));return}n.resolve(t.result)}}rejectAll(r){for(let t of this.pending.values())t.reject(r);this.pending.clear()}};async function at(e,r){let t=await ce(e);if(!t)throw new Error("No Pi OpenAI Codex subscription auth was available. Use a Pi OpenAI Codex model or run /login for OpenAI ChatGPT Plus/Pro (Codex).");let n=await M(Re,{headers:t.headers},r),o=await n.text();n.ok||J("Codex",n,o);let i=F(o,"Codex usage endpoint response"),a=ot(i,Date.now(),"pi-auth");return Gt(e,r,a)}async function Yt(e,r){try{return{report:await at(e,r),errors:[]}}catch(t){if(y(t))throw t;let n=[{source:"pi-auth",message:x(t),cause:t}];try{let o=await $e(r);return{report:await Gt(e,r,o),errors:[]}}catch(o){if(y(o))throw o;return n.push({source:"codex-app-server",message:x(o),cause:o}),{errors:n}}}}async function Gt(e,r,t){if(t.bankedResetsAvailable===0)return t;try{let n=await ke(e,r);return{...t,bankedResetsAvailable:n.availableCount,nextBankedResetExpiresAt:Kt(n)}}catch{return t}}async function dt(e,r){let t=O(e).length>0,n=D(e).length>0,o={errors:[]},[i,a]=await Promise.allSettled([t?Yt(e,r.timeoutMs):Promise.resolve(o),n?tt(e,r.timeoutMs).then(c=>({report:c,errors:[]})):Promise.resolve(o)]),s=[],u=[],d=(c,p)=>{if(c.status==="rejected"){if(y(c.reason))throw c.reason;u.push({source:p,message:x(c.reason),cause:c.reason})}else c.value.report&&s.push(c.value.report),u.push(...c.value.errors)};return d(i,"pi-auth"),d(a,"anthropic-oauth"),{reports:s,errors:u}}async function Zt(e,r){let t;for(let n=1;n<=We;n+=1){if(t=await qr(e,r),t.ok||t.errors.some(o=>Q(o.message)))return t;n<We&&await Pt(St)}return t??{ok:!1,errors:[{source:"pi-auth",message:"Usage query failed."}]}}async function qr(e,r){if(de(e.model))try{return{ok:!0,report:await tt(e,r.timeoutMs)}}catch(n){if(y(n))throw n;return{ok:!1,errors:[{source:"anthropic-oauth",message:x(n),cause:n}]}}if(!K(e.model))return{ok:!1,errors:[{source:"pi-auth",message:"Current model provider is not supported."}]};let t=[];try{return{ok:!0,report:await at(e,r.timeoutMs)}}catch(n){if(y(n))throw n;t.push({source:"pi-auth",message:x(n),cause:n})}try{return{ok:!0,report:await $e(r.timeoutMs)}}catch(n){if(y(n))throw n;t.push({source:"codex-app-server",message:x(n),cause:n})}return{ok:!1,errors:t}}import{mkdirSync as Vr,readFileSync as Qr,renameSync as Jr,writeFileSync as er}from"node:fs";import{dirname as Xr}from"node:path";function X(){try{let e=JSON.parse(Qr(H,"utf8"));return!e||e.version!==He||!e.entries||typeof e.entries!="object"?void 0:e}catch{return}}function Te(e){try{let r=X()??{version:He,entries:{}};e(r),Vr(Xr(H),{recursive:!0});let t=`${H}.${process.pid}.tmp`;er(t,JSON.stringify(r));try{Jr(t,H)}catch{er(H,JSON.stringify(r))}}catch{}}function fe(e){Te(r=>{r.entries[e.provider]={createdAt:Date.now(),report:e},r.backoffUntil&&delete r.backoffUntil[e.provider]})}function Ne(e){Te(r=>{delete r.entries[e]})}function Le(e,r){let t=Math.min(r,Date.now()+ie);Te(n=>{n.backoffUntil={...n.backoffUntil??{},[e]:t}})}function tr(){Te(e=>{e.backoffUntil=void 0})}function rr(e){let r=X()?.backoffUntil?.[e]??0;return Math.min(r-Date.now(),ie)}var Y,le,w,$,_=0,G=!1,he;function ct(){return G}function pt(e){G=e}function nr(){return le}function ge(e){le=e}function or(){Y=void 0}var ir=()=>{w&&clearTimeout(w),$&&clearTimeout($),w=void 0,$=void 0};function T(e,r){return y(r)?(e===he&&(_+=1,ir(),he=void 0),!0):!1}var xe=e=>r=>{if(!T(e,r))throw r},k=(e,r)=>{try{return e.ui.setStatus(se,r),!0}catch(t){if(T(e,t))return!1;throw t}};function Z(e){_+=1,ir(),he=void 0,k(e,void 0)}var Yr=e=>{w&&clearTimeout(w);let r=_;w=setTimeout(()=>{w=void 0,!(!G||r!==_)&&k(e,void 0)},b),w.unref?.()},ut=(e,r,t=b)=>{$&&clearTimeout($);let n=_;$=setTimeout(()=>{$=void 0,!(!G||n!==_)&&Ce(e,r).catch(xe(e))},t),$.unref?.()},me=(e,r,t)=>{let n=Dt(r,t.model);t.staleAgeMs!==void 0&&t.staleAgeMs>b&&(n=`${n} (${be(t.staleAgeMs)} old)`),k(e,n)&&(he=e,w&&clearTimeout(w),w=void 0,t.autoRefresh?ut(e,t.model,t.refreshDelayMs):Yr(e))},Gr=e=>{let r=Y&&P(Y.report,e)?Y:void 0;if(le){let n=le.reports.find(o=>P(o,e));if(n){let o={createdAt:le.createdAt,report:n};(!r||o.createdAt>r.createdAt)&&(r=o)}}let t=X()?.entries?.[Ve(e)];return t?.report&&P(t.report,e)&&(!r||t.createdAt>r.createdAt)&&(r=t),r};async function Ce(e,r){if(!G)return;he=e;let t=r??e.model;if(!I(t)){Z(e);return}let n=_+1;_=n;let o=Gr(t),i=o&&Date.now()-o.createdAt<b?o:void 0;if(i){let d=b-(Date.now()-i.createdAt);me(e,i.report,{autoRefresh:!0,model:t,refreshDelayMs:Math.max(d,1e4)});return}let a=Ve(t),s=rr(a);if(s>0){o?me(e,o.report,{autoRefresh:!0,model:t,staleAgeMs:Date.now()-o.report.capturedAt,refreshDelayMs:Math.max(s,1e4)}):k(e,`usage rate-limited (${be(s)})`)&&ut(e,t,Math.max(s,1e4));return}if(!o&&!k(e,"checking"))return;let u=await Zt(e,{timeoutMs:Se});if(!(!G||n!==_)){if(!u.ok){let d=u.errors.some(l=>Q(l.message)),c=d?Ue(u.errors):b;if(d&&Le(a,Date.now()+c),o){me(e,o.report,{autoRefresh:!0,model:t,staleAgeMs:Date.now()-o.report.capturedAt,refreshDelayMs:c});return}let p=d?`usage rate-limited (${be(c)})`:"usage error";k(e,p)&&ut(e,t,c);return}Y={createdAt:Date.now(),report:u.report},fe(u.report),me(e,u.report,{autoRefresh:!0,model:t})}}function ft(e,r){let t=r.find(n=>P(n,e.model));return t?(Y={createdAt:Date.now(),report:t},me(e,t,{autoRefresh:I(e.model),model:e.model}),!0):(k(e,void 0),!1)}function sr(e){return k(e,"checking")}function Ie(e){return k(e,void 0)}function ar(e){e.registerCommand(yt,{description:"Show usage for all configured providers (Codex and Anthropic)",getArgumentCompletions:rt,handler:async(r,t)=>{try{let n=nt(r);if(!n.ok){t.ui.notify(n.error,"warning");return}if(n.value.raw){let s=n.value.timeoutMs;Wt(t,s).then(u=>{ct()&&t.ui.notify(u,"info")}).catch(u=>{T(t,u)||t.ui.notify(x(u),"error")});return}if(n.value.consumeBankedReset){let s=await ke(t,n.value.timeoutMs),u=s.credits.filter(l=>(l.status??"available").toLowerCase()==="available");if(s.availableCount<=0||u.length===0){t.ui.notify("No Codex banked resets are available.","info");return}if(!t.hasUI){t.ui.notify("Consuming a Codex banked reset requires interactive confirmation.","warning");return}let d=n.value.consumeBankedResetId;if(!d){let l=await t.ui.select("Choose a Codex banked reset to consume",u.map(h=>Pe(h)));if(!l)return;d=u.find(h=>Pe(h)===l)?.id}if(!d){t.ui.notify("Could not determine which banked reset to consume.","warning");return}let c=u.find(l=>l.id===d);if(!c){t.ui.notify(`Codex banked reset ${d} is not available.`,"warning");return}if(!await t.ui.confirm("Consume Codex banked reset?",`${Pe(c)}
13
13
 
14
- This action cannot be undone.`))return;await Ht(t,n.value.timeoutMs,d),or(),ge(void 0),Ne("codex"),t.ui.notify(`Consumed Codex banked reset ${d}.`,"info"),dt(t,{timeoutMs:n.value.timeoutMs}).then(l=>{if(l.reports.length>0){ge({createdAt:Date.now(),reports:l.reports});for(let h of l.reports)fe(h);Me(t,l.reports,!1)}}).catch(()=>{});return}let o=nr(),i=o&&Date.now()-o.createdAt<b?o:void 0;if(!i){let s=X();if(s){let u=Object.values(s.entries).filter(d=>!!d&&Date.now()-d.createdAt<b);u.length>0&&(i={createdAt:Math.min(...u.map(d=>d.createdAt)),reports:u.map(d=>d.report)})}}if(i){let s=Mt(t,i.reports);i=s.length>0?{...i,reports:s}:void 0}if(i&&!n.value.refresh){ft(t,i.reports),Me(t,i.reports,!0);return}let a=n.value;a.refresh&&tr(),sr(t),dt(t,a).then(s=>{if(!ct())return;let u=new Set(s.reports.map(c=>c.provider));if(!u.has("anthropic")&&s.errors.some(c=>c.source==="anthropic-oauth")&&Ne("anthropic"),!u.has("codex")&&s.errors.some(c=>c.source!=="anthropic-oauth")&&Ne("codex"),s.reports.length===0){ge(void 0),Oe(t),t.ui.notify(Ze(s.errors),"warning");return}ge({createdAt:Date.now(),reports:s.reports});for(let c of s.reports)fe(c);for(let c of s.errors)Q(c.message)&&Le(c.source==="anthropic-oauth"?"anthropic":"codex",Date.now()+Ue([c]));ft(t,s.reports)||Oe(t),Me(t,s.reports,!1),s.errors.length>0&&t.ui.notify(Ze(s.errors,!0),"warning")}).catch(s=>{Oe(t),T(t,s)||t.ui.notify(x(s),"error")})}catch(n){if(T(t,n))return;throw n}}})}import{isAbsolute as Zr,relative as en,resolve as dr,sep as ur}from"node:path";import{truncateToWidth as ye,visibleWidth as z}from"@earendil-works/pi-tui";var cr=!1;function pr(){return cr}function fr(e){cr=e}function mr(e,r){r.ui.setFooter((t,n,o)=>{let i=t,a=n,s=o;return{dispose:s.onBranchChange(()=>i.requestRender()),invalidate(){},render(d){return tn(e,r,a,s,d)}}})}function tn(e,r,t,n,o){let i=0,a=0,s=0,u=0,d=0,c;for(let A of r.sessionManager.getEntries()){let oe=A.message;if(A.type!=="message"||oe?.role!=="assistant")continue;let L=oe.usage??{},gt=m(L.input)??0,gr=m(L.output)??0,Fe=m(L.cacheRead)??0,xt=m(L.cacheWrite)??0,xr=L.cost;i+=gt,a+=gr,s+=Fe,u+=xt,d+=m(xr?.total)??0;let Ct=gt+Fe+xt;c=Ct>0?Fe/Ct*100:void 0}let p=r.getContextUsage(),l=p?.contextWindow??r.model?.contextWindow??0,h=p?.percent??0,te=p&&p.percent!==null?h.toFixed(1):"?",w=nn(r.sessionManager.getCwd(),process.env.HOME||process.env.USERPROFILE),B=n.getGitBranch();B&&(w=`${w} (${B})`);let Ae=r.sessionManager.getSessionName();Ae&&(w=`${w} \u2022 ${Ae}`);let S=[];i&&S.push(`\u2191${ee(i)}`),a&&S.push(`\u2193${ee(a)}`),s&&S.push(`R${ee(s)}`),u&&S.push(`W${ee(u)}`),(s>0||u>0)&&c!==void 0&&S.push(`CH${c.toFixed(1)}%`);let re=r.model?r.modelRegistry.isUsingOAuth(r.model):!1;(d||re)&&S.push(`$${d.toFixed(3)}${re?" (sub)":""}`);let ne=te==="?"?`?/${ee(l)}`:`${te}%/${ee(l)}`,De=ne;h>90?De=t.fg("error",ne):h>70&&(De=t.fg("warning",ne)),S.push(De);let E=S.join(" "),N=z(E);N>o&&(E=ye(E,o,"..."),N=z(E));let Ie=r.model?.id||"no-model",j=Ie;if(r.model?.reasoning){let A=e.getThinkingLevel?.()??"off";j=A==="off"?`${Ie} \u2022 thinking off`:`${Ie} \u2022 ${A}`}if(n.getAvailableProviderCount()>1&&r.model){let A=`(${r.model.provider}) ${j}`;N+2+z(A)<=o&&(j=A)}let mt=z(j),Re;if(N+2+mt<=o)Re=E+" ".repeat(o-N-mt)+j;else{let A=o-N-2;if(A>0){let oe=ye(j,A,""),L=Math.max(0,o-N-z(oe));Re=E+" ".repeat(L)+oe}else Re=E}let lr=t.fg("dim",E),hr=t.fg("dim",Re.slice(E.length)),lt=[ye(t.fg("dim",w),o,t.fg("dim","...")),lr+hr],ht=rn(t,n,o);return ht!==void 0&&lt.push(ht),lt}function rn(e,r,t){let n=r.getExtensionStatuses();if(n.size===0)return;let o=n.get(se),a=Array.from(n.entries()).filter(([p])=>p!==se).sort(([p],[l])=>p.localeCompare(l)).map(([,p])=>Xe(p)).join(" ");if(!o)return a?ye(a,t,e.fg("dim","...")):void 0;let s=Xe(o),u=z(a),d=z(s);if(u+1+d>t)return ye(a?`${a} ${s}`:s,t,e.fg("dim","..."));let c=" ".repeat(Math.max(1,t-u-d));return a+c+s}function ee(e){return e<1e3?e.toString():e<1e4?`${(e/1e3).toFixed(1)}k`:e<1e6?`${Math.round(e/1e3)}k`:e<1e7?`${(e/1e6).toFixed(1)}M`:`${Math.round(e/1e6)}M`}function nn(e,r){if(!r)return e;let t=dr(e),n=dr(r),o=en(n,t);return o===""||o!==".."&&!o.startsWith(`..${ur}`)&&!Zr(o)?o===""?"~":`~${ur}${o}`:e}function on(e){ar(e);let r=t=>{if(!(pr()||!t.hasUI))try{mr(e,t),fr(!0)}catch(n){if(!T(t,n))throw n}};e.on("session_start",(t,n)=>{pt(!0),r(n),O(n.model)?Ce(n,n.model).catch(xe(n)):Z(n)}),e.on("session_tree",(t,n)=>{O(n.model)?Ce(n,n.model).catch(xe(n)):Z(n)}),e.on("model_select",(t,n)=>{O(t.model)?Ce(n,t.model).catch(xe(n)):Z(n)}),e.on("session_shutdown",(t,n)=>{pt(!1),Z(n)})}export{rt as completeCodexStatusArguments,on as default,Ot as formatCodexUsageReport,Dt as formatCodexUsageStatusline,y as isStaleExtensionContextError,it as normalizeAppServerResponse,ot as normalizeBackendPayload,nt as parseArgs};
14
+ This action cannot be undone.`))return;await Ht(t,n.value.timeoutMs,d),or(),ge(void 0),Ne("codex"),t.ui.notify(`Consumed Codex banked reset ${d}.`,"info"),dt(t,{timeoutMs:n.value.timeoutMs}).then(l=>{if(l.reports.length>0){ge({createdAt:Date.now(),reports:l.reports});for(let h of l.reports)fe(h);_e(t,l.reports,!1)}}).catch(()=>{});return}let o=nr(),i=o&&Date.now()-o.createdAt<b?o:void 0;if(!i){let s=X();if(s){let u=Object.values(s.entries).filter(d=>!!d&&Date.now()-d.createdAt<b);u.length>0&&(i={createdAt:Math.min(...u.map(d=>d.createdAt)),reports:u.map(d=>d.report)})}}if(i){let s=_t(t,i.reports);i=s.length>0?{...i,reports:s}:void 0}if(i&&!n.value.refresh){ft(t,i.reports),_e(t,i.reports,!0);return}let a=n.value;a.refresh&&tr(),sr(t),dt(t,a).then(s=>{if(!ct())return;let u=new Set(s.reports.map(c=>c.provider));if(!u.has("anthropic")&&s.errors.some(c=>c.source==="anthropic-oauth")&&Ne("anthropic"),!u.has("codex")&&s.errors.some(c=>c.source!=="anthropic-oauth")&&Ne("codex"),s.reports.length===0){ge(void 0),Ie(t),t.ui.notify(Ze(s.errors),"warning");return}ge({createdAt:Date.now(),reports:s.reports});for(let c of s.reports)fe(c);for(let c of s.errors)Q(c.message)&&Le(c.source==="anthropic-oauth"?"anthropic":"codex",Date.now()+Ue([c]));ft(t,s.reports)||Ie(t),_e(t,s.reports,!1),s.errors.length>0&&t.ui.notify(Ze(s.errors,!0),"warning")}).catch(s=>{Ie(t),T(t,s)||t.ui.notify(x(s),"error")})}catch(n){if(T(t,n))return;throw n}}})}import{isAbsolute as Zr,relative as en,resolve as dr,sep as ur}from"node:path";import{truncateToWidth as ye,visibleWidth as B}from"@earendil-works/pi-tui";var cr=!1;function pr(){return cr}function fr(e){cr=e}function mr(e,r){r.ui.setFooter((t,n,o)=>{let i=t,a=n,s=o;return{dispose:s.onBranchChange(()=>i.requestRender()),invalidate(){},render(d){return tn(e,r,a,s,d)}}})}function tn(e,r,t,n,o){let i=0,a=0,s=0,u=0,d=0,c;for(let A of r.sessionManager.getEntries()){let oe=A.message;if(A.type!=="message"||oe?.role!=="assistant")continue;let L=oe.usage??{},gt=m(L.input)??0,gr=m(L.output)??0,Fe=m(L.cacheRead)??0,xt=m(L.cacheWrite)??0,xr=L.cost;i+=gt,a+=gr,s+=Fe,u+=xt,d+=m(xr?.total)??0;let Ct=gt+Fe+xt;c=Ct>0?Fe/Ct*100:void 0}let p=r.getContextUsage(),l=p?.contextWindow??r.model?.contextWindow??0,h=p?.percent??0,te=p&&p.percent!==null?h.toFixed(1):"?",R=nn(r.sessionManager.getCwd(),process.env.HOME||process.env.USERPROFILE),j=n.getGitBranch();j&&(R=`${R} (${j})`);let Ae=r.sessionManager.getSessionName();Ae&&(R=`${R} \u2022 ${Ae}`);let S=[];i&&S.push(`\u2191${ee(i)}`),a&&S.push(`\u2193${ee(a)}`),s&&S.push(`R${ee(s)}`),u&&S.push(`W${ee(u)}`),(s>0||u>0)&&c!==void 0&&S.push(`CH${c.toFixed(1)}%`);let re=r.model?r.modelRegistry.isUsingOAuth(r.model):!1;(d||re)&&S.push(`$${d.toFixed(3)}${re?" (sub)":""}`);let ne=te==="?"?`?/${ee(l)}`:`${te}%/${ee(l)}`,Oe=ne;h>90?Oe=t.fg("error",ne):h>70&&(Oe=t.fg("warning",ne)),S.push(Oe);let E=S.join(" "),N=B(E);N>o&&(E=ye(E,o,"..."),N=B(E));let De=r.model?.id||"no-model",W=De;if(r.model?.reasoning){let A=e.getThinkingLevel?.()??"off";W=A==="off"?`${De} \u2022 thinking off`:`${De} \u2022 ${A}`}if(n.getAvailableProviderCount()>1&&r.model){let A=`(${r.model.provider}) ${W}`;N+2+B(A)<=o&&(W=A)}let mt=B(W),we;if(N+2+mt<=o)we=E+" ".repeat(o-N-mt)+W;else{let A=o-N-2;if(A>0){let oe=ye(W,A,""),L=Math.max(0,o-N-B(oe));we=E+" ".repeat(L)+oe}else we=E}let lr=t.fg("dim",E),hr=t.fg("dim",we.slice(E.length)),lt=[ye(t.fg("dim",R),o,t.fg("dim","...")),lr+hr],ht=rn(t,n,o);return ht!==void 0&&lt.push(ht),lt}function rn(e,r,t){let n=r.getExtensionStatuses();if(n.size===0)return;let o=n.get(se),a=Array.from(n.entries()).filter(([p])=>p!==se).sort(([p],[l])=>p.localeCompare(l)).map(([,p])=>Xe(p)).join(" ");if(!o)return a?ye(a,t,e.fg("dim","...")):void 0;let s=Xe(o),u=B(a),d=B(s);if(u+1+d>t)return ye(a?`${a} ${s}`:s,t,e.fg("dim","..."));let c=" ".repeat(Math.max(1,t-u-d));return a+c+s}function ee(e){return e<1e3?e.toString():e<1e4?`${(e/1e3).toFixed(1)}k`:e<1e6?`${Math.round(e/1e3)}k`:e<1e7?`${(e/1e6).toFixed(1)}M`:`${Math.round(e/1e6)}M`}function nn(e,r){if(!r)return e;let t=dr(e),n=dr(r),o=en(n,t);return o===""||o!==".."&&!o.startsWith(`..${ur}`)&&!Zr(o)?o===""?"~":`~${ur}${o}`:e}function on(e){ar(e);let r=t=>{if(!(pr()||!t.hasUI))try{mr(e,t),fr(!0)}catch(n){if(!T(t,n))throw n}};e.on("session_start",(t,n)=>{pt(!0),r(n),I(n.model)?Ce(n,n.model).catch(xe(n)):Z(n)}),e.on("session_tree",(t,n)=>{I(n.model)?Ce(n,n.model).catch(xe(n)):Z(n)}),e.on("model_select",(t,n)=>{I(t.model)?Ce(n,t.model).catch(xe(n)):Z(n)}),e.on("session_shutdown",(t,n)=>{pt(!1),Z(n)})}export{rt as completeCodexStatusArguments,on as default,It as formatCodexUsageReport,Ot as formatCodexUsageStatusline,y as isStaleExtensionContextError,it as normalizeAppServerResponse,ot as normalizeBackendPayload,nt as parseArgs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sreetej510/pi-usage",
3
- "version": "0.12.4",
3
+ "version": "0.13.0",
4
4
  "description": "Pi extension that reports provider usage/rate-limit budgets (Codex, Anthropic OAuth, etc.) via /usage, with a live statusline widget.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -28,7 +28,8 @@
28
28
  "prepublishOnly": "npm run build",
29
29
  "check": "biome check . && npm run typecheck",
30
30
  "format": "biome check --write .",
31
- "typecheck": "tsc --noEmit"
31
+ "typecheck": "tsc --noEmit",
32
+ "test": "node --test test/*.test.mjs"
32
33
  },
33
34
  "devDependencies": {
34
35
  "@biomejs/biome": "^2.5.3",