@neilurk12/pi-clean-footer 0.2.5 → 0.2.7

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
@@ -79,14 +79,35 @@ Example:
79
79
 
80
80
  ```json
81
81
  {
82
+ "preset": "compact",
82
83
  "enabled": true,
83
84
  "showGit": true,
84
85
  "showTokens": true,
85
- "showCache": false,
86
+ "showCache": true,
87
+ "showCacheRead": true,
88
+ "showCacheWrites": true,
86
89
  "showContext": true,
87
90
  "showDirectory": true,
88
91
  "showEffort": true,
89
92
  "gitRefreshDebounceMs": 500,
93
+ "separator": " • ",
94
+ "layouts": [
95
+ {
96
+ "minWidth": 100,
97
+ "left": ["model", "directory", "git"],
98
+ "right": ["context", "tokensFull"]
99
+ },
100
+ {
101
+ "minWidth": 60,
102
+ "left": ["model", "git"],
103
+ "right": ["context", "tokensTotal"]
104
+ },
105
+ {
106
+ "minWidth": 0,
107
+ "left": ["model"],
108
+ "right": ["context"]
109
+ }
110
+ ],
90
111
  "contextWarningPercent": 70,
91
112
  "contextDangerPercent": 85,
92
113
  "modelAliases": {
@@ -107,6 +128,40 @@ Example:
107
128
  }
108
129
  ```
109
130
 
131
+ Preset example:
132
+
133
+ ```json
134
+ {
135
+ "preset": "minimal",
136
+ "showGit": true
137
+ }
138
+ ```
139
+
140
+ Supported presets:
141
+
142
+ | Preset | Description |
143
+ |---|---|
144
+ | `default` | Built-in footer behavior. |
145
+ | `minimal` | Quiet model + context layout with git, directory, and tokens hidden. |
146
+ | `compact` | Model, git, context, and total tokens with cache noise hidden. |
147
+ | `dense` | Full information layout with cache read and write counts enabled. |
148
+ | `focus` | Model + context only for low-distraction sessions. |
149
+ | `muted` | Softer semantic colors while keeping default-style behavior. |
150
+
151
+ Preset values are applied before user config, so explicit settings override the preset. Unknown preset names are ignored with a `/footer config` warning and default behavior is used.
152
+
153
+ Supported layout segment IDs:
154
+
155
+ - `model` - model name plus thinking effort when `showEffort` is enabled
156
+ - `directory` - current directory basename
157
+ - `git` - git branch and dirty count
158
+ - `context` - context usage
159
+ - `tokensFull` - input, output, total, cache read, and cache write tokens
160
+ - `tokensNoCache` - input, output, and total tokens
161
+ - `tokensTotal` - total tokens only
162
+
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
+
110
165
  Malformed JSON keeps defaults/last loaded behavior and reports an error through `/footer config` or at startup.
111
166
 
112
167
  ## Package manifest
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import T from"path";import H from"os";import N from"path";import{existsSync as M,readFileSync as $}from"fs";var D=500,f={enabled:!0,showGit:!0,showTokens:!0,showCache:!0,showContext:!0,showDirectory:!0,showEffort:!0,gitRefreshDebounceMs:D,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 p(e,t){return S([e,t])}function S(e){let t=[],o={},n;for(let r of e)if(M(r))try{let s=JSON.parse($(r,"utf8"));o=I(o,s),t.push(r)}catch(s){n=`${r}: ${s instanceof Error?s.message:String(s)}`}return{config:_(o),loadedPaths:t,error:n}}function I(e,t){return{...e,...t,modelAliases:{...e.modelAliases??{},...t.modelAliases??{}},colors:{...e.colors??{},...t.colors??{}}}}function _(e){return{...f,...e,gitRefreshDebounceMs:L(e.gitRefreshDebounceMs,f.gitRefreshDebounceMs),contextWarningPercent:x(e.contextWarningPercent,f.contextWarningPercent),contextDangerPercent:x(e.contextDangerPercent,f.contextDangerPercent),modelAliases:{...f.modelAliases,...e.modelAliases??{}},colors:{...f.colors,...e.colors??{}}}}function L(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:t}function x(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=100?e:t}import{execFile as j}from"child_process";import{promisify as A}from"util";var w=A(j);function F(e){let t={inRepo:!1,dirtyCount:0},o,n=[];e.onChange&&n.push(e.onChange);async function r(){if(!e.enabled){t={inRepo:!1,dirtyCount:0};return}try{let[l,i]=await Promise.all([w("git",["branch","--show-current"],{cwd:e.cwd,timeout:2e3}),w("git",["status","--porcelain"],{cwd:e.cwd,timeout:2e3})]),a=l.stdout.trim()||"detached",d=i.stdout.split(`
2
- `).filter(Boolean).length;t={inRepo:!0,branch:a,dirtyCount:d}}catch{t={inRepo:!1,dirtyCount:0}}for(let l of n)l()}function s(){c(),o=setTimeout(()=>{o=void 0,r()},e.debounceMs)}function c(){o&&(clearTimeout(o),o=void 0)}return{get state(){return t},schedule:s,clear:c,refresh:r,onChange(l){return n.push(l),()=>{let i=n.indexOf(l);i>=0&&n.splice(i,1)}}}}function P(e){var o,n,r,s,c;let t={input:0,output:0,cacheRead:0,cacheWrite:0};for(let l of e){if(l.type!=="message"||((o=l.message)==null?void 0:o.role)!=="assistant")continue;let i=l.message;t.input+=((n=i.usage)==null?void 0:n.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+=((c=i.usage)==null?void 0:c.cacheWrite)??0}return t}function m(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}var C=class{#t;#r;#i;#e;#o;#s;#a;#l;#c;#n;constructor(t){this.#a=t.globalConfigPath,this.#l=t.getProjectConfigPath,this.#c=t.getThinkingLevel,this.#n=t.onRenderNeeded,this.#t=f,this.#r={config:this.#t,loadedPaths:[]},this.#i=void 0,this.#e=void 0,this.#o=!0,this.#s=""}async start(t){this.#s=t.cwd,this.#r=p(this.#a,this.#l(t.cwd)),this.#t=this.#r.config,this.#i=m(this.#c()),this.#o=this.#t.enabled,this.#o&&(this.#d(t.cwd),await this.#e.refresh())}shutdown(){var t;(t=this.#e)==null||t.clear(),this.#e=void 0}#d(t){this.#e=F({cwd:t,debounceMs:this.#t.gitRefreshDebounceMs,enabled:this.#t.showGit,onChange:()=>this.#n()})}onThinkingLevel(t){this.#i=m(t),this.#n()}onModelSelect(){this.#n()}onMessageEnd(t){t==="assistant"&&this.#n()}onToolEnd(t){var o;["bash","edit","write"].includes(t)&&((o=this.#e)==null||o.schedule()),this.#n()}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.#r=p(this.#a,this.#l(t.cwd)),this.#t=this.#r.config,this.#o=this.#t.enabled,(o=this.#e)==null||o.clear(),this.#e=void 0,this.#o&&(this.#d(this.#s),await this.#e.refresh()),this.#n()}async toggle(){var t;return this.#o=!this.#o,this.#o?(this.#i=m(this.#c()),this.#d(this.#s),await this.#e.refresh()):((t=this.#e)==null||t.clear(),this.#e=void 0),this.#n(),this.#o}getFooterInput(t){var o,n,r,s,c,l;return{modelId:((o=t.model)==null?void 0:o.id)??"no-model",thinkingLevel:this.#i,directory:N.basename(t.cwd),gitBranch:(n=this.#e)==null?void 0:n.state.branch,gitDirtyCount:((r=this.#e)==null?void 0:r.state.dirtyCount)??0,contextUsed:((c=(s=t.getContextUsage)==null?void 0:s.call(t))==null?void 0:c.tokens)??0,contextMax:(l=t.model)==null?void 0:l.contextWindow,totals:P(t.sessionManager.getBranch()),config:this.#t}}get isEnabled(){return this.#o}get loadedError(){return this.#r.error}get loadedPaths(){return this.#r.loadedPaths}get config(){return this.#t}};import{truncateToWidth as u,visibleWidth as k}from"@earendil-works/pi-tui";function R(e,t){if(t[e])return t[e];let o=e.toLowerCase(),n=o.includes("/")?o.split("/").pop():o;if(t[n])return t[n];if(n.includes("claude")&&n.includes("sonnet"))return n.includes("4-5")||n.includes("4.5")?"sonnet-4.5":n.includes("4")?"sonnet-4":"sonnet";if(n.includes("claude")&&n.includes("opus"))return"opus";if(n.includes("claude")&&n.includes("haiku"))return"haiku";let r=n.match(/gpt-5(?:[.-][a-z0-9]+)*/);if(r)return r[0];let s=n.match(/gpt-4(?:[.-][a-z0-9]+)*/);if(s)return s[0];let c=n.match(/gemini-[a-z0-9.-]+/);return c?c[0].replace(/-preview.*/,""):n.length>24?`${n.slice(0,21)}\u2026`:n}function v(e,t,o){let n=(c,l)=>t.fg(c,l),r=U(e,n),s=n(e.config.colors.separator," | ");return z(r,s,o)}function U(e,t){let o=e.config,n=W(e,t),r=o.showDirectory?G(e,t):void 0,s=o.showGit?B(e,t):void 0,c=o.showContext?O(e,t):void 0,l={};return o.showTokens&&(l.full=b(e.totals,"full",o.showCache,t,o.colors.tokens),l.noCache=b(e.totals,"no-cache",o.showCache,t,o.colors.tokens),l.totalOnly=b(e.totals,"total-only",o.showCache,t,o.colors.tokens)),{model:n,dir:r,git:s,context:c,tokens:l}}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 W(e,t){let o=R(e.modelId,e.config.modelAliases),n=e.config.showEffort&&e.thinkingLevel?` \u2022 ${e.thinkingLevel}`:"";return t(e.config.colors.model,`${o}${n}`)}function G(e,t){if(e.directory)return t(e.config.colors.directory,e.directory)}function B(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 b(e,t,o,n,r){let s=o?t:t==="full"?"no-cache":t,c=e.input+e.output,l;if(s==="total-only")l=`\u03A3${g(c)}`;else{let i=`\u2191${g(e.input)} \u2193${g(e.output)} \u03A3${g(c)}`;l=s==="full"?`${i} \u21AF${g(e.cacheRead)} \u21A5${g(e.cacheWrite)}`:i}return n(r,l)}function O(e,t){let o=`ctx ${g(e.contextUsed)}/${e.contextMax?g(e.contextMax):"--"}`;if(!e.contextMax||e.contextMax<=0)return t("dim",o);let n=e.contextUsed/e.contextMax*100;return n>=e.config.contextDangerPercent?t(e.config.colors.contextDanger,o):n>=e.config.contextWarningPercent?t(e.config.colors.contextWarning,o):t(e.config.colors.contextNormal,o)}function z(e,t,o){let n=[e.model,e.dir,e.git].filter(Boolean).join(t),r=e.model;if(o>=100){let s=[e.context,e.tokens.full].filter(Boolean).join(t);return[h(n,s,o)]}if(o>=80){let s=[e.context,e.tokens.noCache].filter(Boolean).join(t);return[h(n,s,o)]}if(o>=60){let s=[e.context,e.tokens.totalOnly].filter(Boolean).join(t);return[h(n,s,o)]}return o>=40?[h(n,e.context??"",o)]:[h(r,e.context??"",o)]}function h(e,t,o){if(!t)return u(e,o);if(!e)return u(t,o);let n=o-k(e)-k(t);if(n>=1)return u(e+" ".repeat(n)+t,o);let r=Math.max(1,Math.floor((o-1)/2));return u(e,r)+" "+u(t,o-r-1)}function ue(e){let t=T.join(H.homedir(),".pi","agent","clean-footer.json"),o=i=>T.join(i,".pi","clean-footer.json"),n=()=>{},r=new C({globalConfigPath:t,getProjectConfigPath:o,getThinkingLevel:()=>{var i;return(i=e.getThinkingLevel)==null?void 0:i.call(e)},onRenderNeeded:()=>n()});e.registerCommand("footer",{description:"Toggle, refresh, or configure the clean footer",handler:async(i,a)=>{let d=i.trim();if(d==="refresh"){await r.refresh(),a.hasUI&&a.ui.notify("Footer refreshed","info");return}if(d==="reload"){await r.reload(a),a.hasUI&&r.isEnabled&&s(a),a.hasUI&&!r.isEnabled&&a.ui.setFooter(void 0),n(),c(a);return}if(d==="config"){l(a);return}let y=await r.toggle();a.hasUI&&(y?(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(),n=()=>{},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_end",i=>{r.onMessageEnd(i.message.role)}),e.on("tool_execution_end",i=>{r.onToolEnd(i.toolName)}),e.on("user_bash",()=>{r.onUserBash()});function s(i){i.hasUI&&i.ui.setFooter((a,d)=>(n=()=>a.requestRender(),{invalidate(){},render(y){let E=r.getFooterInput(i);return v(E,d,y)}}))}function c(i){i.hasUI&&(r.loadedError?i.ui.notify(`Clean footer config error: ${r.loadedError}`,"error"):i.ui.notify("Clean footer config loaded","info"))}function l(i){if(!i.hasUI)return;let a=r.loadedPaths.length?r.loadedPaths.join(`
3
- `):"none",d=o(i.cwd);i.ui.notify(["Clean footer config",`global: ${t}`,`project: ${d}`,`loaded:
4
- ${a}`,r.loadedError?`error: ${r.loadedError}`:"error: none",`resolved: ${JSON.stringify(r.config)}`].join(`
5
- `),"info")}}export{ue as default};
1
+ import T from"path";import de from"os";import Z from"path";import{existsSync as E,readFileSync as M}from"fs";var D=500,j=["model","directory","git","context","tokensFull","tokensNoCache","tokensTotal"],_=["default","minimal","compact","dense","focus","muted"],m=[{minWidth:100,left:["model","directory","git"],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"]}],N=[{minWidth:0,left:["model"],right:["context"]}],A=[{minWidth:80,left:["model","git"],right:["context","tokensTotal"]},{minWidth:0,left:["model"],right:["context"]}],U=[{minWidth:100,left:["model","directory","git"],right:["context","tokensFull"]},{minWidth:60,left:["model","git"],right:["context","tokensNoCache"]},{minWidth:0,left:["model"],right:["context"]}],G=[{minWidth:0,left:["model"],right:["context"]}],B={default:{},minimal:{separator:" \xB7 ",showDirectory:!1,showGit:!1,showTokens:!1,layouts:N},compact:{separator:" \xB7 ",showDirectory:!1,showCacheRead:!1,showCacheWrites:!1,layouts:A},dense:{showCacheRead:!0,showCacheWrites:!0,layouts:U},focus:{showDirectory:!1,showGit:!1,showTokens:!1,layouts:G},muted:{colors:{model:"muted",directory:"dim",git:"muted",gitDirty:"warning",contextNormal:"muted",contextWarning:"warning",contextDanger:"error",tokens:"dim",separator:"dim"}}},c={preset:"default",enabled:!0,showGit:!0,showTokens:!0,showCache:!0,showCacheRead:!0,showCacheWrites:!1,showContext:!0,showDirectory:!0,showEffort:!0,separator:" | ",layouts:m,gitRefreshDebounceMs:D,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 C(e,t){return O([e,t])}function O(e){let t=[],o={},r;for(let s of e)if(E(s))try{let d=JSON.parse(M(s,"utf8"));o=x(o,d),t.push(s)}catch(d){r=`${s}: ${d instanceof Error?d.message:String(d)}`}let n=H(o);return{config:n.config,loadedPaths:t,warnings:n.warnings,error:r}}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"):_.includes(e)?e:(t.push(`unknown preset '${e}'; using default preset`),"default")}function x(e,t){return{...e,...t,modelAliases:{...e.modelAliases??{},...t.modelAliases??{}},colors:{...e.colors??{},...t.colors??{}}}}function H(e){let t=[],o=z(e.preset,t),r=B[o],n=x(r,e),s=q(n.layouts);return{config:{...c,...n,preset:o,separator:typeof n.separator=="string"?n.separator:c.separator,layouts:s.layouts,gitRefreshDebounceMs:V(n.gitRefreshDebounceMs,c.gitRefreshDebounceMs),contextWarningPercent:F(n.contextWarningPercent,c.contextWarningPercent),contextDangerPercent:F(n.contextDangerPercent,c.contextDangerPercent),modelAliases:{...c.modelAliases,...r.modelAliases??{},...e.modelAliases??{}},colors:{...c.colors,...r.colors??{},...e.colors??{}}},loadedPaths:[],warnings:[...t,...s.warnings]}}function q(e){let t=[];if(e===void 0)return{layouts:m,warnings:t};if(!Array.isArray(e))return{layouts:m,warnings:["layouts must be an array; using default layouts"]};let o=e.flatMap((r,n)=>{if(!K(r))return t.push(`layouts[${n}] must be an object; skipping`),[];let s=Q(r.minWidth);if(s===void 0)return t.push(`layouts[${n}].minWidth must be a non-negative number; skipping`),[];let d=b(r.left,`layouts[${n}].left`,t),l=b(r.right,`layouts[${n}].right`,t,new Set(d));return d.length===0&&l.length===0?(t.push(`layouts[${n}] has no visible segments; skipping`),[]):[{minWidth:s,left:d,right:l}]});return o.length===0?(t.push("no valid layouts configured; using default layouts"),{layouts:m,warnings:t}):{layouts:[...o].sort((r,n)=>n.minWidth-r.minWidth),warnings:t}}function b(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(!J(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 J(e){return typeof e=="string"&&j.includes(e)}function K(e){return typeof e=="object"&&e!==null}function Q(e){return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function V(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>0?e:t}function F(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>=0&&e<=100?e:t}import{execFile as X}from"child_process";import{promisify as Y}from"util";var k=Y(X);function P(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[l,i]=await Promise.all([k("git",["branch","--show-current"],{cwd:e.cwd,timeout:2e3}),k("git",["status","--porcelain"],{cwd:e.cwd,timeout:2e3})]),a=l.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 l of r)l()}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(l){return r.push(l),()=>{let i=r.indexOf(l);i>=0&&r.splice(i,1)}}}}function R(e){var o,r,n,s,d;let t={input:0,output:0,cacheRead:0,cacheWrite:0};for(let l of e){if(l.type!=="message"||((o=l.message)==null?void 0:o.role)!=="assistant")continue;let i=l.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}var p=class{#t;#n;#i;#e;#o;#s;#a;#d;#l;#r;constructor(t){this.#a=t.globalConfigPath,this.#d=t.getProjectConfigPath,this.#l=t.getThinkingLevel,this.#r=t.onRenderNeeded,this.#t=c,this.#n={config:this.#t,loadedPaths:[],warnings:[]},this.#i=void 0,this.#e=void 0,this.#o=!0,this.#s=""}async start(t){this.#s=t.cwd,this.#n=C(this.#a,this.#d(t.cwd)),this.#t=this.#n.config,this.#i=y(this.#l()),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}#g(t){this.#e=P({cwd:t,debounceMs:this.#t.gitRefreshDebounceMs,enabled:this.#t.showGit,onChange:()=>this.#r()})}onThinkingLevel(t){this.#i=y(t),this.#r()}onModelSelect(){this.#r()}onMessageEnd(t){t==="assistant"&&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.#n=C(this.#a,this.#d(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.#g(this.#s),await this.#e.refresh()),this.#r()}async toggle(){var t;return this.#o=!this.#o,this.#o?(this.#i=y(this.#l()),this.#g(this.#s),await this.#e.refresh()):((t=this.#e)==null||t.clear(),this.#e=void 0),this.#r(),this.#o}getFooterInput(t){var o,r,n,s,d,l;return{modelId:((o=t.model)==null?void 0:o.id)??"no-model",thinkingLevel:this.#i,directory:Z.basename(t.cwd),gitBranch:(r=this.#e)==null?void 0:r.state.branch,gitDirtyCount:((n=this.#e)==null?void 0:n.state.dirtyCount)??0,contextUsed:((d=(s=t.getContextUsage)==null?void 0:s.call(t))==null?void 0:d.tokens)??0,contextMax:(l=t.model)==null?void 0:l.contextWindow,totals:R(t.sessionManager.getBranch()),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 L}from"@earendil-works/pi-tui";function S(e,t,o,r){let n=e.filter(Boolean).join(o),s=t.filter(Boolean).join(o);return ee(n,s,r)}function ee(e,t,o){if(!t)return h(e,o);if(!e)return h(t,o);let r=o-L(e)-L(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 W(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,o){let r=(d,l)=>t.fg(d,l),n=te(e,r),s=r(e.config.colors.separator,e.config.separator);return[se(n,s,e.config.layouts,o)]}function te(e,t){let o=e.config,r=o.showCache&&o.showCacheRead,n=o.showCache&&o.showCacheWrites;return{model:oe(e,t),directory:o.showDirectory?ne(e,t):void 0,git:o.showGit?re(e,t):void 0,context:o.showContext?ie(e,t):void 0,tokensFull:o.showTokens?w(e.totals,"full",r,n,t,o.colors.tokens):void 0,tokensNoCache:o.showTokens?w(e.totals,"no-cache",r,n,t,o.colors.tokens):void 0,tokensTotal:o.showTokens?w(e.totals,"total-only",r,n,t,o.colors.tokens):void 0}}function f(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 oe(e,t){let o=W(e.modelId,e.config.modelAliases),r=e.config.showEffort&&e.thinkingLevel?` \u2022 ${e.thinkingLevel}`:"";return t(e.config.colors.model,`${o}${r}`)}function ne(e,t){if(e.directory)return t(e.config.colors.directory,e.directory)}function re(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 w(e,t,o,r,n,s){let d=e.input+e.output,l;if(t==="total-only")l=`\u03A3${f(d)}`;else{let i=`\u2191${f(e.input)} \u2193${f(e.output)} \u03A3${f(d)}`;if(t==="full"){let a=[o?`\u21AF${f(e.cacheRead)}`:void 0,r?`\u21A5${f(e.cacheWrite)}`:void 0].filter(Boolean);l=a.length?`${i} ${a.join(" ")}`:i}else l=i}return n(s,l)}function ie(e,t){let o=`ctx ${f(e.contextUsed)}/${e.contextMax?f(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 se(e,t,o,r){let n=ae(o,r),s=v(n.left,e),d=v(n.right,e);return S(s,d,t,r)}function ae(e,t){return e.find(o=>t>=o.minWidth)??e[e.length-1]}function v(e,t){return e.map(o=>t[o]).filter(o=>!!o)}function $e(e){let t=T.join(de.homedir(),".pi","agent","clean-footer.json"),o=i=>T.join(i,".pi","clean-footer.json"),r=()=>{},n=new p({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"){l(a);return}let u=await n.toggle();a.hasUI&&(u?(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_end",i=>{n.onMessageEnd(i.message.role)}),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(u){let $=n.getFooterInput(i);return I($,g,u)}}))}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 l(i){if(!i.hasUI)return;let a=n.loadedPaths.length?n.loadedPaths.join(`
3
+ `):"none",g=n.loadedWarnings.length?n.loadedWarnings.join(`
4
+ `):"none",u=o(i.cwd);i.ui.notify(["Clean footer config",`global: ${t}`,`project: ${u}`,`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{$e as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neilurk12/pi-clean-footer",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "description": "Clean, minimal, and lightweight powerline-style footer extension for pi coding agent.",
5
5
  "type": "module",
6
6
  "keywords": [