@neilurk12/pi-clean-footer 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -83,7 +83,6 @@ Example:
83
83
  "enabled": true,
84
84
  "showGit": true,
85
85
  "showTokens": true,
86
- "showCache": true,
87
86
  "showCacheRead": true,
88
87
  "showCacheWrites": true,
89
88
  "showContext": true,
@@ -159,6 +158,7 @@ Supported layout segment IDs:
159
158
  - `tokensFull` - input, output, total, cache read, and cache write tokens
160
159
  - `tokensNoCache` - input, output, and total tokens
161
160
  - `tokensTotal` - total tokens only
161
+ - `toks` - tokens-per-second rate or activity indicator
162
162
 
163
163
  `layouts` are selected by the highest `minWidth` less than or equal to the terminal width. `showGit`, `showTokens`, `showContext`, `showDirectory`, and `showEffort` still act as global visibility controls. `showCache` is a deprecated global cache-token gate; use `showCacheRead` and `showCacheWrites` to hide cache read (`↯`) and write (`↥`) counts independently. Unknown or duplicate layout segments are omitted and reported by `/footer config`.
164
164
 
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import _ from"path";import ge from"os";import te from"path";import{existsSync as V,readFileSync as X}from"fs";var j=["model","directory","git","context","tokensFull","tokensNoCache","tokensTotal","toks"],N=["default","minimal","compact","dense","focus","muted"],p=[{minWidth:100,left:["model","directory","git","toks"],right:["context","tokensFull"]},{minWidth:80,left:["model","directory","git"],right:["context","tokensNoCache"]},{minWidth:60,left:["model","directory","git"],right:["context","tokensTotal"]},{minWidth:40,left:["model","directory","git"],right:["context"]},{minWidth:0,left:["model"],right:["context"]}],A=[{minWidth:0,left:["model"],right:["context"]}],U=[{minWidth:80,left:["model","git"],right:["context","tokensTotal"]},{minWidth:0,left:["model"],right:["context"]}],G=[{minWidth:100,left:["model","directory","git","toks"],right:["context","tokensFull"]},{minWidth:60,left:["model","git"],right:["context","tokensNoCache"]},{minWidth:0,left:["model"],right:["context"]}],B=[{minWidth:0,left:["model"],right:["context"]}],O={default:{},minimal:{separator:" \xB7 ",showDirectory:!1,showGit:!1,showTokens:!1,layouts:A},compact:{separator:" \xB7 ",showDirectory:!1,showCacheRead:!1,showCacheWrites:!1,layouts:U},dense:{showCacheRead:!0,showCacheWrites:!0,layouts:G},focus:{showDirectory:!1,showGit:!1,showTokens:!1,layouts:B},muted:{colors:{model:"muted",directory:"dim",git:"muted",gitDirty:"warning",contextNormal:"muted",contextWarning:"warning",contextDanger:"error",tokens:"dim",separator:"dim"}}},f={preset:"default",enabled:!0,showGit:!0,showTokens:!0,showCache:!0,showCacheRead:!0,showCacheWrites:!1,showContext:!0,showDirectory:!0,showEffort:!0,showToks:!0,separator:" | ",layouts:p,gitRefreshDebounceMs:500,contextWarningPercent:70,contextDangerPercent:85,modelAliases:{},colors:{model:"accent",directory:"dim",git:"success",gitDirty:"warning",contextNormal:"success",contextWarning:"warning",contextDanger:"error",tokens:"muted",separator:"dim"}};function b(e,t){return{...e,...t,modelAliases:{...e.modelAliases??{},...t.modelAliases??{}},colors:{...e.colors??{},...t.colors??{}}}}function T(e){let t=[],o=z(e.preset,t),r=O[o],n=b(r,e),s=H(n.layouts);return{config:{...f,...n,preset:o,separator:typeof n.separator=="string"?n.separator:f.separator,layouts:s.layouts,gitRefreshDebounceMs:Q(n.gitRefreshDebounceMs,f.gitRefreshDebounceMs),contextWarningPercent:k(n.contextWarningPercent,f.contextWarningPercent),contextDangerPercent:k(n.contextDangerPercent,f.contextDangerPercent),modelAliases:{...f.modelAliases,...r.modelAliases??{},...e.modelAliases??{}},colors:{...f.colors,...r.colors??{},...e.colors??{}}},loadedPaths:[],warnings:[...t,...s.warnings]}}function z(e,t){return e===void 0||e==="default"?"default":typeof e!="string"?(t.push("preset must be a string; using default preset"),"default"):N.includes(e)?e:(t.push(`unknown preset '${e}'; using default preset`),"default")}function H(e){let t=[];if(e===void 0)return{layouts:p,warnings:t};if(!Array.isArray(e))return{layouts:p,warnings:["layouts must be an array; using default layouts"]};let o=e.flatMap((r,n)=>{if(!J(r))return t.push(`layouts[${n}] must be an object; skipping`),[];let s=K(r.minWidth);if(s===void 0)return t.push(`layouts[${n}].minWidth must be a non-negative number; skipping`),[];let d=x(r.left,`layouts[${n}].left`,t),u=x(r.right,`layouts[${n}].right`,t,new Set(d));return d.length===0&&u.length===0?(t.push(`layouts[${n}] has no visible segments; skipping`),[]):[{minWidth:s,left:d,right:u}]});return o.length===0?(t.push("no valid layouts configured; using default layouts"),{layouts:p,warnings:t}):{layouts:[...o].sort((r,n)=>n.minWidth-r.minWidth),warnings:t}}function x(e,t,o,r=new Set){if(!Array.isArray(e))return o.push(`${t} must be an array; using empty segment list`),[];let n=[];for(let s of e){if(!q(s)){o.push(`${t} contains unknown segment '${String(s)}'; omitting`);continue}if(r.has(s)){o.push(`${t} contains duplicate segment '${s}'; omitting`);continue}r.add(s),n.push(s)}return n}function q(e){return typeof e=="string"&&j.includes(e)}function J(e){return typeof e=="object"&&e!==null}function K(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function Q(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:t}function k(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=100?e:t}function F(e,t){return Y([e,t])}function Y(e){let t=[],o={},r;for(let s of e)if(V(s))try{let d=JSON.parse(X(s,"utf8"));o=b(o,d),t.push(s)}catch(d){r=`${s}: ${d instanceof Error?d.message:String(d)}`}let n=T(o);return{config:n.config,loadedPaths:t,warnings:n.warnings,error:r}}import{execFile as Z}from"child_process";import{promisify as ee}from"util";var R=ee(Z);function S(e){let t={inRepo:!1,dirtyCount:0},o,r=[];e.onChange&&r.push(e.onChange);async function n(){if(!e.enabled){t={inRepo:!1,dirtyCount:0};return}try{let[u,i]=await Promise.all([R("git",["branch","--show-current"],{cwd:e.cwd,timeout:2e3}),R("git",["status","--porcelain"],{cwd:e.cwd,timeout:2e3})]),a=u.stdout.trim()||"detached",g=i.stdout.split(`
2
- `).filter(Boolean).length;t={inRepo:!0,branch:a,dirtyCount:g}}catch{t={inRepo:!1,dirtyCount:0}}for(let u of r)u()}function s(){d(),o=setTimeout(()=>{o=void 0,n()},e.debounceMs)}function d(){o&&(clearTimeout(o),o=void 0)}return{get state(){return t},schedule:s,clear:d,refresh:n,onChange(u){return r.push(u),()=>{let i=r.indexOf(u);i>=0&&r.splice(i,1)}}}}function P(e){var o,r,n,s,d;let t={input:0,output:0,cacheRead:0,cacheWrite:0};for(let u of e){if(u.type!=="message"||((o=u.message)==null?void 0:o.role)!=="assistant")continue;let i=u.message;t.input+=((r=i.usage)==null?void 0:r.input)??0,t.output+=((n=i.usage)==null?void 0:n.output)??0,t.cacheRead+=((s=i.usage)==null?void 0:s.cacheRead)??0,t.cacheWrite+=((d=i.usage)==null?void 0:d.cacheWrite)??0}return t}function y(e){if(typeof e!="string")return;let t=e.toLowerCase();if(t==="medium")return"med";if(t==="extra-high"||t==="extra_high"||t==="x-high")return"xhigh";if(["low","med","high","xhigh"].includes(t))return t}function c(e){return!Number.isFinite(e)||e<=0?"0":e<1e3?`${Math.round(e)}`:e<1e6?`${(e/1e3).toFixed(e<1e4?1:0)}k`:`${(e/1e6).toFixed(1)}m`}var C=class{#t;#n;#d;#e;#o;#c;#g;#f;#l;#r;#s={input:0,output:0,cacheRead:0,cacheWrite:0};#a=0;#i=void 0;#u=void 0;constructor(t){this.#g=t.globalConfigPath,this.#f=t.getProjectConfigPath,this.#l=t.getThinkingLevel,this.#r=t.onRenderNeeded,this.#t=f,this.#n={config:this.#t,loadedPaths:[],warnings:[]},this.#d=void 0,this.#e=void 0,this.#o=!0,this.#c=""}async start(t){this.#s={input:0,output:0,cacheRead:0,cacheWrite:0},this.#a=0,this.#c=t.cwd,this.#n=F(this.#g,this.#f(t.cwd)),this.#t=this.#n.config,this.#d=y(this.#l()),this.#o=this.#t.enabled,this.#o&&(this.#h(t.cwd),await this.#e.refresh())}shutdown(){var t;(t=this.#e)==null||t.clear(),this.#e=void 0,this.#s={input:0,output:0,cacheRead:0,cacheWrite:0},this.#a=0,this.#i=void 0,this.#u=void 0}#h(t){this.#e=S({cwd:t,debounceMs:this.#t.gitRefreshDebounceMs,enabled:this.#t.showGit,onChange:()=>this.#r()})}onThinkingLevel(t){this.#d=y(t),this.#r()}onModelSelect(){this.#r()}onMessageStart(t){t==="assistant"&&(this.#i=Date.now())}onMessageEnd(t,o){if(t==="assistant"){if(this.#i!==void 0&&o&&o>0){let r=Date.now()-this.#i;r>0&&(this.#u=o/(r/1e3))}this.#i=void 0,this.#r()}}onToolEnd(t){var o;["bash","edit","write"].includes(t)&&((o=this.#e)==null||o.schedule()),this.#r()}onUserBash(){var t;(t=this.#e)==null||t.schedule()}async refresh(){var t;await((t=this.#e)==null?void 0:t.refresh())}async reload(t){var o;this.#s={input:0,output:0,cacheRead:0,cacheWrite:0},this.#a=0,this.#i=void 0,this.#u=void 0,this.#n=F(this.#g,this.#f(t.cwd)),this.#t=this.#n.config,this.#o=this.#t.enabled,(o=this.#e)==null||o.clear(),this.#e=void 0,this.#o&&(this.#h(this.#c),await this.#e.refresh()),this.#r()}async toggle(){var t;return this.#s={input:0,output:0,cacheRead:0,cacheWrite:0},this.#a=0,this.#i=void 0,this.#u=void 0,this.#o=!this.#o,this.#o?(this.#d=y(this.#l()),this.#h(this.#c),await this.#e.refresh()):((t=this.#e)==null||t.clear(),this.#e=void 0),this.#r(),this.#o}getFooterInput(t){var r,n,s,d,u,i;let o=t.sessionManager.getBranch();return o.length!==this.#a&&(this.#s=P(o),this.#a=o.length),{modelId:((r=t.model)==null?void 0:r.id)??"no-model",thinkingLevel:this.#d,directory:te.basename(t.cwd),gitBranch:(n=this.#e)==null?void 0:n.state.branch,gitDirtyCount:((s=this.#e)==null?void 0:s.state.dirtyCount)??0,contextUsed:((u=(d=t.getContextUsage)==null?void 0:d.call(t))==null?void 0:u.tokens)??0,contextMax:(i=t.model)==null?void 0:i.contextWindow,totals:this.#s,lastTokPerSec:this.#u,config:this.#t}}get isEnabled(){return this.#o}get loadedError(){return this.#n.error}get loadedWarnings(){return this.#n.warnings}get loadedPaths(){return this.#n.loadedPaths}get config(){return this.#t}};import{truncateToWidth as h,visibleWidth as W}from"@earendil-works/pi-tui";function L(e,t,o,r){let n=e.filter(Boolean).join(o),s=t.filter(Boolean).join(o);return oe(n,s,r)}function oe(e,t,o){if(!t)return h(e,o);if(!e)return h(t,o);let r=o-W(e)-W(t);if(r>=1)return h(e+" ".repeat(r)+t,o);let n=Math.max(1,Math.floor((o-1)/2));return h(e,n)+" "+h(t,o-n-1)}function v(e,t){if(t[e])return t[e];let o=e.toLowerCase(),r=o.includes("/")?o.split("/").pop():o;if(t[r])return t[r];if(r.includes("claude")&&r.includes("sonnet"))return r.includes("4-5")||r.includes("4.5")?"sonnet-4.5":r.includes("4")?"sonnet-4":"sonnet";if(r.includes("claude")&&r.includes("opus"))return"opus";if(r.includes("claude")&&r.includes("haiku"))return"haiku";let n=r.match(/gpt-5(?:[.-][a-z0-9]+)*/);if(n)return n[0];let s=r.match(/gpt-4(?:[.-][a-z0-9]+)*/);if(s)return s[0];let d=r.match(/gemini-[a-z0-9.-]+/);return d?d[0].replace(/-preview.*/,""):r.length>24?`${r.slice(0,21)}\u2026`:r}function I(e,t){let o=e.input+e.output,r=`\u2191${c(e.input)} \u2193${c(e.output)} \u03A3${c(o)}`,n=[t.showCacheRead?`\u21AF${c(e.cacheRead)}`:void 0,t.showCacheWrites?`\u21A5${c(e.cacheWrite)}`:void 0].filter(Boolean),s=n.length?`${r} ${n.join(" ")}`:r;return t.cf(t.color,s)}function $(e,t,o){let r=e.input+e.output,n=`\u2191${c(e.input)} \u2193${c(e.output)} \u03A3${c(r)}`;return t(o,n)}function M(e,t,o){let r=e.input+e.output;return t(o,`\u03A3${c(r)}`)}function D(e,t,o){let r=(d,u)=>t.fg(d,u),n=ne(e,r),s=r(e.config.colors.separator,e.config.separator);return[ue(n,s,e.config.layouts,o)]}function ne(e,t){let o=e.config,r=o.showCache&&o.showCacheRead,n=o.showCache&&o.showCacheWrites;return{model:re(e,t),directory:o.showDirectory?ie(e,t):void 0,git:o.showGit?se(e,t):void 0,context:o.showContext?ae(e,t):void 0,tokensFull:o.showTokens?I(e.totals,{showCacheRead:r,showCacheWrites:n,cf:t,color:o.colors.tokens}):void 0,tokensNoCache:o.showTokens?$(e.totals,t,o.colors.tokens):void 0,tokensTotal:o.showTokens?M(e.totals,t,o.colors.tokens):void 0,toks:o.showToks?de(e,t):void 0}}function re(e,t){let o=v(e.modelId,e.config.modelAliases),r=e.config.showEffort&&e.thinkingLevel?` \u2022 ${e.thinkingLevel}`:"";return t(e.config.colors.model,`${o}${r}`)}function ie(e,t){if(e.directory)return t(e.config.colors.directory,e.directory)}function se(e,t){if(!e.gitBranch)return;let o=t(e.config.colors.git,e.gitBranch);return e.gitDirtyCount<=0?o:`${o} ${t(e.config.colors.gitDirty,`\u25CF${e.gitDirtyCount}`)}`}function ae(e,t){let o=`ctx ${c(e.contextUsed)}/${e.contextMax?c(e.contextMax):"--"}`;if(!e.contextMax||e.contextMax<=0)return t("dim",o);let r=e.contextUsed/e.contextMax*100;return r>=e.config.contextDangerPercent?t(e.config.colors.contextDanger,o):r>=e.config.contextWarningPercent?t(e.config.colors.contextWarning,o):t(e.config.colors.contextNormal,o)}function de(e,t){if(!(e.lastTokPerSec===void 0||e.lastTokPerSec<=0))return t(e.config.colors.tokens,`${Math.round(e.lastTokPerSec)} tok/s`)}function ue(e,t,o,r){let n=ce(o,r),s=E(n.left,e),d=E(n.right,e);return L(s,d,t,r)}function ce(e,t){return e.find(o=>t>=o.minWidth)??e[e.length-1]}function E(e,t){return e.map(o=>t[o]).filter(o=>!!o)}function Be(e){let t=_.join(ge.homedir(),".pi","agent","clean-footer.json"),o=i=>_.join(i,".pi","clean-footer.json"),r=()=>{},n=new C({globalConfigPath:t,getProjectConfigPath:o,getThinkingLevel:()=>{var i;return(i=e.getThinkingLevel)==null?void 0:i.call(e)},onRenderNeeded:()=>r()});e.registerCommand("footer",{description:"Toggle, refresh, or configure the clean footer",handler:async(i,a)=>{let g=i.trim();if(g==="refresh"){await n.refresh(),a.hasUI&&a.ui.notify("Footer refreshed","info");return}if(g==="reload"){await n.reload(a),a.hasUI&&n.isEnabled&&s(a),a.hasUI&&!n.isEnabled&&a.ui.setFooter(void 0),r(),d(a);return}if(g==="config"){u(a);return}let l=await n.toggle();a.hasUI&&(l?(s(a),a.ui.notify("Clean footer enabled","info")):(a.ui.setFooter(void 0),a.ui.notify("Default footer restored","info")))}}),e.on("session_start",async(i,a)=>{await n.start(a),a.hasUI&&n.loadedError&&n.isEnabled&&a.ui.notify(`Config error: ${n.loadedError}`,"error"),a.hasUI&&n.isEnabled&&s(a)}),e.on("session_shutdown",(i,a)=>{n.shutdown(),r=()=>{},a.hasUI&&a.ui.setFooter(void 0)}),e.on("thinking_level_select",i=>{n.onThinkingLevel(i.level)}),e.on("model_select",()=>{n.onModelSelect()}),e.on("message_start",i=>{n.onMessageStart(i.message.role)}),e.on("message_end",i=>{var l;let a=i.message,g;if(a.role==="assistant"){let m=a,w=m.usage??((l=m.message)==null?void 0:l.usage);g=w==null?void 0:w.output}n.onMessageEnd(a.role,g)}),e.on("tool_execution_end",i=>{n.onToolEnd(i.toolName)}),e.on("user_bash",()=>{n.onUserBash()});function s(i){i.hasUI&&i.ui.setFooter((a,g)=>(r=()=>a.requestRender(),{invalidate(){},render(l){let m=n.getFooterInput(i);return D(m,g,l)}}))}function d(i){i.hasUI&&(n.loadedError?i.ui.notify(`Clean footer config error: ${n.loadedError}`,"error"):n.loadedWarnings.length>0?i.ui.notify(`Clean footer config loaded with warnings: ${n.loadedWarnings.join("; ")}`,"warning"):i.ui.notify("Clean footer config loaded","info"))}function u(i){if(!i.hasUI)return;let a=n.loadedPaths.length?n.loadedPaths.join(`
3
- `):"none",g=n.loadedWarnings.length?n.loadedWarnings.join(`
4
- `):"none",l=o(i.cwd);i.ui.notify(["Clean footer config",`global: ${t}`,`project: ${l}`,`loaded:
5
- ${a}`,n.loadedError?`error: ${n.loadedError}`:"error: none",`warnings:
6
- ${g}`,`preset: ${n.config.preset}`,`resolved: ${JSON.stringify(n.config)}`].join(`
7
- `),"info")}}export{Be as default};
1
+ import K from"path";import Fe from"os";import he from"path";import{existsSync as re,readFileSync as ie}from"fs";var H=["model","directory","git","context","tokensFull","tokensNoCache","tokensTotal","toks"],z=["default","minimal","compact","dense","focus","muted"],y=[{minWidth:100,left:["model","directory","git","toks"],right:["context","tokensFull"]},{minWidth:80,left:["model","directory","git","toks"],right:["context","tokensNoCache"]},{minWidth:60,left:["model","directory","git","toks"],right:["context","tokensTotal"]},{minWidth:40,left:["model","directory","git"],right:["context"]},{minWidth:0,left:["model"],right:["context"]}],J=[{minWidth:0,left:["model"],right:["context"]}],q=[{minWidth:80,left:["model","git"],right:["context","tokensTotal"]},{minWidth:0,left:["model"],right:["context"]}],V=[{minWidth:100,left:["model","directory","git","toks"],right:["context","tokensFull"]},{minWidth:60,left:["model","git"],right:["context","tokensNoCache"]},{minWidth:0,left:["model"],right:["context"]}],X=[{minWidth:0,left:["model"],right:["context"]}],Y={default:{},minimal:{separator:" \xB7 ",showDirectory:!1,showGit:!1,showTokens:!1,layouts:J},compact:{separator:" \xB7 ",showDirectory:!1,showCacheRead:!1,showCacheWrites:!1,layouts:q},dense:{showCacheRead:!0,showCacheWrites:!0,layouts:V},focus:{showDirectory:!1,showGit:!1,showTokens:!1,layouts:X},muted:{colors:{model:"muted",directory:"dim",git:"muted",gitDirty:"warning",contextNormal:"muted",contextWarning:"warning",contextDanger:"error",tokens:"dim",separator:"dim"}}},m={preset:"default",enabled:!0,showGit:!0,showTokens:!0,showCacheRead:!0,showCacheWrites:!1,showContext:!0,showDirectory:!0,showEffort:!0,separator:" | ",layouts:y,gitRefreshDebounceMs:500,contextWarningPercent:70,contextDangerPercent:85,modelAliases:{},colors:{model:"accent",directory:"dim",git:"success",gitDirty:"warning",contextNormal:"success",contextWarning:"warning",contextDanger:"error",tokens:"muted",separator:"dim"}};function w(e,t){return{...e,...t,modelAliases:{...e.modelAliases??{},...t.modelAliases??{}},colors:{...e.colors??{},...t.colors??{}}}}function R(e){let t=[];"showCache"in e&&t.push("showCache is deprecated; use showCacheRead and showCacheWrites instead"),"showCache"in e&&!("showCacheRead"in e)&&(e={...e,showCacheRead:e.showCache});let n=Q(e.preset,t),o=Y[n],r=w(o,e),s=Z(r.layouts);return{config:{...m,...r,preset:n,separator:typeof r.separator=="string"?r.separator:m.separator,layouts:s.layouts,gitRefreshDebounceMs:ne(r.gitRefreshDebounceMs,m.gitRefreshDebounceMs),contextWarningPercent:S(r.contextWarningPercent,m.contextWarningPercent),contextDangerPercent:S(r.contextDangerPercent,m.contextDangerPercent),modelAliases:{...m.modelAliases,...o.modelAliases??{},...e.modelAliases??{}},colors:{...m.colors,...o.colors??{},...e.colors??{}}},loadedPaths:[],warnings:[...t,...s.warnings]}}function Q(e,t){return e===void 0||e==="default"?"default":typeof e!="string"?(t.push("preset must be a string; using default preset"),"default"):z.includes(e)?e:(t.push(`unknown preset '${e}'; using default preset`),"default")}function Z(e){let t=[];if(e===void 0)return{layouts:y,warnings:t};if(!Array.isArray(e))return{layouts:y,warnings:["layouts must be an array; using default layouts"]};let n=e.flatMap((o,r)=>{if(!te(o))return t.push(`layouts[${r}] must be an object; skipping`),[];let s=oe(o.minWidth);if(s===void 0)return t.push(`layouts[${r}].minWidth must be a non-negative number; skipping`),[];let d=v(o.left,`layouts[${r}].left`,t),u=v(o.right,`layouts[${r}].right`,t,new Set(d));return d.length===0&&u.length===0?(t.push(`layouts[${r}] has no visible segments; skipping`),[]):[{minWidth:s,left:d,right:u}]});return n.length===0?(t.push("no valid layouts configured; using default layouts"),{layouts:y,warnings:t}):{layouts:[...n].sort((o,r)=>r.minWidth-o.minWidth),warnings:t}}function v(e,t,n,o=new Set){if(!Array.isArray(e))return n.push(`${t} must be an array; using empty segment list`),[];let r=[];for(let s of e){if(!ee(s)){n.push(`${t} contains unknown segment '${String(s)}'; omitting`);continue}if(o.has(s)){n.push(`${t} contains duplicate segment '${s}'; omitting`);continue}o.add(s),r.push(s)}return r}function ee(e){return typeof e=="string"&&H.includes(e)}function te(e){return typeof e=="object"&&e!==null}function oe(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function ne(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:t}function S(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=100?e:t}function k(e,t){return se([e,t])}function se(e){let t=[],n={},o;for(let s of e)if(re(s))try{let d=JSON.parse(ie(s,"utf8"));n=w(n,d),t.push(s)}catch(d){o=`${s}: ${d instanceof Error?d.message:String(d)}`}let r=R(n);return{config:r.config,loadedPaths:t,warnings:r.warnings,error:o}}import{execFile as ae}from"child_process";import{promisify as de}from"util";var _=de(ae);function E(e){let t={inRepo:!1,dirtyCount:0},n,o=[];e.onChange&&o.push(e.onChange);async function r(){if(!e.enabled){t={inRepo:!1,dirtyCount:0};return}try{let[u,i]=await Promise.all([_("git",["branch","--show-current"],{cwd:e.cwd,timeout:2e3}),_("git",["status","--porcelain"],{cwd:e.cwd,timeout:2e3})]),a=u.stdout.trim()||"detached",l=i.stdout.split(`
2
+ `).filter(Boolean).length;t={inRepo:!0,branch:a,dirtyCount:l}}catch{t={inRepo:!1,dirtyCount:0}}for(let u of o)u()}function s(){d(),n=setTimeout(()=>{n=void 0,r()},e.debounceMs)}function d(){n&&(clearTimeout(n),n=void 0)}return{get state(){return t},schedule:s,clear:d,refresh:r,onChange(u){return o.push(u),()=>{let i=o.indexOf(u);i>=0&&o.splice(i,1)}}}}function I(e){var n,o,r,s,d;let t={input:0,output:0,cacheRead:0,cacheWrite:0};for(let u of e){if(u.type!=="message"||((n=u.message)==null?void 0:n.role)!=="assistant")continue;let i=u.message;t.input+=((o=i.usage)==null?void 0:o.input)??0,t.output+=((r=i.usage)==null?void 0:r.output)??0,t.cacheRead+=((s=i.usage)==null?void 0:s.cacheRead)??0,t.cacheWrite+=((d=i.usage)==null?void 0:d.cacheWrite)??0}return t}function C(e){if(typeof e!="string")return;let t=e.toLowerCase();if(t==="medium")return"med";if(t==="extra-high"||t==="extra_high"||t==="x-high")return"xhigh";if(["low","med","high","xhigh"].includes(t))return t}function g(e){return!Number.isFinite(e)||e<=0?"0":e<1e3?`${Math.round(e)}`:e<1e6?`${(e/1e3).toFixed(e<1e4?1:0)}k`:`${(e/1e6).toFixed(1)}m`}function M(e){let t=0;for(let n of e){let o=n.codePointAt(0)??0;o>=32&&o<=126?t+=.25:o>=19968&&o<=40959||o>=13312&&o<=19903||o>=63744&&o<=64255||o>=12352&&o<=12447||o>=12448&&o<=12543||o>=44032&&o<=55215||o>=11904&&o<=12255||o>=12544&&o<=12591||o>=12784&&o<=12799||o>=65281&&o<=65374||o>=65381&&o<=65439?t+=.67:o>=12288&&o<=12351?t+=.5:o>65535?t+=1:t+=.5}return Math.ceil(t)}var ue={edit:"edit",write:"write",bash:"bash",ctx_shell:"bash",read:"read",ctx_read:"read",Agent:"agent",agent_browser:"browser"},le=[["gitnexus_","nexus"],["context7_","docs"]],P=8;function L(e){if(!e)return"";let t=ue[e];if(t)return t;for(let[n,o]of le)if(e.startsWith(n))return o;return e.length>P?e.slice(0,P):e}var ce=300,fe=5e3,ge=[". ",".. ","..."];function W(e){let t,n=0,o="",r=0,s,d;function u(){i(),s=setInterval(()=>{r=(r+1)%ge.length,e.onRenderNeeded()},ce)}function i(){s&&(clearInterval(s),s=void 0)}function a(){l(),d=setTimeout(()=>{d=void 0,t&&(t=void 0,e.onRenderNeeded())},fe)}function l(){d&&(clearTimeout(d),d=void 0)}function h(c,f,b){return{state:"rate",value:(f&&f>0?f:c)/b,approximate:!(f&&f>0)}}return{onMessageStart(){l(),t={startTime:Date.now(),estimatedTokens:0,hasObservedOutput:!1,displayState:{state:"pending"}},e.onRenderNeeded()},onMessageUpdate(c,f,b){if(!t||!f||c!=="text_delta"&&c!=="thinking_delta"&&c!=="toolcall_delta")return;t.estimatedTokens+=M(f),t.hasObservedOutput=!0;let T=(Date.now()-t.startTime)/1e3;T>0&&(t.displayState=h(t.estimatedTokens,b,T)),e.onRenderNeeded()},onMessageEnd(c){if(n=0,i(),t){let f=(Date.now()-t.startTime)/1e3;c&&c>0&&f>0?(t.displayState={state:"rate",value:c/f,approximate:!1},a()):t.hasObservedOutput&&f>0?(t.displayState={state:"rate",value:t.estimatedTokens/f,approximate:!0},a()):t=void 0}e.onRenderNeeded()},onMessageAbort(){if(t)if(t.hasObservedOutput){let c=(Date.now()-t.startTime)/1e3;c>0&&(t.displayState={state:"rate",value:t.estimatedTokens/c,approximate:!0})}else t=void 0;e.onRenderNeeded()},onToolStart(c){n++,o=L(c)+"...",r=0,u(),e.onRenderNeeded()},onToolEnd(){n=Math.max(0,n-1),n===0&&i(),e.onRenderNeeded()},getState(){return n>0?{state:"activity",label:o}:(t==null?void 0:t.displayState)??{state:"hidden"}},shutdown(){t=void 0,n=0,o="",r=0,i(),l()}}}var x=class{#t;#r;#s;#e;#n;#o;#a;#l;#c;#f;#i;#d={input:0,output:0,cacheRead:0,cacheWrite:0};#u=0;constructor(t){this.#l=t.globalConfigPath,this.#c=t.getProjectConfigPath,this.#f=t.getThinkingLevel,this.#i=t.onRenderNeeded,this.#t=m,this.#r={config:this.#t,loadedPaths:[],warnings:[]},this.#s=void 0,this.#e=void 0,this.#o=!0,this.#a="",this.#n=W({onRenderNeeded:()=>this.#i()})}async start(t){this.#d={input:0,output:0,cacheRead:0,cacheWrite:0},this.#u=0,this.#a=t.cwd,this.#r=k(this.#l,this.#c(t.cwd)),this.#t=this.#r.config,this.#s=C(this.#f()),this.#o=this.#t.enabled,this.#o&&(this.#g(t.cwd),await this.#e.refresh())}shutdown(){var t;(t=this.#e)==null||t.clear(),this.#e=void 0,this.#h()}#g(t){this.#e=E({cwd:t,debounceMs:this.#t.gitRefreshDebounceMs,enabled:this.#t.showGit,onChange:()=>this.#i()})}onThinkingLevel(t){this.#s=C(t),this.#i()}onModelSelect(){this.#i()}onMessageStart(t){t==="assistant"&&this.#n.onMessageStart()}onToolExecutionStart(t){this.#n.onToolStart(t)}onToolExecutionUpdate(t){}onToolExecutionEnd(t){var n;this.#n.onToolEnd(),["bash","edit","write"].includes(t)&&((n=this.#e)==null||n.schedule())}onMessageUpdate(t,n,o){this.#n.onMessageUpdate(t,n,o)}onMessageEnd(t,n){t==="assistant"&&this.#n.onMessageEnd(n)}onMessageAbort(){this.#n.onMessageAbort()}onUserBash(){var t;(t=this.#e)==null||t.schedule()}async refresh(){var t;await((t=this.#e)==null?void 0:t.refresh())}async reload(t){var n;this.#h(),this.#r=k(this.#l,this.#c(t.cwd)),this.#t=this.#r.config,this.#o=this.#t.enabled,(n=this.#e)==null||n.clear(),this.#e=void 0,this.#o&&(this.#g(this.#a),await this.#e.refresh()),this.#i()}async toggle(){var t;return this.#h(),this.#o=!this.#o,this.#o?(this.#s=C(this.#f()),this.#g(this.#a),await this.#e.refresh()):((t=this.#e)==null||t.clear(),this.#e=void 0),this.#i(),this.#o}getFooterInput(t){var o,r,s,d,u,i;let n=t.sessionManager.getBranch();return n.length!==this.#u&&(this.#d=I(n),this.#u=n.length),{modelId:((o=t.model)==null?void 0:o.id)??"no-model",thinkingLevel:this.#s,directory:he.basename(t.cwd),gitBranch:(r=this.#e)==null?void 0:r.state.branch,gitDirtyCount:((s=this.#e)==null?void 0:s.state.dirtyCount)??0,contextUsed:((u=(d=t.getContextUsage)==null?void 0:d.call(t))==null?void 0:u.tokens)??0,contextMax:(i=t.model)==null?void 0:i.contextWindow,totals:this.#d,toksState:this.#n.getState(),config:this.#t}}#h(){this.#d={input:0,output:0,cacheRead:0,cacheWrite:0},this.#u=0,this.#n.shutdown()}get isEnabled(){return this.#o}get loadedError(){return this.#r.error}get loadedWarnings(){return this.#r.warnings}get loadedPaths(){return this.#r.loadedPaths}get config(){return this.#t}};import{truncateToWidth as p,visibleWidth as A}from"@earendil-works/pi-tui";function D(e,t,n,o){let r=e.filter(Boolean).join(n),s=t.filter(Boolean).join(n);return me(r,s,o)}function me(e,t,n){if(!t)return p(e,n);if(!e)return p(t,n);let o=n-A(e)-A(t);if(o>=1)return p(e+" ".repeat(o)+t,n);let r=Math.max(1,Math.floor((n-1)/2));return p(e,r)+" "+p(t,n-r-1)}function N(e,t){if(t[e])return t[e];let n=e.toLowerCase(),o=n.includes("/")?n.split("/").pop():n;if(t[o])return t[o];if(o.includes("claude")&&o.includes("sonnet"))return o.includes("4-5")||o.includes("4.5")?"sonnet-4.5":o.includes("4")?"sonnet-4":"sonnet";if(o.includes("claude")&&o.includes("opus"))return"opus";if(o.includes("claude")&&o.includes("haiku"))return"haiku";let r=o.match(/gpt-5(?:[.-][a-z0-9]+)*/);if(r)return r[0];let s=o.match(/gpt-4(?:[.-][a-z0-9]+)*/);if(s)return s[0];let d=o.match(/gemini-[a-z0-9.-]+/);return d?d[0].replace(/-preview.*/,""):o.length>24?`${o.slice(0,21)}\u2026`:o}function $(e,t){let n=e.input+e.output,o=`\u2191${g(e.input)} \u2193${g(e.output)} \u03A3${g(n)}`,r=[t.showCacheRead?`\u21AF${g(e.cacheRead)}`:void 0,t.showCacheWrites?`\u21A5${g(e.cacheWrite)}`:void 0].filter(Boolean),s=r.length?`${o} ${r.join(" ")}`:o;return t.cf(t.color,s)}function O(e,t,n){let o=e.input+e.output,r=`\u2191${g(e.input)} \u2193${g(e.output)} \u03A3${g(o)}`;return t(n,r)}function U(e,t,n){let o=e.input+e.output;return t(n,`\u03A3${g(o)}`)}function G(e,t,n){let o=(d,u)=>t.fg(d,u),r=pe(e,o),s=o(e.config.colors.separator,e.config.separator);return[we(r,s,e.config.layouts,n)]}function pe(e,t){let n=e.config,o=n.showCacheRead,r=n.showCacheWrites;return{model:ye(e,t),directory:n.showDirectory?Ce(e,t):void 0,git:n.showGit?xe(e,t):void 0,context:n.showContext?be(e,t):void 0,tokensFull:n.showTokens?$(e.totals,{showCacheRead:o,showCacheWrites:r,cf:t,color:n.colors.tokens}):void 0,tokensNoCache:n.showTokens?O(e.totals,t,n.colors.tokens):void 0,tokensTotal:n.showTokens?U(e.totals,t,n.colors.tokens):void 0,toks:Te(e,t)}}function ye(e,t){let n=N(e.modelId,e.config.modelAliases),o=e.config.showEffort&&e.thinkingLevel?` \u2022 ${e.thinkingLevel}`:"";return t(e.config.colors.model,`${n}${o}`)}function Ce(e,t){if(e.directory)return t(e.config.colors.directory,e.directory)}function xe(e,t){if(!e.gitBranch)return;let n=t(e.config.colors.git,e.gitBranch);return e.gitDirtyCount<=0?n:`${n} ${t(e.config.colors.gitDirty,`\u25CF${e.gitDirtyCount}`)}`}function be(e,t){let n=`ctx ${g(e.contextUsed)}/${e.contextMax?g(e.contextMax):"--"}`;if(!e.contextMax||e.contextMax<=0)return t("dim",n);let o=e.contextUsed/e.contextMax*100;return o>=e.config.contextDangerPercent?t(e.config.colors.contextDanger,n):o>=e.config.contextWarningPercent?t(e.config.colors.contextWarning,n):t(e.config.colors.contextNormal,n)}function Te(e,t){let n=e.toksState;if(n.state==="hidden")return;if(n.state==="activity")return t(e.config.colors.tokens,n.label);if(n.state==="pending")return t(e.config.colors.tokens,"\u2026 tok/s");let o=Math.round(n.value);return n.approximate?t(e.config.colors.tokens,`\u2248${o} tok/s`):t(e.config.colors.tokens,`${o} tok/s`)}function we(e,t,n,o){let r=ke(n,o),s=j(r.left,e),d=j(r.right,e);return D(s,d,t,o)}function ke(e,t){return e.find(n=>t>=n.minWidth)??e[e.length-1]}function j(e,t){return e.map(n=>t[n]).filter(n=>!!n)}function B(e){return e!==null&&typeof e=="object"&&"usage"in e&&e.usage!==null&&typeof e.usage=="object"}function F(e){if(e===null||typeof e!="object")return;let t=e,n=B(t)?t.usage.output:void 0;if(typeof n=="number"&&Number.isFinite(n)&&n>=0)return n;let o=t.message;if(o!==null&&typeof o=="object"&&B(o)){let r=o.usage.output;if(typeof r=="number"&&Number.isFinite(r)&&r>=0)return r}}function ut(e){let t=K.join(Fe.homedir(),".pi","agent","clean-footer.json"),n=i=>K.join(i,".pi","clean-footer.json"),o=()=>{},r=new x({globalConfigPath:t,getProjectConfigPath:n,getThinkingLevel:()=>{var i;return(i=e.getThinkingLevel)==null?void 0:i.call(e)},onRenderNeeded:()=>o()});e.registerCommand("footer",{description:"Toggle, refresh, or configure the clean footer",handler:async(i,a)=>{let l=i.trim();if(l==="refresh"){await r.refresh(),a.hasUI&&a.ui.notify("Footer refreshed","info");return}if(l==="reload"){await r.reload(a),a.hasUI&&r.isEnabled&&s(a),a.hasUI&&!r.isEnabled&&a.ui.setFooter(void 0),o(),d(a);return}if(l==="config"){u(a);return}let h=await r.toggle();a.hasUI&&(h?(s(a),a.ui.notify("Clean footer enabled","info")):(a.ui.setFooter(void 0),a.ui.notify("Default footer restored","info")))}}),e.on("session_start",async(i,a)=>{await r.start(a),a.hasUI&&r.loadedError&&r.isEnabled&&a.ui.notify(`Config error: ${r.loadedError}`,"error"),a.hasUI&&r.isEnabled&&s(a)}),e.on("session_shutdown",(i,a)=>{r.shutdown(),o=()=>{},a.hasUI&&a.ui.setFooter(void 0)}),e.on("thinking_level_select",i=>{r.onThinkingLevel(i.level)}),e.on("model_select",()=>{r.onModelSelect()}),e.on("message_start",i=>{r.onMessageStart(i.message.role)}),e.on("message_end",i=>{let a=i.message,l=a.role==="assistant"?F(a):void 0;r.onMessageEnd(a.role,l)}),e.on("message_update",i=>{let a=i.assistantMessageEvent;if(i.message.role==="assistant"){let l="delta"in a?a.delta:void 0,h=F(i.message);r.onMessageUpdate(a.type,l,h)}}),e.on("tool_execution_start",i=>{r.onToolExecutionStart(i.toolName)}),e.on("tool_execution_update",i=>{r.onToolExecutionUpdate(i.toolName)}),e.on("tool_execution_end",i=>{r.onToolExecutionEnd(i.toolName)}),e.on("user_bash",()=>{r.onUserBash()});function s(i){i.hasUI&&i.ui.setFooter((a,l)=>(o=()=>a.requestRender(),{invalidate(){},render(h){let c=r.getFooterInput(i);return G(c,l,h)}}))}function d(i){i.hasUI&&(r.loadedError?i.ui.notify(`Clean footer config error: ${r.loadedError}`,"error"):r.loadedWarnings.length>0?i.ui.notify(`Clean footer config loaded with warnings: ${r.loadedWarnings.join("; ")}`,"warning"):i.ui.notify("Clean footer config loaded","info"))}function u(i){if(!i.hasUI)return;let a=r.loadedPaths.length?r.loadedPaths.join(`
3
+ `):"none",l=r.loadedWarnings.length?r.loadedWarnings.join(`
4
+ `):"none",h=n(i.cwd);i.ui.notify(["Clean footer config",`global: ${t}`,`project: ${h}`,`loaded:
5
+ ${a}`,r.loadedError?`error: ${r.loadedError}`:"error: none",`warnings:
6
+ ${l}`,`preset: ${r.config.preset}`,`resolved: ${JSON.stringify(r.config)}`].join(`
7
+ `),"info")}}export{ut as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neilurk12/pi-clean-footer",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Clean, minimal, and lightweight powerline-style footer extension for pi coding agent.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -42,6 +42,9 @@
42
42
  "@earendil-works/pi-coding-agent": "*",
43
43
  "@earendil-works/pi-tui": "*"
44
44
  },
45
+ "engines": {
46
+ "node": ">=18"
47
+ },
45
48
  "devDependencies": {
46
49
  "prettier": "^3.8.3",
47
50
  "tsup": "^8.5.1",